/*
 * SecBus - This file is part of SecBus
 * Copyright (C) 2012 - Telecom ParisTech
 * 
 * This file must be used under the terms of the CeCILL.
 * This source file is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at    
 * http://www.cecill.info/licences/Licence_CeCILL_V1.1-US.txt
 *
 */

#include "my_interfaces.h"

#define OPERATOR_ATTACH(name, dir, from)		     \
  void name##_##dir::operator() (name##_##from &sig)	     \
  {							     \
    name##_ATTACH;					     \
  }

#define TPLOPERATOR_ATTACH(name, dir, from, ...)			\
  void name##_##dir<__VA_ARGS__>::operator ()				\
  (name##_##from<__VA_ARGS__> &sig)					\
  {									\
    name##_ATTACH(base_##name##_##dir##_t);				\
  }

#define MEMORY_CTRL_CMD_ATTACH			\
  start_address(sig.start_address);		\
  plen(sig.plen);				\
  id(sig.id);					\
  cmdval(sig.cmdval);				\
  cmd(sig.cmd);					\
  cmdack(sig.cmdack);				\
  direct_write(sig.direct_write);		\
  rspval(sig.rspval);

OPERATOR_ATTACH(MEMORY_CTRL_CMD, IN, SIGNALS);
OPERATOR_ATTACH(MEMORY_CTRL_CMD, OUT, SIGNALS);

void MEMORY_CTRL_CMD_IN::operator = (MEMORY_CTRL_CMD_SIGNALS &sig)
{
  cmdack = sig.cmdack;
  rspval = sig.rspval;
}

void MEMORY_CTRL_CMD_OUT::operator = (MEMORY_CTRL_CMD_SIGNALS &sig)
{
  start_address = sig.start_address.read();
  plen = sig.plen.read();
  id = sig.id.read();
  cmd = sig.cmd.read();
  cmdval = sig.cmdval.read();
  direct_write = sig.direct_write.read();
}


sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  MEMORY_CTRL_CMD_IN &sig)
{
  ss << sig.start_address
     << sig.plen
     << sig.id
     << sig.cmd
     << sig.cmdval
     << sig.direct_write;

  return ss;
}

sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  MEMORY_CTRL_CMD_OUT &sig)
{
  ss << sig.cmdack
     << sig.rspval;

  return ss;
}

void MEMORY_CTRL_CMD_SIGNALS::operator () (MEMORY_CTRL_CMD_IN &sig)
{
  start_address = sig.start_address.read();
  plen = sig.plen.read();
  id = sig.id.read();
  cmd = sig.cmd.read();
  cmdval = sig.cmdval.read();
  direct_write = sig.direct_write.read();
}

void MEMORY_CTRL_CMD_SIGNALS::operator () (MEMORY_CTRL_CMD_OUT &sig)
{
  cmdack = sig.cmdack;
  rspval = sig.rspval;
}

#define DATA_REGISTER_READ_ATTACH \
  be(sig.be);			  \
  address (sig.address);	  \
  for (int i=0;i<8;i++)		  \
    data[i] (sig.data[i]);
  
OPERATOR_ATTACH(DATA_REGISTER_READ, IN, SIGNALS);
OPERATOR_ATTACH(DATA_REGISTER_READ, OUT, SIGNALS);

#define DATA_REGISTER_WRITE_ATTACH		\
  address (sig.address);			\
  enable(sig.enable);				\
  flush(sig.flush);				\
  for (int i=0;i<8;i++)				\
    data[i] (sig.data[i]);			\
						\
  be (sig.be);

OPERATOR_ATTACH(DATA_REGISTER_WRITE, IN, SIGNALS);
OPERATOR_ATTACH(DATA_REGISTER_WRITE, OUT, SIGNALS);

void DATA_REGISTER_WRITE_OUT::operator () (DATA_REGISTER_WRITE_IN &sig)
{
  address = sig.address.read();
  for (size_t i=0;i<8;i++)
    data[i] = sig.data[i].read();
  
  enable = sig.enable.read();
  flush  = sig.flush.read();
  be     = sig.be.read();
}

void DATA_REGISTER_WRITE_IN::operator () (DATA_REGISTER_WRITE_OUT &sig)
{

}

sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  DATA_REGISTER_WRITE_IN &sig )
{
  ss << sig.address
     << sig.be
     << sig.enable
     << sig.flush;
  for (size_t i=0;i<8;i++)
    ss << sig.data[i];

  return ss;
}

sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  DATA_REGISTER_WRITE_OUT &sig )
{
  return ss;
}

#define SECURITY_CTX_CMD_ATTACH			\
  enable(sig.enable);				\
  cmd(sig.cmd);					\
  mt(sig.mt);					\
  address(sig.address);				\
  ack(sig.ack);

OPERATOR_ATTACH(SECURITY_CTX_CMD, IN, SIGNALS);
OPERATOR_ATTACH(SECURITY_CTX_CMD, OUT, SIGNALS);

void SECURITY_CTX_CMD_OUT::operator () (SECURITY_CTX_CMD_IN &sig)
{
  enable = sig.enable.read();
  cmd = sig.cmd.read();
  mt = sig.mt.read();
  address = sig.address.read();
}

void SECURITY_CTX_CMD_IN::operator () (SECURITY_CTX_CMD_OUT &sig)
{
  ack = sig.ack.read();
}

sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  SECURITY_CTX_CMD_IN &sig )
{
  ss << sig.enable
     << sig.cmd
     << sig.mt
     << sig.address;

  return ss;
}

sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  SECURITY_CTX_CMD_OUT &sig )
{
  ss << sig.ack;

  return ss;
}


#define MASTER_CTX_REG_READ_ATTACH		\
  enable(sig.enable);				\
  for (size_t i=0;i<PSPE_SIZE_IN_WORDS;i++)	\
    pspe[i](sig.pspe[i]);			\
						\
  for (size_t i=0;i<SP_SIZE_IN_WORDS;i++)	\
    sp[i](sig.sp[i]);

OPERATOR_ATTACH(MASTER_CTX_REG_READ, IN, SIGNALS);
OPERATOR_ATTACH(MASTER_CTX_REG_READ, OUT, SIGNALS);

#define CTX_REGISTER_READ_ATTACH		\
  page_address(sig.page_address);		\
  s_pspe_address(sig.s_pspe_address);		\
  s_page_address(sig.s_page_address);		\
  for (size_t i=0;i<PSPE_SIZE_IN_WORDS;i++)	\
    m_pspe[i](sig.m_pspe[i]);			\
						\
  for (size_t i=0;i<PSPE_SIZE_IN_WORDS;i++)	\
    s_pspe[i](sig.s_pspe[i]);			\
						\
  for (size_t i=0;i<SP_SIZE_IN_WORDS;i++)	\
    sp[i](sig.sp[i]);
  
OPERATOR_ATTACH(CTX_REGISTER_READ, IN, SIGNALS);
OPERATOR_ATTACH(CTX_REGISTER_READ, OUT, SIGNALS);

#define SECURITY_RQ_ATTACH			\
  address(sig.address);				\
  enable(sig.enable);				\
  cmd(sig.cmd);					\
  cmdval(sig.cmdval);				\
  be(sig.be);					\
  mb(sig.mb);					\
  cmdack(sig.cmdack);				\
  rspval(sig.rspval);
  
OPERATOR_ATTACH(SECURITY_RQ, IN, SIGNALS);
OPERATOR_ATTACH(SECURITY_RQ, OUT, SIGNALS);

sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  SECURITY_RQ_IN &sig )
{
  ss << sig.address
     << sig.cmd
     << sig.cmdval
     << sig.be
     << sig.mb;

  return ss;
}

sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  SECURITY_RQ_OUT &sig )
{
  ss << sig.cmdack
     << sig.cmdval;

  return ss;
}

#define ACK_ATTACH				\
  rack(sig.rack);				\
  wack(sig.wack);				

OPERATOR_ATTACH(ACK, IN, SIGNALS);
OPERATOR_ATTACH(ACK, OUT, SIGNALS);

#define IRQ_ATTACH				\
  irq(sig.irq);					\
  address(sig.address);				\
  type(sig.type);				\
  op(sig.op);					\
  ack(sig.ack);

OPERATOR_ATTACH(IRQ, IN, SIGNALS);
OPERATOR_ATTACH(IRQ, OUT, SIGNALS);

#define DATA_ATTACH(x)						\
  x::enable(sig.enable);					\
  for (uint32_t i=0;i<size_in_words;i++)			\
    x::data[i](sig.data[i]);

