OpenCores
URL https://opencores.org/ocsvn/m32632/m32632/trunk

Subversion Repositories m32632

[/] [m32632/] [trunk/] [rtl/] [CACHE_LOGIK.v] - Rev 27

Go to most recent revision | Compare with Previous | Blame | View Log

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// This file is part of the M32632 project
// http://opencores.org/project,m32632
//
//	Filename:	CACHE_LOGIK.v
//	Version:	2.0
//	History:	1.1 bug fix of 7 October 2015
//				1.0 first release of 30 Mai 2015
//	Date:		14 August 2016
//
// Copyright (C) 2016 Udo Moeller
// 
// This source file may be used and distributed without 
// restriction provided that this copyright statement is not 
// removed from the file and that any derivative work contains 
// the original copyright notice and the associated disclaimer.
// 
// This source file is free software; you can redistribute it 
// and/or modify it under the terms of the GNU Lesser General 
// Public License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any 
// later version. 
// 
// This source is distributed in the hope that it will be 
// useful, but WITHOUT ANY WARRANTY; without even the implied 
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
// PURPOSE. See the GNU Lesser General Public License for more 
// details. 
// 
// You should have received a copy of the GNU Lesser General 
// Public License along with this source; if not, download it 
// from http://www.opencores.org/lgpl.shtml 
// 
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//	Modules contained in this file:
//	1. NEU_VALID	Cache Valid RAM
//	2. DEBUG_AE  	Debug unit for address compare in data cache
//	3. MMU_UP		MMU memory update and initalization controller
//	4. DCA_CONTROL	Data cache valid memory update and initalization controller
//	5. MMU_MATCH	MMU virtual address match detector
//	6. CA_MATCH		Cache tag match detector
//	7. FILTCMP		Address Filter and Comparator
//	8. DCACHE_SM	Data cache state machine
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//	1. NEU_VALID 	Cache Valid RAM
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
module NEU_VALID ( BCLK, VALIN, WADR, WREN, RADR, VALOUT );
 
	input			BCLK;
	input	[23:0]	VALIN;
	input	 [4:0]	WADR;
	input			WREN;
	input	 [4:0]	RADR;
 
	output	[23:0]	VALOUT;
 
	reg		[23:0]	cvalid [0:31];	// Valid bits for Data Set 0 and 1 : 32 entries of 24 bits
	reg		[23:0]	ramout;
	reg		[23:0]	valhold;
	reg				gleich;
 
	always @(posedge BCLK) ramout <= cvalid[RADR];
	always @(posedge BCLK) if (WREN) cvalid[WADR] <= VALIN;
 
	always @(posedge BCLK) valhold <= VALIN;
	always @(posedge BCLK) gleich  <= WREN & (RADR == WADR);
 
	assign VALOUT = gleich ? valhold : ramout;
 
endmodule
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//	2. DEBUG_AE  	Debug unit for address compare in data cache
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
module DEBUG_AE ( DBG_IN, READ, WRITE, USER, VIRTUELL, ACC_OK, VADR_R, MMU_Q, ENBYTE, DBG_HIT );
 
	input	[40:2]	DBG_IN;
 
	input			READ,WRITE;
	input			USER;
	input			VIRTUELL;
	input			ACC_OK;
	input	[31:2]	VADR_R;
	input	[19:0]	MMU_Q;
	input	 [3:0]	ENBYTE;
 
	output	 		DBG_HIT;
 
	wire			sd,ud,crd,cwr,vnp;
	wire			make;
	wire			virt_adr,real_adr,page_adr;
	wire			byte_en;
 
	assign sd  = DBG_IN[40];
	assign ud  = DBG_IN[39];
	assign crd = DBG_IN[38];
	assign cwr = DBG_IN[37];
	assign vnp = DBG_IN[36];
 
	assign make =  ((ud & USER) | (sd & ~USER))		// compare USER or SUPERVISOR
				 & (VIRTUELL == vnp)				// compare real or virtual address
				 & ((cwr & WRITE) | (crd & READ));	// compare READ or WRITE
 
	assign virt_adr = (MMU_Q 		 == DBG_IN[31:12]);
	assign real_adr = (VADR_R[31:12] == DBG_IN[31:12]);
	assign page_adr = (VADR_R[11:2]	 == DBG_IN[11:2]);
 
	assign byte_en  = |(ENBYTE & DBG_IN[35:32]);
 
	assign DBG_HIT  =  ACC_OK		// all valid
					 & make			// selection is valid
					 & (VIRTUELL ? virt_adr : real_adr)	& page_adr	// address
					 & byte_en;		// Byte Enable
 
