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

Subversion Repositories thor

[/] [thor/] [trunk/] [FT64v7/] [rtl/] [common/] [FT64_ICController.v] - Rev 66

Compare with Previous | Blame | View Log

// ============================================================================
//        __
//   \\__/ o\    (C) 2017-2019  Robert Finch, Waterloo
//    \  __ /    All rights reserved.
//     \/_//     robfinch<remove>@finitron.ca
//       ||
//
//	FT64_ICController.v
//
// 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 3 of the License, or     
// (at your option) any later version.                                      
//                                                                          
// This source file 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 General Public License for more details.                             
//                                                                          
// You should have received a copy of the GNU General Public License        
// along with this program.  If not, see <http://www.gnu.org/licenses/>.    
//
// ============================================================================
//
`include ".\FT64_config.vh"
`define HIGH	1'b1
`define LOW		1'b0;
 
module FT64_ICController(clk_i, asid, pc0, pc1, pc2, hit0, hit1, hit2, bstate, state,
	invline, invlineAddr,
	thread_en, ihitL2, selL2, L2_ld, L2_cnt, L2_adr, L2_dato, L2_nxt,
	L1_selpc, L1_adr, L1_dat, L1_wr0, L1_wr1, L1_wr2, L1_en, L1_invline, icnxt, icwhich,
	icl_o, cti_o, bte_o, bok_i, cyc_o, stb_o, ack_i, err_i, tlbmiss_i, exv_i, sel_o, adr_o, dat_i);
parameter ABW = 64;
parameter AMSB = ABW-1;
parameter RSTPC = 64'hFFFFFFFFFFFC0100;
input clk_i;
input [7:0] asid;
input [AMSB:0] pc0;
input [AMSB:0] pc1;
input [AMSB:0] pc2;
input hit0;
input hit1;
input hit2;
input [4:0] bstate;
(* mark_debug="true" *)
output reg [3:0] state = IDLE;
input invline;
input [71:0] invlineAddr;
input thread_en;
input ihitL2;
output reg selL2 = 1'b0;
output reg L2_ld;
output [2:0] L2_cnt;
output reg [71:0] L2_adr = RSTPC;
input [305:0] L2_dato;
output reg L2_nxt;
output L1_selpc;
output reg [71:0] L1_adr = RSTPC;
output reg [305:0] L1_dat = {2'b0,{38{8'h3D}}};	// NOP
output reg L1_wr0;
output reg L1_wr1;
output reg L1_wr2;
output reg [9:0] L1_en;
output reg L1_invline;
output reg icnxt;
output reg [1:0] icwhich;
output reg icl_o;
output reg [2:0] cti_o = 3'b000;
output reg [1:0] bte_o = 2'b00;
input bok_i;
output reg cyc_o = 1'b0;
output reg stb_o;
input ack_i;
input err_i;
input tlbmiss_i;
input exv_i;
output reg [7:0] sel_o;
output reg [71:0] adr_o;
input [63:0] dat_i;
 
parameter TRUE = 1'b1;
parameter FALSE = 1'b0;
 
reg [3:0] picstate;
`include ".\FT64_busStates.vh"
reg invline_r = 1'b0;
reg [71:0] invlineAddr_r = 72'd0;
 
wire [AMSB:0] pc0plus6 = pc0 + 8'd7;
wire [AMSB:0] pc0plus12 = pc0 + 8'd14;
 
//assign L2_ld = (state==IC_Ack) && (ack_i|err_i|tlbmiss_i|exv_i);
assign L1_selpc = (state==IDLE||state==IC_Next) && !invline_r;
 
wire clk = clk_i;
reg [2:0] iccnt;
assign L2_cnt = iccnt;
 
//BUFH uclkb (.I(clk_i), .O(clk));
 
always @(posedge clk)
begin
L1_wr0 <= FALSE;
L1_wr1 <= FALSE;
L1_wr2 <= FALSE;
L1_en <= 10'h000;
L1_invline <= FALSE;
icnxt <= FALSE;
L2_nxt <= FALSE;
if (invline) begin
	invline_r <= 1'b1;
	invlineAddr_r <= invlineAddr;
end
 
// Instruction cache state machine.
// On a miss first see if the instruction is in the L2 cache. No need to go to
// the BIU on an L1 miss.
// If not the machine will wait until the BIU loads the L2 cache.
 
