module CA_MATCH ( CVALID, DRAMSZ, ADDR, TAG0, TAG1, CFG, WRITE, MMU_HIT, CI, INVAL_L, KDET, ENDRAM, DC_ILO,
				  CA_HIT, CA_SET, UPDATE, IO_SPACE, USE_CA, WB_ACC, KILL );

	input	[23:0]	CVALID;
	input	 [2:0]	DRAMSZ;
	input	[31:4]	ADDR;
	input  [28:12]	TAG0,TAG1;
	input	 [1:0]	CFG;	// LDC , DC
	input			WRITE;
	input			MMU_HIT;
	input			CI;
	input			INVAL_L;	// invalid cache line
	input			KDET;
	input			ENDRAM;
	input			DC_ILO;		// CBITI/SBITI special case
	
	output			CA_HIT;
	output			CA_SET;	// if no Hit then says SET where to store
	output	[23:0]	UPDATE;	// Update Information for CVALID memory 
	output			IO_SPACE;
	output			USE_CA;
	output			WB_ACC;
	output			KILL;
	
	reg		 [7:0]	maske;
	reg				acc_dram;
	
	wire			match_0,match_1;
	wire			valid_0,valid_1;
	wire			select;
	wire			clear;
	wire	 [7:0]	update_0,update_1,lastinfo;
	wire			sel_dram;
	
	always @(ADDR)
		case (ADDR[6:4])
		  3'h0 : maske = 8'h01;
		  3'h1 : maske = 8'h02;
		  3'h2 : maske = 8'h04;
		  3'h3 : maske = 8'h08;
		  3'h4 : maske = 8'h10;
		  3'h5 : maske = 8'h20;
		  3'h6 : maske = 8'h40;
		  3'h7 : maske = 8'h80;
		endcase
		
	assign valid_0 = (( CVALID[7:0] & maske) != 8'h00);
	assign valid_1 = ((CVALID[15:8] & maske) != 8'h00);
	
	assign match_0 = ( TAG0 == ADDR[28:12] );	// 4KB
	assign match_1 = ( TAG1 == ADDR[28:12] );	// 4KB

	assign CA_HIT = ((valid_0 & match_0) | (valid_1 & match_1)) & ~DC_ILO & CFG[0] & (sel_dram | KDET);
	
	// which SET is written in cache miss ? If both are valid the last used is not taken
	assign select = (valid_1 & valid_0) ? ~((CVALID[23:16] & maske) != 8'h00) : valid_0;	// Last-used field = CVALID[23:16]
	
	assign CA_SET = CA_HIT ? (valid_1 & match_1) : select;
	
	assign clear = INVAL_L | KDET;	// INVAL_L is from CINV
 
	assign update_0 = CA_SET ? CVALID[7:0] : (clear ? (CVALID[7:0] & ~maske) : (CVALID[7:0] | maske));
	assign update_1 = CA_SET ? (clear ? (CVALID[15:8] & ~maske) : (CVALID[15:8] | maske)) : CVALID[15:8];
	
	assign lastinfo = CA_HIT ? (CA_SET ? (CVALID[23:16] | maske) : (CVALID[23:16] & ~maske)) : CVALID[23:16];
	
	assign UPDATE = {lastinfo,update_1,update_0};
	
	assign KILL = clear & CA_HIT & ~CFG[1];		// only if cache is not locked
	
	always @(DRAMSZ or ADDR)	// Size of DRAM
		case (DRAMSZ)
		  3'b000 : acc_dram = (ADDR[28:23] == 6'd0);	//   8 MB 32016 Second Processor
		  3'b001 : acc_dram = (ADDR[28:24] == 5'd0);	//  16 MB
		  3'b010 : acc_dram = (ADDR[28:25] == 4'd0);	//  32 MB
		  3'b011 : acc_dram = (ADDR[28:26] == 3'd0);	//  64 MB
		  3'b100 : acc_dram = (ADDR[28:27] == 2'd0);	// 128 MB
		  3'b101 : acc_dram = ~ADDR[28];				// 256 MB
		  3'b110 : acc_dram =   1'b1;					// 512 MB
		  3'b111 : acc_dram = ~(ADDR[28:27] == 2'b10);	// 256 MB NetBSD + 128 MB
		endcase
	
	assign sel_dram =  (ADDR[31:29] == 3'd0) & acc_dram & ENDRAM;
	assign IO_SPACE = ~sel_dram;					// not DRAM or DRAM ist off
	
	assign USE_CA   = ~CI & ~DC_ILO & CFG[0] & ~CFG[1];	// CI ? ILO ? Cache on ? Locked Cache ? 
	assign WB_ACC   = WRITE & MMU_HIT & sel_dram;
	
endmodule