module DCACHE_SM ( BCLK, BRESET, IO_SPACE, MDONE, IO_READY, MMU_HIT, CA_HIT, READ, WRITE, ZTEST, RMW, CAPDAT, VADR_R, IC_VA, 
				   USE_CA, PTB_WR, PTB_SEL, SEL_PTB1, CPU_OUT, USER, PROT_ERROR, WB_ACC, ENWR, ADR_EQU, IC_PREQ, DMA_CHK, ICTODC,
				   RWVAL, VIRTUELL, QWATWO,
				   DRAM_ACC, DRAM_WR, IO_ACC, IO_RD, IO_WR, PTE_MUX, PD_MUX, PKEEP, PTE_ADR, PTE_DAT, HIT_ALL, ACC_OK,
				   ABORT, PROTECT, IACC_STAT, ABO_LEVEL1, WR_MRAM, CUPDATE, AUX_DAT, NEW_PTB, PTB_ONE, MMU_DIN, IC_SIGS, KOMUX,
				   KDET, DMA_MUX, HLDA, RWVFLAG, PTE_STAT );

	input			BCLK;
	input			BRESET;
	input			IO_SPACE;
	input			MDONE;		// Memory Done : feedback from DRAM Controller, BCLK aligned !
	input			IO_READY;
	input			MMU_HIT,CA_HIT;
	input			READ,WRITE,ZTEST,RMW;
	input	[31:0]	CAPDAT;
	input  [31:12]	VADR_R,IC_VA;
	input			USE_CA;
	input			PTB_WR,PTB_SEL;
	input			SEL_PTB1;
	input  [28:12]	CPU_OUT;	// used for PTB0/1
	input			USER;
	input			PROT_ERROR;
	input			WB_ACC;
	input			ENWR;		// Enable WRITE from DRAM
	input			ADR_EQU;
	input			IC_PREQ;
	input			DMA_CHK;
	input	 [3:0]	ICTODC;		// multiple signals from ICACHE, especially DMA
	input	 [1:0]	RWVAL;		// RDVAL+WRVAL Operation
	input			VIRTUELL;	// for RDVAL/WRVAL
	input			QWATWO;
	
	output	reg		DRAM_ACC,DRAM_WR;
	output			IO_ACC,IO_RD,IO_WR;
	output			PTE_MUX,PD_MUX,PKEEP;
	output	[28:0]	PTE_ADR;
	output	[19:0]	PTE_DAT;
	output			HIT_ALL;
	output			ACC_OK;
	output			ABORT,PROTECT;
	output	 [3:1]	IACC_STAT;
	output			ABO_LEVEL1;
	output			WR_MRAM;
	output			CUPDATE;
	output			AUX_DAT;
	output	reg		NEW_PTB;
	output	reg		PTB_ONE;
	output	[23:0]	MMU_DIN;
	output	 [1:0]	IC_SIGS;
	output			KOMUX;
	output			KDET;		// Signal for detection of collision
	output			DMA_MUX;
	output			HLDA;		// active low
	output			RWVFLAG;	// RDVAL/WRVAL result
	output	 [1:0]	PTE_STAT;
	
	reg				IO_WR,IO_RD;
	reg		 [1:0]	pl_dat;
	reg		 [6:0]	new_state;
	reg				mem_done;
	reg				rd_done;
	reg		 [2:0]	pstate;
	reg				pte_run_wr;
	reg		 [1:0]	prot_level1;
	reg				card_flag;
	reg	   [28:12]	ptb0,ptb1;
	reg				write_ok;
	reg				icp_acc;
	reg		 [2:0]	ko_state;
	reg				dma_run;
	reg				dma_kdet;
	reg				rwv_bit;
	reg				prot_i;
	reg				rd_rdy;
	
	wire   [28:12]	ptb10;
	wire   [31:12]	virtual_adr;
	wire			io_busy;
	wire			dram_go;
	wire			pte_sel;
	wire			pte_acc;
	wire			do_ca_rd,pte_go,do_ic_p;
	wire			valid,valid_a,refer,modi;
	wire			level1,level2;
	wire			rd_level2;
	wire			wr_req;
	wire			wr_dram;
	wire			wr_icmram;
	wire			rd_ende;
	wire			pte_dat_8;
	wire			pte_wr_sig;
	wire			run_dc;
	wire			kostart;
	wire			dma;
	wire			dma_go;
	wire			zugriff;
	wire			mmu_hit_i;
	wire			do_zt;
	wire			zt_ok;
	wire	 [1:0]	acc_level;
	wire			user_ptw,wr_ptw;
	wire			pte_puls;
	
	// if USER not virtual then ZTEST is quickly done
	assign zugriff = READ | WRITE | (ZTEST & VIRTUELL);
	assign mmu_hit_i = MMU_HIT & ~ZTEST;
	
	// WB_ACC is a successful WRITE access, ICTODC[0] is coherent Logik release : >=3 entries in FIFO
	assign wr_req = WB_ACC & ((ENWR & ICTODC[0]) | (DRAM_WR & ADR_EQU));	// release done by DRAM signal ENWR

	assign rd_ende = CA_HIT | rd_rdy;	// CA_HIT only when Cache activ !
	
	always @(	 zugriff 	// READ or WRITE or ZTEST , global control
			  or PROT_ERROR	// must not be
			//
			  or IO_SPACE	// access of IO world
			  or io_busy	// is access already running ?
			//
			  or mmu_hit_i	// Hit in MMU , now only a READ can happen
			  or READ
			  or wr_req
			  or rd_ende	// Cache Hit
			//
			  or DRAM_ACC 	// DRAM Access : shows an active state
			  or pte_acc 	// PTE access is running
			//
			  or IC_PREQ 	// PTE Request from ICACHE
			//
			  or dma		// DMA Request
			  or dma_run )	// DMA running
			//					 #_#			  #_#						    #_#					    #_#
		casex ({zugriff,PROT_ERROR,IO_SPACE,io_busy,mmu_hit_i,READ,wr_req,rd_ende,DRAM_ACC,pte_acc,IC_PREQ,dma,dma_run})
		// MMU Miss : PTE load from memory , valid too if WRITE and M=0
		  13'b10_xx_0xxx_x0_x_x0 : new_state = 7'b0001010;	// start PTE access
	  	// IO-Address selected : external access starts if not busy because of WRITE
		  13'b10_10_1xxx_x0_x_x0 : new_state = 7'b0000001;
		// DRAM access : Cache Miss at READ : 
		  13'b10_0x_1100_00_x_x0 : new_state = 7'b0010010;
		// DRAM access : WRITE
		  13'b10_0x_101x_x0_x_x0 : new_state = 7'b0000100;
		// PTE Request ICACHE , IO access with WRITE is stored - parallel DRAM access possible
		  13'b0x_xx_xxxx_x0_1_x0 : new_state = 7'b0101010;	// no access
		  13'b10_0x_1101_x0_1_x0 : new_state = 7'b0101010;	// if successful READ a PTE access can happen in parallel
		// DMA access. Attention : no IO-Write access in background and no ICACHE PTE access !
		  13'b0x_x0_xxxx_x0_0_10 : new_state = 7'b1000000;	// DMA access is started
		  default 				 : new_state = 7'b0;
		endcase
		
	assign IO_ACC   = new_state[0];	// to load registers for data, addr und BE, signal one pulse
	assign dram_go  = new_state[1] | rd_level2 ;
	assign wr_dram  = new_state[2];	// pulse only
	assign pte_go   = new_state[3];
	assign do_ca_rd = new_state[4];
	assign do_ic_p	= new_state[5];
	assign dma_go	= new_state[6];

	// ZTEST logic is for the special case when a write access is crossing page boundaries
	
	assign do_zt = ZTEST & ~icp_acc;
	
	// 0 is pass , 1 is blocked. RWVAL[0] is 1 if WRVAL. Level 1 can only be blocked, otherwise ABORT or Level 2 is following.
	always @(posedge BCLK) if (mem_done) rwv_bit <= level2 ? ~(CAPDAT[2] & (~RWVAL[0] | CAPDAT[1])) : 1'b1;
	
	assign RWVFLAG = VIRTUELL & rwv_bit;
	
	assign zt_ok = mem_done & (RWVAL[1] ? (~CAPDAT[2] | (RWVAL[0] & ~CAPDAT[1]) | level2)	// Level 2 always ok
										: (CAPDAT[0] & ~prot_i & level2) );	// "normal" access

	// PTE access logic, normal state machine
	// Updates to the PTEs are normal WRITE request to DRAM, therefore no MDONE at Write
	
	assign modi  = ~CAPDAT[8] & WRITE & write_ok & ~icp_acc;	// is "1" if the Modified Bit must be set
	assign refer = CAPDAT[7] | do_zt;	// Assumption "R" Bit is set if RDVAL/WRVAL and page border test
	assign valid = (do_zt & RWVAL[1]) ? (CAPDAT[2] & (CAPDAT[1] | ~RWVAL[0]) & CAPDAT[0] & level1)
									  : (CAPDAT[0] & ~prot_i);
	
	always @(posedge BCLK) mem_done <= MDONE & pte_acc;
	
	always @(posedge BCLK or negedge BRESET)
		if (!BRESET) pstate <= 3'h0;
		  else
			casex ({pte_go,mem_done,valid,refer,modi,pte_run_wr,pstate})
			  9'b0x_xxxx_000 : pstate <= 3'd0;	// nothing to do
			  9'b1x_xxxx_000 : pstate <= 3'd4;	// start
			  9'bx0_xxxx_100 : pstate <= 3'd4;	// wait for Level 1
			  9'bx1_0xxx_100 : pstate <= 3'd0;	// THAT'S ABORT ! 
			  9'bx1_11xx_100 : pstate <= 3'd6;	// PTE Level 1 was referenced , next is Level 2
			  9'bx1_10xx_100 : pstate <= 3'd5;	// for writing of modified Level 1 : R=1
			  9'bxx_xxx0_101 : pstate <= 3'd5;	// write must wait
			  9'bxx_xxx1_101 : pstate <= 3'd6;	// one wait cycle
			  9'bx0_xxxx_110 : pstate <= 3'd6;	// wait for Level 2
			  9'bx1_0xxx_110 : pstate <= 3'd0;	// THAT'S ABORT !
			  9'bx1_10xx_110 : pstate <= 3'd7;	// Update neccesary : R=0
			  9'bx1_110x_110 : pstate <= 3'd0;	// all ok - end
			  9'bx1_111x_110 : pstate <= 3'd7;	// Update neccesary : M=0
			  9'bxx_xxx0_111 : pstate <= 3'd7;	// write must wait
			  9'bxx_xxx1_111 : pstate <= 3'd0;	// continues to end of DRAM write
			  default	     : pstate <= 3'd0;
			endcase
			
	assign pte_acc =  pstate[2];
	assign level1  = ~pstate[1];
	assign level2  =  pstate[1];
	
	assign valid_a = (ZTEST & RWVAL[1]) ? (CAPDAT[2] & (CAPDAT[1] | ~RWVAL[0]) & ~CAPDAT[0] & level1)
										: ~CAPDAT[0];	// not do_zt because of icp_acc in ABORT

	assign ABORT   =   mem_done & valid_a & ~icp_acc;
	assign PROTECT = ((mem_done & prot_i  & ~icp_acc) | PROT_ERROR) & ~(ZTEST & RWVAL[1]);	// no Protection-Error at RDVAL/WRVAL

	assign IACC_STAT[1] = mem_done & ~CAPDAT[0] & icp_acc;
	assign IACC_STAT[2] = level1;
	assign IACC_STAT[3] = mem_done & prot_i & icp_acc;

	assign ABO_LEVEL1 = level1;	// is stored in case of ABORT in ADDR_UNIT
	
	assign rd_level2 = (pstate == 3'd5) | (mem_done & (pstate == 3'd4) & refer & valid);

	assign WR_MRAM   = mem_done &  (pstate == 3'd6) & valid & ~icp_acc & ~ZTEST;
	assign wr_icmram = mem_done &  (pstate == 3'd6) & valid &  icp_acc;
	
	// Signals to the Instruction Cache
	// pte_acc combined with icp_acc for STATISTIK.
	assign IC_SIGS = {(pte_acc & icp_acc),wr_icmram};
	
	assign PTE_MUX = pte_go | (pte_acc & ~pstate[1]);

	assign pte_puls = mem_done & pte_acc & ~pstate[1];
	assign PTE_STAT = {(pte_puls & icp_acc),(pte_puls & ~icp_acc)};	// only for statistic
	
	assign PD_MUX =  ((pstate == 3'd4) & mem_done & valid & ~refer)		// switch data-MUX, write level 1 too
				   | ((pstate == 3'd6) & mem_done & valid & (~refer | modi))	// write level 2
				   | (((pstate == 3'd5) | (pstate == 3'd7)) & ~pte_run_wr);

	assign pte_wr_sig = ENWR & PD_MUX;
	
	always @(posedge BCLK) pte_run_wr <= pte_wr_sig;	// Ok-Signal for pstate State-machine
	
	assign PKEEP = (pstate == 3'd6) | ((pstate == 3'd7) & ~pte_run_wr);	// keep the DRAM address
	
	// If there is a PTE still in the data cache it must be deleted. If MMU Bits are set by the pte engine a following
	// READ would deliver wrong data if cache hit. Therefore access of the Tags.
	always @(posedge BCLK or negedge BRESET)
		if (!BRESET) ko_state <= 3'b000;
		  else
			casex ({kostart,ko_state})
			  4'b0_000 : ko_state <= 3'b000;
			  4'b1_000 : ko_state <= 3'b110;
			  4'bx_110 : ko_state <= 3'b111;
			  4'bx_111 : ko_state <= 3'b100;
			  4'bx_100 : ko_state <= 3'b000;
			  default  : ko_state <= 3'b000;
			endcase
			
	assign kostart = pte_go | rd_level2;
	
	// ko_state[2] suppresses ACC_OK at READ
	assign run_dc = (~ko_state[2] | QWATWO) & ~dma_run;	// Bugfix of 7.10.2015
	assign KOMUX  =   ko_state[1] 			|  DMA_MUX;
	assign KDET   =   ko_state[0] 			|  dma_kdet;
	  
	assign HIT_ALL = MMU_HIT & CA_HIT & run_dc & ~pte_acc;	// for Update "Last-Set" , MMU_HIT contains ZUGRIFF
	
	always @(posedge BCLK or negedge BRESET)
		if (!BRESET) card_flag <= 1'b0;
			else card_flag <= (do_ca_rd & ~rd_rdy) | (card_flag & ~MDONE);
	
	assign CUPDATE = card_flag & USE_CA & MDONE;

	always @(posedge BCLK) rd_rdy <= card_flag & MDONE;
	
	// The cache RAM can not provide fast enough the data after an Update. In this case a secondary data path is activated
	assign AUX_DAT = rd_rdy;
	
	// DRAM interface :

	always @(posedge BCLK)				DRAM_WR  <= wr_dram | pte_wr_sig; // pulse
	always @(posedge BCLK) if (dram_go) DRAM_ACC <= 1'b1;
							 else
								DRAM_ACC <= DRAM_ACC & ~MDONE & BRESET;
	// IO interface :
	
	always @(posedge BCLK)
	  begin
		if (IO_ACC) IO_RD <= READ;  else IO_RD <= IO_RD & ~IO_READY & BRESET;
		if (IO_ACC) IO_WR <= WRITE; else IO_WR <= IO_WR & ~IO_READY & BRESET;
	  end
	  
	assign io_busy = IO_RD | IO_WR | rd_done;	// access is gone in next clock cycle, therefore blocked with "rd_done"
	
	always @(posedge BCLK) rd_done <= IO_RD & IO_READY;	// For READ one clock later for data to come through
	
	assign dma = ICTODC[2];	// external request HOLD after FF in ICACHE
	
	always @(posedge BCLK) dma_run <= (dma_go | (dma_run & dma)) & BRESET;	// stops the data access until HOLD becomes inactive
	
	assign HLDA = ~(ICTODC[1] & dma_run);	// Signal for system that the CPU has stopped accesses
	
	always @(posedge BCLK) dma_kdet <= DMA_CHK;
	assign DMA_MUX = DMA_CHK | dma_kdet;
	
	// global feedback to ADDR_UNIT, early feedback to Op-Dec : you can continue
	
	assign ACC_OK = ZTEST ? (~VIRTUELL | zt_ok)
						  : (IO_SPACE ? ((IO_ACC & WRITE) | rd_done) : (wr_dram | (READ & MMU_HIT & rd_ende & run_dc)) );
						  
	// PTB1 and PTB0
	
	always @(posedge BCLK) if (PTB_WR && !PTB_SEL) ptb0 <= CPU_OUT;
	always @(posedge BCLK) if (PTB_WR &&  PTB_SEL) ptb1 <= CPU_OUT;
	
	always @(posedge BCLK) NEW_PTB <= PTB_WR;			// to MMU Update Block
	always @(posedge BCLK) if (PTB_WR) PTB_ONE <= PTB_SEL;
	
	assign ptb10 = SEL_PTB1 ? ptb1 : ptb0;
	
	// Address multiplex between ICACHE=1 and DCACHE=0 :
	always @(posedge BCLK) if (pte_go) icp_acc <= do_ic_p;
				
	assign pte_sel = pte_go ? do_ic_p : icp_acc;
	
	assign virtual_adr = pte_sel ? IC_VA : VADR_R;
	
	// The 2 Address-LSB's : no full access : USE_CA = 0	
	assign PTE_ADR = rd_level2 ? {CAPDAT[28:12],virtual_adr[21:12],2'b00} : {ptb10,virtual_adr[31:22],2'b00};
	
	// PTE_DAT[8] is used for update of MMU_RAM.
	assign pte_dat_8 = (level2 & WRITE & write_ok & ~icp_acc) | CAPDAT[8];
	assign PTE_DAT = {4'h3,CAPDAT[15:9],pte_dat_8,1'b1,CAPDAT[6:0]};	// the top 4 bits are Byte-Enable
	
	// The data for the MMU-RAM : 24 Bits , [6]=Cache Inhibit
	assign MMU_DIN = {pl_dat,pte_dat_8,CAPDAT[6],CAPDAT[31:12]};
	
	// Protection field
	
	always @(posedge BCLK) if (mem_done && (pstate[2:0] == 3'd4)) prot_level1 <= CAPDAT[2:1];

	always @(prot_level1 or CAPDAT)	
		casex ({prot_level1,CAPDAT[2]})
		  3'b11_x : pl_dat = CAPDAT[2:1];
		  3'b10_1 : pl_dat = 2'b10;
		  3'b10_0 : pl_dat = CAPDAT[2:1];
		  3'b01_1 : pl_dat = 2'b01;
		  3'b01_0 : pl_dat = CAPDAT[2:1];
		  3'b00_x : pl_dat = 2'b00;
		endcase
		
	always @(USER or pl_dat)	// is used if no PTE update is neccesary for M-Bit if writing is not allowed
		casex ({USER,pl_dat})
		  3'b1_11 : write_ok = 1'b1;
		  3'b0_1x : write_ok = 1'b1;
		  3'b0_01 : write_ok = 1'b1;
		  default : write_ok = 1'b0;
		endcase
		
	assign acc_level = level2 ? pl_dat : CAPDAT[2:1];
	assign user_ptw = icp_acc ? ICTODC[3] : USER;
	assign wr_ptw = ~icp_acc & (WRITE | RMW | (ZTEST & ~RWVAL[1]));	// only data cache can write
	
	always @(acc_level or user_ptw or wr_ptw)
		case (acc_level)
			2'b00 : prot_i = user_ptw | wr_ptw;
			2'b01 : prot_i = user_ptw;
			2'b10 : prot_i = user_ptw & wr_ptw;
			2'b11 : prot_i = 1'b0;
		endcase
		
endmodule