// Capture the previous ic state, used to determine how long to wait in
// icstate #4.
picstate <= state;
case(state)
IDLE:
	begin
		iccnt <= 3'd0;
		if (invline_r) begin
			L1_adr <= {invlineAddr_r[71:5],5'b0};
			L1_invline <= TRUE;
			invline_r <= 1'b0;
		end
		// If the bus unit is busy doing an update involving L1_adr or L2_adr
		// we have to wait.
		else begin
			if (!hit0) begin
				L1_adr <= {asid,pc0[AMSB:5],5'h0};
				L1_invline <= TRUE;
				icwhich <= 2'b00;
				state <= IC2;
			end
			else if (!hit1 && `WAYS > 1) begin
				if (thread_en) begin
					L1_adr <= {asid,pc1[AMSB:5],5'h0};
				end
				else begin
					L1_adr <= {asid,pc0plus6[AMSB:5],5'h0};
				end
				L1_invline <= TRUE;
				icwhich <= 2'b01;
				state <= IC2;
			end
			else if (!hit2 && `WAYS > 2) begin
				if (thread_en) begin
					L1_adr <= {asid,pc2[AMSB:5],5'h0};
				end
				else begin
					L1_adr <= {asid,pc0plus12[AMSB:5],5'h0};
				end
				L1_invline <= TRUE;
				icwhich <= 2'b10;
				state <= IC2;
			end
		end
	end
 
IC2:     state <= IC3;
IC3:     state <= IC3a;
IC3a:     state <= IC_WaitL2;
// If data was in the L2 cache already there's no need to wait on the
// BIU to retrieve data. It can be determined if the hit signal was
// already active when this state was entered in which case waiting
// will do no good.
// The IC machine will stall in this state until the BIU has loaded the
// L2 cache. 
IC_WaitL2: 
	if (ihitL2 && picstate==IC3a) begin
		L1_en <= 10'h3FF;
		L1_wr0 <= TRUE;
		L1_wr1 <= TRUE && `WAYS > 1;
		L1_wr2 <= TRUE && `WAYS > 2;
//		L1_adr <= L2_adr;
		// L1_dati is loaded dring an L2 icache load operation
//		if (picstate==IC3a)
		L1_dat <= L2_dato;
		state <= IC5;
	end
	else begin
		if (bstate == B_WaitIC)
			state <= IC_Access;
	end
/*
	else if (state!=IC_Nack)
		;
	else begin
		L1_en <= 10'h3FF;
		L1_wr0 <= TRUE;
		L1_wr1 <= TRUE && `WAYS > 1;
		L1_wr2 <= TRUE && `WAYS > 2;
//		L1_adr <= L2_adr;
		// L1_dati set below while loading cache line
		//L1_dati <= L2_dato;
		state <= IC5;
	end
*/
IC5: 	state <= IC6;
IC6:  state <= IC7;
IC7:	state <= IC_Next;
IC_Next:
  begin
   state <= IDLE;
   icnxt <= TRUE;
	end
IC_Access:
	begin
		iccnt <= 3'd0;
		icl_o <= `HIGH;
		cti_o <= 3'b001;
		bte_o <= 2'b00;
		cyc_o <= `HIGH;
		stb_o <= `HIGH;
		sel_o <= 8'hFF;
		adr_o <= {L1_adr[AMSB:5],5'b0};
		L2_adr <= L1_adr;
		L2_adr[4:0] <= 5'd0;
		selL2 <= TRUE;
		L2_ld <= TRUE;
		state <= IC_Ack;
	end
IC_Ack:
  if (ack_i|err_i|tlbmiss_i|exv_i) begin
  	L2_ld <= TRUE;
  	if (!bok_i) begin
  		stb_o <= `LOW;
			adr_o[AMSB:3] <= adr_o[AMSB:3] + 2'd1;
  		state <= IC_Nack2;
  	end
		if (tlbmiss_i) begin
			L1_dat[305:304] <= 2'd1;
			L1_dat[303:0] <= {38{8'h3D}};	// NOP
			nack();
	  end
		else if (exv_i) begin
			L1_dat[305:304] <= 2'd2;
			L1_dat[303:0] <= {38{8'h3D}};	// NOP
			nack();
		end
	  else if (err_i) begin
			L1_dat[305:304] <= 2'd3;
			L1_dat[303:0] <= {38{8'h3D}};	// NOP
			nack();
	  end
	  else
	  	case(iccnt)
	  	3'd0:	L1_dat[63:0] <= dat_i;
	  	3'd1:	L1_dat[127:64] <= dat_i;
	  	3'd2:	L1_dat[191:128] <= dat_i;
	  	3'd3:	L1_dat[255:192] <= dat_i;
	  	3'd4:	L1_dat[305:256] <= {2'b00,dat_i[47:0]};
	  	default:	L1_dat <= L1_dat;
	  	endcase
    iccnt <= iccnt + 3'd1;
    if (iccnt==3'd3)
      cti_o <= 3'b111;
    if (iccnt>=3'd4)
    	nack();
  end
IC_Nack2:
	if (~ack_i) begin
		stb_o <= `HIGH;
		state <= IC_Ack;
	end
IC_Nack:
 	begin
    iccnt <= iccnt + 3'd1;
		L2_ld <= FALSE;
		selL2 <= FALSE;
		if (~ack_i) begin
			//icl_ctr <= icl_ctr + 40'd1;
			state <= IDLE;
			L2_nxt <= TRUE;
		end
	end
default:
	begin
   	state <= IDLE;
  end
endcase
end
 
task nack;
begin
	icl_o <= `LOW;
	cti_o <= 3'b000;
	cyc_o <= `LOW;
	stb_o <= `LOW;
	L1_en <= 10'h3FF;
	L1_wr0 <= TRUE;
	L1_wr1 <= TRUE && `WAYS > 1;
	L1_wr2 <= TRUE && `WAYS > 2;
	state <= IC_Nack;
end
endtask
 
endmodule
 

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.