template<int size_in_words>
TPLOPERATOR_ATTACH(DATA, IN, SIGNALS, size_in_words);

template<int size_in_words>
TPLOPERATOR_ATTACH(DATA, OUT, SIGNALS, size_in_words);


template<int size_in_words>
void DATA_IN<size_in_words>::operator () (DATA_OUT<size_in_words> &sig)
{
}

template<int size_in_words>
void DATA_OUT<size_in_words>::operator () (DATA_IN<size_in_words> &sig)
{
  DATA_WIRES<sc_out, sc_in, size_in_words>::enable = sig.enable.read();
  for (uint32_t i=0;i<size_in_words;i++)
    DATA_WIRES<sc_out, sc_in, size_in_words>::data[i] = sig.data[i];    
}

template<int size_in_words>
sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  DATA_IN<size_in_words> &sig )
{
  ss << sig.enable;
  for (size_t i=0;i<size_in_words;i++)
    ss << sig.data[i];

  return ss;
}

template<int size_in_words>
sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  DATA_OUT<size_in_words> &sig )
{
  return ss;
}

#define CRYPTO_CMD_ATTACH			\
  mode(sig.mode);				\
  enable(sig.enable);				\
  cipher(sig.cipher);				\
  cmdval(sig.cmdval);				\
  id_src(sig.id_src);				\
  id_dest(sig.id_dest);				\
  reg_ready(sig.reg_ready);			\
  address(sig.address);				\
  direct_data(sig.direct_data);			\
  no_init(sig.no_init);				\
  size(sig.size);				\
						\
  for (size_t i=0;i<DES_KEY_SIZE_IN_WORDS;i++)	\
    key[i](sig.key[i]);				\
  						\
  for (size_t i=0;i<IV_SIZE_IN_WORDS;i++)	\
    iv[i](sig.iv[i]);				\
						\
  cmdack(sig.cmdack);				\
  rspval(sig.rspval);				

OPERATOR_ATTACH(CRYPTO_CMD, IN, SIGNALS);
OPERATOR_ATTACH(CRYPTO_CMD, OUT, SIGNALS);

void CRYPTO_CMD_IN::operator = (CRYPTO_CMD_SIGNALS &sig)
{
  cmdack = sig.cmdack;
  rspval = sig.rspval;
}

void CRYPTO_CMD_OUT::operator = (CRYPTO_CMD_SIGNALS &sig)
{
  cipher      = sig.cipher;
  enable      =	sig.enable;     
  mode        =	sig.mode;       
  cmdval      =	sig.cmdval;     
  id_src      =	sig.id_src;     
  id_dest     =	sig.id_dest;    
  reg_ready   =	sig.reg_ready;  
  direct_data =	sig.direct_data;
  no_init     = sig.no_init;
  
  for (size_t i=0;i<DES_KEY_SIZE_IN_WORDS;i++)
    key[i] = sig.key[i];

  for (size_t i=0;i<IV_SIZE_IN_WORDS;i++)
    iv[i] = sig.iv[i];

  address = sig.address;
  size = sig.size;
}

sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  CRYPTO_CMD_IN &sig )
{
  ss << sig.mode
     << sig.enable
     << sig.cipher
     << sig.cmdval
     << sig.id_src
     << sig.id_dest
     << sig.reg_ready
     << sig.address
     << sig.direct_data
     << sig.no_init
     << sig.size;

  for (size_t i=0;i<DES_KEY_SIZE_IN_WORDS;i++)
    ss << sig.key[i];

  for (size_t i=0;i<IV_SIZE_IN_WORDS;i++)
    ss << sig.iv[i];

  return ss;
}

sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  CRYPTO_CMD_OUT &sig )
{
  ss << sig.cmdack
     << sig.rspval;

  return ss;
}

void CRYPTO_CMD_SIGNALS::operator () (CRYPTO_CMD_IN &sig)
{
  mode = sig.mode;
  enable = sig.enable;
  cipher = sig.cipher;
  cmdval = sig.cmdval;
  id_src = sig.id_src;
  id_dest = sig.id_dest;
  reg_ready = sig.reg_ready;
  address = sig.address;
  direct_data = sig.direct_data;
  no_init = sig.no_init;
  size = sig.size;

  for (size_t i=0;i<DES_KEY_SIZE_IN_WORDS;i++)
    key[i] = sig.key[i];

  for (size_t i=0;i<IV_SIZE_IN_WORDS;i++)
    iv[i] = sig.iv[i];
}