endmodule
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//	3. MMU_UP		MMU memory update and initalization controller
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
module MMU_UP ( BCLK, BRESET, NEW_PTB, PTB1, IVAR, WR_MRAM, VADR, VADR_R, MVALID, UPDATE,
				WE_MV, WADR_MV, RADR_MV, DAT_MV, NEW_PTB_RUN );
 
	input			BCLK;
	input			BRESET;	
	input			NEW_PTB;	// the MMU memory is cleared. Pulse of one BCLK cycle, Op-Dec is waiting
	input			PTB1;		// which one
	input			IVAR;
	input			WR_MRAM;	// BCLK : update MRAM and MMU_VAL
	input  [19:16]	VADR,VADR_R;	// For update
	input	[31:0]	MVALID,UPDATE;
 
	output			WE_MV;		// Write Enable MMU Valid
	output	 [3:0]	WADR_MV,RADR_MV;
	output	[31:0]	DAT_MV;
	output			NEW_PTB_RUN;
 
	reg				neue_ptb,wr_flag,old_rst,run_over;
	reg		 [3:0]	count;
 
	wire	[15:0]	new_val;
 
	assign WE_MV   = wr_flag | WR_MRAM | IVAR;	// write on falling edge BCLK
	assign RADR_MV = run_over ? count : VADR;
	assign WADR_MV = wr_flag ? (count - 4'b0001) : VADR_R;
	assign DAT_MV  = wr_flag ? {MVALID[31:16],new_val} : UPDATE;	// Only the matching entries are cleared : PTB0/PTB1
 
	// [31:16] Address-Space memory, [15:0] Valid memory
	assign new_val = neue_ptb ? (PTB1 ? (MVALID[15:0] & ~MVALID[31:16]) : (MVALID[15:0] & MVALID[31:16])) : 16'h0;
 
	always @(posedge BCLK or negedge BRESET)
		if (!BRESET) neue_ptb <= 1'b0;
			else neue_ptb <= NEW_PTB | (neue_ptb & run_over);
 
	always @(posedge BCLK) old_rst <= BRESET;	// after Reset all will be set to 0 
 
	always @(posedge BCLK) run_over <= ((~old_rst | NEW_PTB) | (run_over & (count != 4'hF))) & BRESET;
 
	always @(posedge BCLK) count <= run_over ? count + 4'h1 : 4'h0;
 
	always @(posedge BCLK) wr_flag <= run_over;
 
	assign NEW_PTB_RUN = wr_flag;	// Info to Op-Dec
 
endmodule
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//	4. DCA_CONTROL	Data cache valid memory update and initalization controller
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
module DCA_CONTROL ( BCLK, MCLK, BRESET, CUPDATE, DRAM_ACC, CA_SET, HIT_ALL, WRCFG, VADR_R, UPDATE, INVAL_A, WRITE,
					 WCTRL, KILL, WRCRAM0, WRCRAM1, WE_CV, WADR_CV, DAT_CV, INIT_CA_RUN, WRSET0, WRSET1 );
 
	input			BCLK;
	input			MCLK;
	input			BRESET;
	input			CUPDATE;	// State CUPDATE : Cache is filled from DRAM
	input			DRAM_ACC;
	input			CA_SET;
	input			HIT_ALL;	// a complete cache hit !
	input			WRCFG;		// static signal : GND or VDD
	input	[11:7]	VADR_R;
	input	[23:0]	UPDATE;
	input			INVAL_A;
	input			WRITE;
	input	 [1:0]	WCTRL;		// [1] : Read Burst Signal from DRAM controller, MCLK aligned. [0] : Cache inhibit
	input			KILL;		// valid Ram must be updated because of collision ... or CINV
 
	output			WRCRAM0,WRCRAM1;
	output			WE_CV;
	output	 [4:0]	WADR_CV;
	output	[23:0]	DAT_CV;
	output			INIT_CA_RUN;
	output			WRSET0,WRSET1;
 
	reg		 [1:0]	state;
	reg		 [4:0]	acount;
	reg				ca_set_d;
 
	reg				dly_bclk,zero,wr_puls;
	reg		 [2:0]	count,refer;
 
	wire			countf;
 
	always @(posedge BCLK) if (DRAM_ACC) ca_set_d <= CA_SET;	// Store for whole access
 
	// physical address is stored in TAG-RAM
 
	assign WRCRAM0 = (CUPDATE & ~WCTRL[0]) & ~ca_set_d;
	assign WRCRAM1 = (CUPDATE & ~WCTRL[0]) &  ca_set_d;
 
	// Load Valid RAM :
 
	assign WE_CV   = state[1] | HIT_ALL | (CUPDATE & ~WCTRL[0]) | KILL; // Hit All for "Last" Update
	assign WADR_CV = state[1] ? acount : VADR_R;
	assign DAT_CV  = state[1] ? 24'h0 : UPDATE;	
 
	// Clear of Cache-Valid RAMs : 32 clocks of BCLK
 
	assign countf = (acount == 5'h1F);
 
	always @(posedge BCLK)
		casex ({BRESET,INVAL_A,countf,state[1:0]})
		  5'b0xx_xx : state <= 2'b01;
		  5'b1xx_01 : state <= 2'b10;		// start counter
		  5'b10x_00 : state <= 2'b00;		// wait ...
		  5'b11x_00 : state <= 2'b10;
		  5'b1x0_10 : state <= 2'b10;
		  5'b1x1_10 : state <= 2'b00;
		  default   : state <= 2'b0;
		endcase
 
	always @(posedge BCLK) if (!state[1]) acount <= 5'h0; else acount <= acount + 5'h01;
 
	assign INIT_CA_RUN = state[1];
 
	// WRITE Control in data RAMs
	assign WRSET0 = ( ~CA_SET & WRITE & HIT_ALL & wr_puls) | (WCTRL[1] & ~ca_set_d);
	assign WRSET1 = (  CA_SET & WRITE & HIT_ALL & wr_puls) | (WCTRL[1] &  ca_set_d);
 
	// ++++++++++++ Special circuit for Timing of write pulse for data RAM of data cache +++++++++
 
	always @(negedge MCLK) dly_bclk <= BCLK;
 
	always @(negedge MCLK) zero <= BCLK & ~dly_bclk;
 
	always @(posedge MCLK) if (zero) count <= 3'd0; else count <= count + 3'd1;
 
	//    count at zero , ref Wert
	// 1 : --- always on	5 : 100  001
	// 2 : 001  000			6 : 101  010
	// 3 : 010  010			7 : 110  011
	// 4 : 011  000			8 : 111  100
	always @(posedge MCLK) if (zero) refer <= {(count == 3'd7),((count == 3'd5) | (count[1:0] == 2'b10)),(count[2] & ~count[0])};
 
	always @(posedge MCLK) wr_puls <= (count == refer) | WRCFG;
 
endmodule
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//	5. MMU_MATCH	MMU virtual address match detector
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
module MMU_MATCH ( USER, READ, WRITE, RMW, MCR_FLAGS, MVALID, VADR_R, MMU_VA, IVAR,
				   VIRTUELL, MMU_HIT , UPDATE, PROT_ERROR, CI, SEL_PTB1 );
 
	input			USER;
	input			READ;
	input			WRITE;
	input			RMW;
	input	 [2:0]	MCR_FLAGS;
	input	[31:0]	MVALID;
	input  [31:12]	VADR_R;
	input  [31:16]	MMU_VA;
	input	 [1:0]	IVAR;	// Invalidate Entry
 
	output			VIRTUELL;	// only for Adress-Mux
	output			MMU_HIT;
	output	[31:0]	UPDATE;
	output	reg		PROT_ERROR;	// if valid must suppress write in Write Buffer and cache
	output			CI,SEL_PTB1;
 
	reg		[15:0]	maske;
 
	wire			adr_space,as_sorte,match,alles_ok;
	wire	[15:0]	val_bits,as_bits;
	wire			ena_prot;
	wire			zugriff;
 
	assign zugriff = READ | WRITE;
 
	always @(VADR_R)
		case (VADR_R[15:12])
		  4'h0 : maske = 16'h0001;
		  4'h1 : maske = 16'h0002;
		  4'h2 : maske = 16'h0004;
		  4'h3 : maske = 16'h0008;
		  4'h4 : maske = 16'h0010;
		  4'h5 : maske = 16'h0020;
		  4'h6 : maske = 16'h0040;
		  4'h7 : maske = 16'h0080;
		  4'h8 : maske = 16'h0100;
		  4'h9 : maske = 16'h0200;
		  4'hA : maske = 16'h0400;
		  4'hB : maske = 16'h0800;
		  4'hC : maske = 16'h1000;
		  4'hD : maske = 16'h2000;
		  4'hE : maske = 16'h4000;
		  4'hF : maske = 16'h8000;
		endcase
 
	assign VIRTUELL = USER ? MCR_FLAGS[0] : MCR_FLAGS[1];
 
	assign adr_space = IVAR[1] ? IVAR[0] : (MCR_FLAGS[2] & USER);	// adr_space = IVARx ? 1 or 0 : DualSpace & TU
 
	assign as_sorte = ((MVALID[31:16] & maske) != 16'h0);
 
	assign match = (VADR_R[31:20] == MMU_VA[31:20]) & (adr_space == as_sorte) & ((MVALID[15:0] & maske) != 16'h0000);
 
	assign alles_ok = match & ( ~WRITE | MMU_VA[17] ) & ~PROT_ERROR;	// Modified - Flag : reload the PTE
 
	// if MMU_HIT = 0 then there is no Write-Buffer access and no update of cache !
	assign MMU_HIT = zugriff ? ( VIRTUELL ? alles_ok : 1'b1 ) : 1'b0 ;	// MMU off : then always HIT
 
	assign val_bits = IVAR[1] ? (MVALID[15:0] & (match ? ~maske : 16'hFFFF)) : (MVALID[15:0] | maske);
	assign as_bits  = IVAR[1] ? MVALID[31:16] : (adr_space ? (MVALID[31:16] | maske) : (MVALID[31:16] & ~maske));
 
	assign UPDATE = {as_bits,val_bits};
 
	assign ena_prot = zugriff & VIRTUELL & match;
 
	// A Protection error must suppress write in WB and cache
	always @(ena_prot or MMU_VA or USER or WRITE or RMW)
		case ({ena_prot,MMU_VA[19:18]})
		   3'b100 : PROT_ERROR = USER | WRITE | RMW;	// Only Supervisor READ
		   3'b101 : PROT_ERROR = USER;					// no USER access
		   3'b110 : PROT_ERROR = USER & (WRITE | RMW);	// USER only READ
		  default : PROT_ERROR = 1'b0;
		endcase
 
	assign CI = VIRTUELL & MMU_VA[16];
	assign SEL_PTB1 = adr_space;		// For PTE update
 
endmodule
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//	6. CA_MATCH		Cache tag match detector
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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  [27: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		 [4:0]	szmaske;
 
	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,filter;
 
	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[27:12] );	// 4KB
	assign match_1 = ( TAG1 == ADDR[27:12] );	// 4KB
 
	assign CA_HIT = ((valid_0 & match_0) | (valid_1 & match_1)) & ~DC_ILO & CFG[0];
 
	// 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)	// Size of DRAM
		casex (DRAMSZ)
		   3'b00x : szmaske = 5'h1F;	//   8 MB 32016 Second Processor
	// 	   3'b001 reserved for Ceres III
		   3'b01x : szmaske = 5'h10;	// 128 MB MCUBE
		default   : szmaske = 5'h00;	// 256 MB NetBSD
		endcase
 
	assign filter   = ((ADDR[27:23] & szmaske) == 5'd0);
	assign sel_dram =  (ADDR[31:28] == 4'd0) & filter & 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
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//	7. FILTCMP		Address Filter and Comparator
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
module FILTCMP ( DRAMSZ, RADR, DRAM_A, ADR_EQU, TAGDAT );
 
	input	 [2:0]	DRAMSZ;
	input	[27:4]	RADR,DRAM_A;
 
	output			ADR_EQU;
	output reg	[27:12]	TAGDAT;
 
	reg	   [27:23]	adram;
 
	always @(DRAMSZ or RADR)
		casex (DRAMSZ)
		  3'b00x : TAGDAT = {5'd0,RADR[22:12]};	//   8 MB
		  3'bx10 : TAGDAT = {3'd0,RADR[24:12]};	//  32 MB
		  3'bx11 : TAGDAT = {2'd0,RADR[25:12]};	//  64 MB
		  3'b100 : TAGDAT = {1'd0,RADR[26:12]};	// 128 MB
		  3'b101 : TAGDAT =       RADR[27:12] ;	// 256 MB
		endcase
 
	always @(DRAMSZ or DRAM_A)	// The address comparator is only used in the data cache.
		casex (DRAMSZ)
		  3'b00x : adram =  5'd0;					//   8 MB
		  3'bx10 : adram = {3'd0,DRAM_A[24:23]};	//  32 MB
		  3'bx11 : adram = {2'd0,DRAM_A[25:23]};	//  64 MB
		  3'b100 : adram = {1'd0,DRAM_A[26:23]};	// 128 MB
		  3'b101 : adram =       DRAM_A[27:23] ;	// 256 MB
		endcase
 
	assign ADR_EQU = {TAGDAT,RADR[11:4]} == {adram,DRAM_A[22:4]};
 
endmodule
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//	8. DCACHE_SM	Data cache state machine
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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  [27: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	[27: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		 [2:0]	cap_dat;	// only for analyse of timing
	reg				mem_done;
	reg				rd_done;
	reg		 [2:0]	pstate;
	reg				pte_run_wr;
	reg		 [1:0]	prot_level1;
	reg				card_flag;
	reg	   [27:12]	ptb0,ptb1;
	reg				write_ok;
	reg				icp_acc;
	reg				pte_modi;
	reg		 [2:0]	ko_state;
	reg				dma_run;
	reg				dma_kdet;
	reg				rwv_bit;
	reg				prot_i;
	reg				rd_rdy;
 
	wire   [27: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;
 
	always @(posedge BCLK) cap_dat <= CAPDAT[2:0];
 
	// 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 ? ~(cap_dat[2] & (~RWVAL[0] | cap_dat[1])) : 1'b1;
 
	assign RWVFLAG = VIRTUELL & rwv_bit;
 
	assign zt_ok = mem_done & (RWVAL[1] ? (~cap_dat[2] | (RWVAL[0] & ~cap_dat[1]) | level2)	// Level 2 always ok
										: (cap_dat[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]) ? (cap_dat[2] & (cap_dat[1] | ~RWVAL[0]) & cap_dat[0] & level1)
									  : (cap_dat[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]) ? (cap_dat[2] & (cap_dat[1] | ~RWVAL[0]) & ~cap_dat[0] & level1)
										: ~cap_dat[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 & ~cap_dat[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[27:12];
	always @(posedge BCLK) if (PTB_WR &&  PTB_SEL) ptb1 <= CPU_OUT[27:12];
 
	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[27: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];
	always @(posedge BCLK) pte_modi = pte_dat_8;
	assign PTE_DAT = {4'h3,CAPDAT[15:9],pte_modi,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 <= cap_dat[2:1];
 
	always @(prot_level1 or cap_dat)	
		casex ({prot_level1,cap_dat[2]})
		  3'b11_x : pl_dat = cap_dat[2:1];
		  3'b10_1 : pl_dat = 2'b10;
		  3'b10_0 : pl_dat = cap_dat[2:1];
		  3'b01_1 : pl_dat = 2'b01;
		  3'b01_0 : pl_dat = cap_dat[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 : cap_dat[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
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.