#ifndef	__CACHE_H
#define	__CACHE_H
#include <systemc.h>
#include "B128.h"
#include "MAIN.h"

#define	dcachewidth  DCACHE_width //unit byte
#define	dcachesets   DCACHE_nset	//two way
#define	dcacherowb	DCACHE_nA
#define	dcachesetmask (dcachesets-1)
#define	dcachelocmask ((dcachewidth/4)-1)   //unit 32bit
#define	dcacherows	(1<<dcacherowb)
#define	dcacherowmask	(dcacherows-1)
#define	dcachewidthmask  (dcachewidth-1)

#if (dcachewidth<(CPUDATAWIDTH/8))
#define ddcachewerr
#elif	(dcachewidth==4)
    #define	dcachewidthb 2
#elif	(dcachewidth==8)
  #define	dcachewidthb 3
#elif	(dcachewidth==16)
  #define	dcachewidthb 4
#elif	(dcachewidth==32)
  #define	dcachewidthb 5
#else
  #define dcachewerr
#endif

#ifdef dcachewerr
  #if (CPUDATAWIDTH==32)
    #error "DCACHE_width should be 4,8,16,32"
  #elif (CPUDATAWIDTH==64)
    #error "DCACHE_width should be 8,16,32"
  #elif (CPUDATAWIDTH==128)
    #error "DCACHE_width should be 16,32"
  #else
    #error 
  #endif
#endif
#if (dcachesets==1)
#define dcachesetb 0
#elif (dcachesets==2)
#define dcachesetb 1
#elif (dcachesets==4)
#define dcachesetb 2
#elif (dcachesets==8)
#define dcachesetb 3
#elif (dcachesets==16)
#define dcachesetb 4
#elif (dcachesets==32)
#define dcachesetb 5
#elif (dcachesets==64)
#define dcachesetb 6
#else
#error "DCACHE_nset should be 1,2,4,8,16,32,64"
#endif

#define	dcachecolb	(dcachewidthb-CPUDATAWIDTHb)
#define	dcachecols	(1<<dcachecolb)
#define	dcachecolmask	(dcachecols-1)
#define	dcachetagsh	(dcachewidthb+dcacherowb)
#define	dcachetagb	(30-dcachewidthb-dcacherowb) //A[31:30]=00
#define	dcachelrub	dcachesetb   //dcachesetb<=n<=32-dcachetagb
#define	dcachelrumask	((1<<dcachelrub)-1)

/////////////////////////////////////////////////////////

SC_MODULE(DCACHE)
{
	sc_in_clk			clk;
	sc_in<sc_uint<1> >		reset;
	sc_in<sc_uint<1> >		ram_trans;
	//sc_in<sc_uint<1> >		ram_seq;
	sc_in<sc_uint<1> >		ram_write;
	sc_in<sc_uint<2> >		ram_size;
	sc_in<sc_uint<32> >		ram_addr;
	sc_in<sc_uint<32> >		ram_wdata[CPUDATAWIDTH/32];
	sc_out<sc_uint<32> >		ram_rdata[CPUDATAWIDTH/32];
	sc_out<sc_uint<1> >		ram_ready;
	sc_out<sc_uint<1> >		xm_req;
	sc_in<sc_uint<1> >		xm_grant;
	sc_out<sc_uint<1> >		xm_trans;
	sc_out<sc_uint<1> >		xm_seq;
	sc_out<sc_uint<1> >		xm_last;
	sc_out<sc_uint<1> >		xm_write;
	sc_out<sc_uint<4> >		xm_we;
	sc_out<sc_uint<32> >		xm_addr;
	sc_out<sc_uint<32> >		xm_wdata;
	sc_in<sc_uint<32> >		xm_rdata;
	sc_in<sc_uint<1> >		xm_ready;
	sc_in<sc_uint<1> >		invalid;
	sc_out<sc_uint<1> >		invalidbusy;

	sc_signal<sc_uint<1> >		binvalid;

	//first cmd buffer@ready
	bool		mwaiting;
	bool		mrwaiting; //waiting for reload
	bool		mmodew;
	unsigned	maddr;
	unsigned	mrowtag; //part of maddr
	unsigned	mrow;
	unsigned	mtag;
	char		msize;
	bool		mrvalid;
	B128		mdata;
	//second cmd buffer@proc
	bool		bready;
	bool		bmodew;
	unsigned	baddr;
	unsigned	browtag; //part of baddr
	unsigned	brow;
	unsigned	btag;
	char		bsize;
	int		bset; //working set
	int		b1set; //next row set
	bool		b1valid; //next row is valid @brow+1,bset1
	bool		bisnext; //loading next row
	char		bdata[dcachewidth+CPUDATAWIDTH/8]; //one col+one word
	unsigned	bdirty; //one bit per byte
	unsigned	brvalid; //one bit per dword
	char		bmsts; //buff->mem
	char		bmcnt;
	bool		bchecktag;
	bool		bchecktagfail;
	//cache ram
	unsigned char	memdatas[dcacherows*dcachesets*dcachecols][CPUDATAWIDTH/8];
	int		memtags[dcacherows][dcachesets]; //tags and lrus combine 32bit
	int		memlrus[dcacherows][dcachesets];
	//
	bool		noclear;

	int		countWritesameblock;
	int		countReadsameblock;
	int		countWritehit;
	int		countWritemis;
	int		countReadhit;
	int		countReadmis;

	void	setinvalid();
	void	entry();
	void	statistic();
	bool	loaddata(const unsigned long *data,unsigned long startaddr,int dwords);

	SC_CTOR(DCACHE)
    	{
		SC_METHOD(entry);
		sensitive_pos<<clk;
		setinvalid();
		noclear=false;
	}
};

#endif