void CRYPTO_CMD_SIGNALS::operator () (CRYPTO_CMD_OUT &sig)
{
  cmdack = sig.cmdack;
  rspval = sig.rspval;
}

void CRYPTO_CMD_IN::operator () (CRYPTO_CMD_OUT &sig)
{
  cmdack = sig.cmdack;
  rspval = sig.rspval;
}

void CRYPTO_CMD_OUT::operator () (CRYPTO_CMD_IN &sig)
{
  mode = sig.mode;
  enable = sig.enable;
  cipher = sig.cipher;
  cmdval = sig.cmdval;
  id_src = sig.id_src;
  id_dest = sig.id_dest;
  reg_ready = sig.reg_ready;
  address = sig.address;
  direct_data = sig.direct_data;
  no_init = sig.no_init;
  size = sig.size;

  for (size_t i=0;i<DES_KEY_SIZE_IN_WORDS;i++)
    key[i] = sig.key[i];

  for (size_t i=0;i<IV_SIZE_IN_WORDS;i++)
    iv[i] = sig.iv[i];
}

#define IO_BLOCK_ATTACH(x)			\
  for (uint32_t i=0;i<size_in_words;i++)	\
    x::data[i](sig.data[i]);			\
						\
  x::cmd(sig.cmd);				\
  x::addr(sig.addr)				

template<int size_in_words>
TPLOPERATOR_ATTACH(IO_BLOCK, IN, SIGNALS, size_in_words);

template<int size_in_words>
TPLOPERATOR_ATTACH(IO_BLOCK, OUT, SIGNALS, size_in_words);

#define CACHE_CTRL_ACK_ATTACH			\
  rack(sig.rack);				\
  wack(sig.wack);				\
  sack(sig.sack);				\
  rstack(sig.rstack);				\
  full(sig.full);				\
  hit(sig.hit);					\
  dirty(sig.dirty);				\
  victim_address(sig.victim_address);

OPERATOR_ATTACH(CACHE_CTRL_ACK, IN, SIGNALS);
OPERATOR_ATTACH(CACHE_CTRL_ACK, OUT, SIGNALS);

#define CACHE_CTRL_CMD_ATTACH			\
  address(sig.address);				\
  enable(sig.enable);				\
  cmd(sig.cmd);

OPERATOR_ATTACH(CACHE_CTRL_CMD, IN, SIGNALS);
OPERATOR_ATTACH(CACHE_CTRL_CMD, OUT, SIGNALS);

#define INTEGRITY_CTRL_CMD_ATTACH		\
  address(sig.address);				\
  enable(sig.enable);				\
  cmd(sig.cmd);					\
  src(sig.src);

OPERATOR_ATTACH(INTEGRITY_CTRL_CMD, IN, SIGNALS);
OPERATOR_ATTACH(INTEGRITY_CTRL_CMD, OUT, SIGNALS);

void INTEGRITY_CTRL_CMD_IN::operator () (INTEGRITY_CTRL_CMD_OUT &sig)
{
}

void INTEGRITY_CTRL_CMD_OUT::operator () (INTEGRITY_CTRL_CMD_IN &sig)
{
  enable = sig.enable.read();
  cmd = sig.cmd.read();
  address = sig.address.read();
  src = sig.src.read();
}

sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  INTEGRITY_CTRL_CMD_IN &sig )
{
  ss << sig.address
     << sig.enable
     << sig.cmd
     << sig.src;

  return ss;
}

sc_core::sc_sensitive& operator <<(
  sc_core::sc_sensitive &ss,
  INTEGRITY_CTRL_CMD_OUT &sig )
{
  return ss;
}

#define INTEGRITY_CTRL_ACK_ATTACH		\
  cack(sig.cack);				\
  uack(sig.uack);				\
  alap_ack(sig.alap_ack);			\
  iack(sig.iack);

OPERATOR_ATTACH(INTEGRITY_CTRL_ACK, IN, SIGNALS);
OPERATOR_ATTACH(INTEGRITY_CTRL_ACK, OUT, SIGNALS);
