Permalink
Browse files

initial ITLB implemenation

This patch adds the instruction translation lookaside buffer.

Miss exceptions are delayed until the X stage and if the instruction is
still qualified (eg. not killed and still valid) the exception is taken.

Signed-off-by: Michael Walle <michael@walle.cc>
Signed-off-by: Yann Sionneau <yann.sionneau@gmail.com>
  • Loading branch information...
1 parent 22737d8 commit 63e18e50053c9f65fd4e1c7ff4bac1b900046d9a @mwalle mwalle committed Dec 12, 2012
Showing with 469 additions and 4 deletions.
  1. +57 −1 rtl/lm32_cpu.v
  2. +42 −2 rtl/lm32_icache.v
  3. +2 −1 rtl/lm32_include.v
  4. +89 −0 rtl/lm32_instruction_unit.v
  5. +278 −0 rtl/lm32_itlb.v
  6. +1 −0 test/Makefile
View
58 rtl/lm32_cpu.v
@@ -816,7 +816,10 @@ reg [`LM32_WORD_RNG] tlbvaddr; // TLBVADDR CSR
reg [`LM32_WORD_RNG] tlbbadvaddr; // TLBBADVADDR CSR
wire [`LM32_WORD_RNG] dtlb_miss_vfn; // VFN of the missed address
wire [`LM32_WORD_RNG] itlb_miss_vfn; // VFN of the missed instruction
+wire itlb_miss_x; // Indicates if an ITLB miss has occured in the X stage
+wire itlb_stall_request; // Stall pipeline because instruction TLB is busy
+wire itlb_miss_exception; // Indicates if an ITLB miss exception has occured
wire itlb_exception; // Indicates if an ITLB exception has occured
wire dtlb_exception; // Indicates if a DTLB exception has occured
`endif
@@ -877,6 +880,14 @@ lm32_instruction_unit #(
.dcache_refill_request (dcache_refill_request),
.dcache_refilling (dcache_refilling),
`endif
+`ifdef CFG_MMU_ENABLED
+ .itlb_enable (itlbe),
+ .tlbpaddr (tlbpaddr),
+ .tlbvaddr (tlbvaddr),
+ .itlb_update (itlb_update),
+ .itlb_flush (itlb_flush),
+ .itlb_invalidate (itlb_invalidate),
+`endif
`ifdef CFG_IWB_ENABLED
// From Wishbone
.i_dat_i (I_DAT_I),
@@ -905,6 +916,11 @@ lm32_instruction_unit #(
`ifdef CFG_IROM_ENABLED
.irom_data_m (irom_data_m),
`endif
+`ifdef CFG_MMU_ENABLED
+ .itlb_stall_request (itlb_stall_request),
+ .itlb_miss_vfn (itlb_miss_vfn),
+ .itlb_miss_x (itlb_miss_x),
+`endif
`ifdef CFG_IWB_ENABLED
// To Wishbone
.i_dat_o (I_DAT_O),
@@ -1707,6 +1723,9 @@ assign kill_f = ( (valid_d == `TRUE)
`ifdef CFG_DCACHE_ENABLED
|| (dcache_refill_request == `TRUE)
`endif
+`ifdef CFG_MMU_ENABLED
+ || (itlb_miss_exception == `TRUE)
+`endif
;
assign kill_d = (branch_taken_m == `TRUE)
`ifdef CFG_FAST_UNCONDITIONAL_BRANCH
@@ -1718,6 +1737,9 @@ assign kill_d = (branch_taken_m == `TRUE)
`ifdef CFG_DCACHE_ENABLED
|| (dcache_refill_request == `TRUE)
`endif
+`ifdef CFG_MMU_ENABLED
+ || (itlb_miss_exception == `TRUE)
+`endif
;
assign kill_x = (branch_flushX_m == `TRUE)
`ifdef CFG_DCACHE_ENABLED
@@ -1773,6 +1795,14 @@ assign system_call_exception = ( (scall_x == `TRUE)
`endif
);
+`ifdef CFG_MMU_ENABLED
+assign itlb_miss_exception = ( (itlb_miss_x == `TRUE)
+ && (itlbe == `TRUE)
+ && (valid_x == `TRUE)
+ );
+assign itlb_exception = (itlb_miss_exception == `TRUE);
+`endif
+
`ifdef CFG_DEBUG_ENABLED
assign debug_exception_x = (breakpoint_exception == `TRUE)
|| (watchpoint_exception == `TRUE)
@@ -1800,6 +1830,9 @@ assign non_debug_exception_x = (system_call_exception == `TRUE)
`endif
)
`endif
+`ifdef CFG_MMU_ENABLED
+ || (itlb_exception == `TRUE)
+`endif
;
assign exception_x = (debug_exception_x == `TRUE) || (non_debug_exception_x == `TRUE);
@@ -1823,6 +1856,9 @@ assign exception_x = (system_call_exception == `TRUE)
`endif
)
`endif
+`ifdef CFG_MMU_ENABLED
+ || (itlb_exception == `TRUE)
+`endif
;
`endif
@@ -1871,14 +1907,31 @@ begin
eid_x = `LM32_EID_INTERRUPT;
else
`endif
+`ifdef CFG_MMU_ENABLED
+ if (itlb_miss_exception == `TRUE)
+ eid_x = `LM32_EID_ITLB_MISS;
+ else
+`endif
eid_x = `LM32_EID_SCALL;
end
// Stall generation
assign stall_a = (stall_f == `TRUE);
-assign stall_f = (stall_d == `TRUE);
+assign stall_f = (stall_d == `TRUE)
+`ifdef CFG_MMU_ENABLED
+ // We need to stall for one cycle. Otherwise the icache
+ // starts one cycle earlier and the restart address will be
+ // wrong in case of a miss, that is one instruction is
+ // skipped.
+ || ( (itlbe == `TRUE)
+ && ( (debug_exception_q_w == `TRUE)
+ || (non_debug_exception_q_w == `TRUE)
+ )
+ )
+`endif
+ ;
assign stall_d = (stall_x == `TRUE)
|| ( (interlock == `TRUE)
@@ -1976,6 +2029,9 @@ assign stall_m = (stall_wb_load == `TRUE)
&& (user_complete == `FALSE)
)
`endif
+`ifdef CFG_MMU_ENABLED
+ || (itlb_stall_request == `TRUE) // ITLB is busy
+`endif
;
// Qualify state changing control signals
View
44 rtl/lm32_icache.v
@@ -91,6 +91,9 @@ module lm32_icache (
stall_f,
address_a,
address_f,
+`ifdef CFG_MMU_ENABLED
+ physical_address_f,
+`endif
read_enable_f,
refill_ready,
refill_data,
@@ -105,6 +108,9 @@ module lm32_icache (
restart_request,
refill_request,
refill_address,
+`ifdef CFG_MMU_ENABLED
+ physical_refill_address,
+`endif
refilling,
inst
);
@@ -125,7 +131,11 @@ localparam addr_offset_lsb = 2;
localparam addr_offset_msb = (addr_offset_lsb+addr_offset_width-1);
localparam addr_set_lsb = (addr_offset_msb+1);
localparam addr_set_msb = (addr_set_lsb+addr_set_width-1);
+`ifdef CFG_MMU_ENABLED
+localparam addr_tag_lsb = (addr_offset_msb+1);
+`else
localparam addr_tag_lsb = (addr_set_msb+1);
+`endif
localparam addr_tag_msb = `CLOG2(`CFG_ICACHE_LIMIT-`CFG_ICACHE_BASE_ADDRESS);
localparam addr_tag_width = (addr_tag_msb-addr_tag_lsb+1);
@@ -144,6 +154,9 @@ input branch_predict_taken_d; // Instruction in D stage is
input [`LM32_PC_RNG] address_a; // Address of instruction in A stage
input [`LM32_PC_RNG] address_f; // Address of instruction in F stage
+`ifdef CFG_MMU_ENABLED
+input [`LM32_PC_RNG] physical_address_f; // Physical address of instruction in F stage
+`endif
input read_enable_f; // Indicates if cache access is valid
input refill_ready; // Next word of refill data is ready
@@ -166,6 +179,10 @@ output refill_request; // Request to refill a cache
wire refill_request;
output [`LM32_PC_RNG] refill_address; // Base address of cache refill
reg [`LM32_PC_RNG] refill_address;
+`ifdef CFG_MMU_ENABLED
+output [`LM32_PC_RNG] physical_refill_address; // Physical base address of cache refill
+reg [`LM32_PC_RNG] physical_refill_address;
+`endif
output refilling; // Indicates the instruction cache is currently refilling
reg refilling;
output [`LM32_INSTRUCTION_RNG] inst; // Instruction read from cache
@@ -270,7 +287,12 @@ endgenerate
generate
for (i = 0; i < associativity; i = i + 1)
begin : match
-assign way_match[i] = ({way_tag[i], way_valid[i]} == {address_f[`LM32_IC_ADDR_TAG_RNG], `TRUE});
+assign way_match[i] =
+`ifdef CFG_MMU_ENABLED
+ ({way_tag[i], way_valid[i]} == {physical_address_f[`LM32_IC_ADDR_TAG_RNG], `TRUE});
+`else
+ ({way_tag[i], way_valid[i]} == {address_f[`LM32_IC_ADDR_TAG_RNG], `TRUE});
+`endif
end
endgenerate
@@ -328,7 +350,12 @@ endgenerate
// On the last refill cycle set the valid bit, for all other writes it should be cleared
assign tmem_write_data[`LM32_IC_TAGS_VALID_RNG] = last_refill & !flushing;
-assign tmem_write_data[`LM32_IC_TAGS_TAG_RNG] = refill_address[`LM32_IC_ADDR_TAG_RNG];
+assign tmem_write_data[`LM32_IC_TAGS_TAG_RNG] =
+`ifdef CFG_MMU_ENABLED
+ physical_refill_address[`LM32_IC_ADDR_TAG_RNG];
+`else
+ refill_address[`LM32_IC_ADDR_TAG_RNG];
+`endif
// Signals that indicate which state we are in
assign flushing = |state[1:0];
@@ -377,6 +404,9 @@ begin
state <= `LM32_IC_STATE_FLUSH_INIT;
flush_set <= {`LM32_IC_TMEM_ADDR_WIDTH{1'b1}};
refill_address <= {`LM32_PC_WIDTH{1'bx}};
+`ifdef CFG_MMU_ENABLED
+ physical_refill_address <= {`LM32_PC_WIDTH{1'bx}};
+`endif
restart_request <= `FALSE;
end
else
@@ -412,12 +442,22 @@ begin
restart_request <= `FALSE;
if (iflush == `TRUE)
begin
+`ifdef CFG_MMU_ENABLED
+ physical_refill_address <= physical_address_f;
+ refill_address <= address_f;
+`else
refill_address <= address_f;
+`endif
state <= `LM32_IC_STATE_FLUSH;
end
else if (miss == `TRUE)
begin
+`ifdef CFG_MMU_ENABLED
+ physical_refill_address <= physical_address_f;
+ refill_address <= address_f;
+`else
refill_address <= address_f;
+`endif
state <= `LM32_IC_STATE_REFILL;
end
end
View
3 rtl/lm32_include.v
@@ -263,7 +263,7 @@
`define LM32_TLB_OP_INVALIDATE 2'h2
// Exception IDs
-`define LM32_EID_WIDTH 3
+`define LM32_EID_WIDTH 4
`define LM32_EID_RNG (`LM32_EID_WIDTH-1):0
`define LM32_EID_RESET `LM32_EID_WIDTH'h0
`define LM32_EID_BREAKPOINT `LM32_EID_WIDTH'h1
@@ -273,6 +273,7 @@
`define LM32_EID_DIVIDE_BY_ZERO `LM32_EID_WIDTH'h5
`define LM32_EID_INTERRUPT `LM32_EID_WIDTH'h6
`define LM32_EID_SCALL `LM32_EID_WIDTH'h7
+`define LM32_EID_ITLB_MISS `LM32_EID_WIDTH'h8
// Exception Base Address
`define LM32_EBA_WIDTH (`LM32_PC_WIDTH-`LM32_EID_WIDTH-3)
View
89 rtl/lm32_instruction_unit.v
@@ -115,6 +115,14 @@ module lm32_instruction_unit (
irom_address_xm,
irom_we_xm,
`endif
+`ifdef CFG_MMU_ENABLED
+ itlb_enable,
+ tlbpaddr,
+ tlbvaddr,
+ itlb_update,
+ itlb_flush,
+ itlb_invalidate,
+`endif
`ifdef CFG_IWB_ENABLED
// From Wishbone
i_dat_i,
@@ -143,6 +151,11 @@ module lm32_instruction_unit (
`ifdef CFG_IROM_ENABLED
irom_data_m,
`endif
+`ifdef CFG_MMU_ENABLED
+ itlb_stall_request,
+ itlb_miss_vfn,
+ itlb_miss_x,
+`endif
`ifdef CFG_IWB_ENABLED
// To Wishbone
i_dat_o,
@@ -232,6 +245,15 @@ input [`LM32_WORD_RNG] irom_address_xm; // Address from load-sto
input irom_we_xm; // Indicates if memory operation is load or store
`endif
+`ifdef CFG_MMU_ENABLED
+input itlb_enable; // Instruction TLB enable
+input [`LM32_WORD_RNG] tlbpaddr; // TLBPADDR CSR
+input [`LM32_WORD_RNG] tlbvaddr; // TLBVADDR CSR
+input itlb_update; // Instruction TLB update request
+input itlb_flush; // Instruction TLB flush request
+input itlb_invalidate; // Instruction TLB invalidate request
+`endif
+
`ifdef CFG_IWB_ENABLED
input [`LM32_WORD_RNG] i_dat_i; // Instruction Wishbone interface read data
input i_ack_i; // Instruction Wishbone interface acknowledgement
@@ -276,6 +298,15 @@ output [`LM32_WORD_RNG] irom_data_m; // Data to load-store un
wire [`LM32_WORD_RNG] irom_data_m;
`endif
+`ifdef CFG_MMU_ENABLED
+output itlb_stall_request; // Instruction TLB stall request
+wire itlb_stall_request;
+output [`LM32_WORD_RNG] itlb_miss_vfn; // Virtual frame number of missed instruction
+wire [`LM32_WORD_RNG] itlb_miss_vfn;
+output itlb_miss_x; // Indicates if an instruction TLB miss occured in X stage
+wire itlb_miss_x;
+`endif
+
`ifdef CFG_IWB_ENABLED
output [`LM32_WORD_RNG] i_dat_o; // Instruction Wishbone interface write data
`ifdef CFG_HW_DEBUG_ENABLED
@@ -340,6 +371,9 @@ reg [`LM32_PC_RNG] restart_address; // Address to restart fr
`ifdef CFG_ICACHE_ENABLED
wire icache_read_enable_f; // Indicates if instruction cache miss is valid
wire [`LM32_PC_RNG] icache_refill_address; // Address that caused cache miss
+`ifdef CFG_MMU_ENABLED
+wire [`LM32_PC_RNG] icache_physical_refill_address; // Physical address that caused cache miss
+`endif
reg icache_refill_ready; // Indicates when next word of refill data is ready to be written to cache
reg [`LM32_INSTRUCTION_RNG] icache_refill_data; // Next word of refill data, fetched from Wishbone
wire [`LM32_INSTRUCTION_RNG] icache_data_f; // Instruction fetched from instruction cache
@@ -373,6 +407,11 @@ reg jtag_access; // Indicates if a JTAG W
reg alternate_eba_taken;
`endif
+`ifdef CFG_MMU_ENABLED
+wire [`LM32_PC_RNG] physical_pc_f; // F stage physical PC
+wire itlb_miss_f; // Indicates if an instruction TLB miss occured in F stage
+`endif
+
/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////
@@ -448,6 +487,9 @@ lm32_icache #(
.valid_d (valid_d),
.address_a (pc_a),
.address_f (pc_f),
+`ifdef CFG_MMU_ENABLED
+ .physical_address_f (physical_pc_f),
+`endif
.read_enable_f (icache_read_enable_f),
.refill_ready (icache_refill_ready),
.refill_data (icache_refill_data),
@@ -457,11 +499,43 @@ lm32_icache #(
.restart_request (icache_restart_request),
.refill_request (icache_refill_request),
.refill_address (icache_refill_address),
+`ifdef CFG_MMU_ENABLED
+ .physical_refill_address(icache_physical_refill_address),
+`endif
.refilling (icache_refilling),
.inst (icache_data_f)
);
`endif
+`ifdef CFG_MMU_ENABLED
+// Instruction TLB
+lm32_itlb itlb (
+ // ----- Inputs -----
+ .clk_i (clk_i),
+ .rst_i (rst_i),
+ .enable (itlb_enable),
+ .stall_a (stall_a),
+ .stall_f (stall_f),
+ .stall_d (stall_d),
+ .stall_x (stall_x),
+ .pc_a (pc_a),
+ .pc_f (pc_f),
+ .pc_x (pc_x),
+ .read_enable_f (icache_read_enable_f),
+ .tlbpaddr (tlbpaddr),
+ .tlbvaddr (tlbvaddr),
+ .update (itlb_update),
+ .flush (itlb_flush),
+ .invalidate (itlb_invalidate),
+ // ----- Outputs -----
+ .physical_pc_f (physical_pc_f),
+ .stall_request (itlb_stall_request),
+ .miss_vfn (itlb_miss_vfn),
+ .miss_f (itlb_miss_f),
+ .miss_x (itlb_miss_x)
+ );
+`endif
+
/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////
@@ -476,6 +550,9 @@ assign icache_read_enable_f = (valid_f == `TRUE)
`ifdef CFG_IROM_ENABLED
&& (irom_select_f == `FALSE)
`endif
+`ifdef CFG_MMU_ENABLED
+ && (itlb_miss_f == `FALSE)
+`endif
;
`endif
@@ -553,21 +630,33 @@ generate
assign first_cycle_type = `LM32_CTYPE_END;
assign next_cycle_type = `LM32_CTYPE_END;
assign last_word = `TRUE;
+`ifdef CFG_MMU_ENABLED
+assign first_address = icache_physical_refill_address;
+`else
assign first_address = icache_refill_address;
+`endif
end
8:
begin
assign first_cycle_type = `LM32_CTYPE_INCREMENTING;
assign next_cycle_type = `LM32_CTYPE_END;
assign last_word = i_adr_o[addr_offset_msb:addr_offset_lsb] == 1'b1;
+`ifdef CFG_MMU_ENABLED
+assign first_address = {icache_physical_refill_address[`LM32_PC_WIDTH+2-1:addr_offset_msb+1], {addr_offset_width{1'b0}}};
+`else
assign first_address = {icache_refill_address[`LM32_PC_WIDTH+2-1:addr_offset_msb+1], {addr_offset_width{1'b0}}};
+`endif
end
default:
begin
assign first_cycle_type = `LM32_CTYPE_INCREMENTING;
assign next_cycle_type = i_adr_o[addr_offset_msb:addr_offset_lsb+1] == {addr_offset_width-1{1'b1}} ? `LM32_CTYPE_END : `LM32_CTYPE_INCREMENTING;
assign last_word = (&i_adr_o[addr_offset_msb:addr_offset_lsb]) == 1'b1;
+`ifdef CFG_MMU_ENABLED
+assign first_address = {icache_physical_refill_address[`LM32_PC_WIDTH+2-1:addr_offset_msb+1], {addr_offset_width{1'b0}}};
+`else
assign first_address = {icache_refill_address[`LM32_PC_WIDTH+2-1:addr_offset_msb+1], {addr_offset_width{1'b0}}};
+`endif
end
endcase
endgenerate
View
278 rtl/lm32_itlb.v
@@ -0,0 +1,278 @@
+/*
+ * LatticeMico32
+ * Instruction Translation Lookaside Buffer
+ *
+ * Copyright (c) 2011-2012 Yann Sionneau <yann.sionneau@gmail.com>
+ * Copyright (c) 2012 Michael Walle <michael@walle.cc>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+`include "lm32_include.v"
+
+`ifdef CFG_MMU_ENABLED
+`define LM32_ITLB_CTRL_FLUSH 5'h1
+`define LM32_ITLB_CTRL_UPDATE 5'h2
+`define LM32_TLB_CTRL_INVALIDATE_ENTRY 5'h10
+
+`define LM32_ITLB_STATE_RNG 1:0
+`define LM32_ITLB_STATE_CHECK 2'b01
+`define LM32_ITLB_STATE_FLUSH 2'b10
+
+`define LM32_ITLB_OFFSET_RNG offset_msb:offset_lsb
+`define LM32_ITLB_IDX_RNG index_msb:index_lsb
+`define LM32_ITLB_VPFN_RNG vpfn_msb:vpfn_lsb
+`define LM32_ITLB_TAG_RNG tag_msb:tag_lsb
+`define LM32_ITLB_ADDR_RNG (index_width-1):0
+`define LM32_ITLB_DATA_WIDTH (vpfn_width+tag_width+1)
+`define LM32_ITLB_DATA_RNG (`LM32_ITLB_DATA_WIDTH-1):0
+
+
+/////////////////////////////////////////////////////
+// Module interface
+/////////////////////////////////////////////////////
+module lm32_itlb (
+ // ----- Inputs -------
+ clk_i,
+ rst_i,
+ enable,
+ stall_a,
+ stall_f,
+ stall_d,
+ stall_x,
+ pc_a,
+ pc_f,
+ pc_x,
+ read_enable_f,
+ tlbpaddr,
+ tlbvaddr,
+ update,
+ flush,
+ invalidate,
+ // ----- Outputs -------
+ physical_pc_f,
+ stall_request,
+ miss_vfn,
+ miss_f,
+ miss_x
+ );
+
+/////////////////////////////////////////////////////
+// Parameters
+/////////////////////////////////////////////////////
+
+parameter entries = 1024; // Number of entires in ITLB
+parameter page_size = 4096; // ITLB page size
+
+localparam offset_width = (`CLOG2(page_size)-2);
+localparam index_width = `CLOG2(entries);
+localparam offset_lsb = 2;
+localparam offset_msb = (offset_lsb+offset_width-1);
+localparam index_lsb = (offset_msb+1);
+localparam index_msb = (index_lsb+index_width-1);
+localparam tag_lsb = (index_msb+1);
+localparam tag_msb = (`LM32_WORD_WIDTH-1);
+localparam tag_width = (tag_msb-tag_lsb+1);
+localparam vpfn_lsb = (offset_msb+1);
+localparam vpfn_msb = (`LM32_WORD_WIDTH-1);
+localparam vpfn_width = (vpfn_msb-vpfn_lsb+1);
+
+/////////////////////////////////////////////////////
+// Inputs
+/////////////////////////////////////////////////////
+
+input clk_i; // Clock
+input rst_i; // Reset
+
+input enable; // Instruction TLB enable
+input stall_a; // Stall instruction in A stage
+input stall_f; // Stall instruction in F stage
+input stall_d; // Stall instruction in D stage
+input stall_x; // Stall instruction in X stage
+
+input [`LM32_PC_RNG] pc_a; // Address of instruction in A stage
+input [`LM32_PC_RNG] pc_f; // Address of instruction in F stage
+input [`LM32_PC_RNG] pc_x; // Address of instruction in X stage
+
+input read_enable_f; // Indicates if cache access is valid
+
+input [`LM32_WORD_RNG] tlbpaddr;
+input [`LM32_WORD_RNG] tlbvaddr;
+input update;
+input flush;
+input invalidate;
+
+/////////////////////////////////////////////////////
+// Outputs
+/////////////////////////////////////////////////////
+output [`LM32_PC_RNG] physical_pc_f;
+reg [`LM32_PC_RNG] physical_pc_f;
+output stall_request;
+wire stall_request;
+output [`LM32_WORD_RNG] miss_vfn;
+wire [`LM32_WORD_RNG] miss_vfn;
+output miss_f;
+wire miss_f;
+output miss_x;
+reg miss_x;
+
+/////////////////////////////////////////////////////
+// Internal nets and registers
+/////////////////////////////////////////////////////
+
+wire [`LM32_ITLB_ADDR_RNG] read_address;
+wire [`LM32_ITLB_ADDR_RNG] write_address;
+wire read_port_enable;
+wire write_port_enable;
+wire [`LM32_ITLB_DATA_RNG] write_data;
+reg [`LM32_ITLB_STATE_RNG] state;
+reg [`LM32_ITLB_ADDR_RNG] flush_set;
+
+wire [`LM32_ITLB_TAG_RNG] tlbe_tag_f;
+wire [`LM32_ITLB_VPFN_RNG] tlbe_pfn_f;
+wire tlbe_valid_f;
+
+reg miss_d;
+
+/////////////////////////////////////////////////////
+// Functions
+/////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////
+// Instantiations
+/////////////////////////////////////////////////////
+
+lm32_ram
+ #(
+ // ----- Parameters -------
+ .data_width (`LM32_ITLB_DATA_WIDTH),
+ .address_width (index_width)
+// Modified for Milkymist: removed non-portable RAM parameters
+ ) data_ram
+ (
+ // ----- Inputs -------
+ .read_clk (clk_i),
+ .write_clk (clk_i),
+ .reset (rst_i),
+ .read_address (read_address),
+ .enable_read (read_port_enable),
+ .write_address (write_address),
+ .enable_write (`TRUE),
+ .write_enable (write_port_enable),
+ .write_data (write_data),
+ // ----- Outputs -------
+ .read_data ({tlbe_pfn_f, tlbe_tag_f, tlbe_valid_f})
+ );
+
+/////////////////////////////////////////////////////
+// Combinational logic
+/////////////////////////////////////////////////////
+
+// Compute address to use to index into the ITLB memory
+assign read_address = pc_a[`LM32_ITLB_IDX_RNG];
+assign write_address = (flushing == `TRUE) ? flush_set : tlbvaddr[`LM32_ITLB_IDX_RNG];
+
+assign read_port_enable = (stall_a == `FALSE);
+assign write_port_enable = (update == `TRUE) || (invalidate == `TRUE) || (flushing == `TRUE);
+
+assign write_data = ((invalidate == `TRUE) || (flushing == `TRUE))
+ ? {{`LM32_ITLB_DATA_WIDTH-1{1'b0}}, `FALSE}
+ : {tlbpaddr[`LM32_ITLB_VPFN_RNG], tlbvaddr[`LM32_ITLB_TAG_RNG], `TRUE};
+
+assign tlbe_match_f = ({tlbe_tag_f, tlbe_valid_f} == {pc_f[`LM32_ITLB_TAG_RNG], `TRUE});
+
+assign miss_vfn = {pc_x[`LM32_ITLB_VPFN_RNG], {offset_width{1'b0}}, 2'b0};
+assign miss_f = (enable == `TRUE) && (tlbe_match_f == `FALSE) && (stall_f == `FALSE);
+
+assign flushing = state[1];
+assign stall_request = (flushing == `TRUE);
+
+always @(*)
+begin
+ if (enable == `TRUE)
+ begin
+ if (tlbe_match_f == `TRUE)
+ physical_pc_f = {tlbe_pfn_f, pc_f[`LM32_ITLB_OFFSET_RNG]};
+ else
+ physical_pc_f = {`LM32_PC_WIDTH{1'b0}};
+ end
+ else
+ physical_pc_f = pc_f;
+end
+
+/////////////////////////////////////////////////////
+// Sequential logic
+/////////////////////////////////////////////////////
+
+always @(posedge clk_i `CFG_RESET_SENSITIVITY)
+begin
+ if (rst_i == `TRUE)
+ begin
+ miss_d <= `FALSE;
+ miss_x <= `FALSE;
+ end
+ else
+ begin
+ if (stall_d == `FALSE)
+ miss_d <= miss_f;
+ if (stall_x == `FALSE)
+ miss_x <= miss_d;
+ end
+end
+
+always @(posedge clk_i `CFG_RESET_SENSITIVITY)
+begin
+ if (rst_i == `TRUE)
+ begin
+ flush_set <= {index_width{1'b1}};
+ state <= `LM32_ITLB_STATE_FLUSH;
+ end
+ else
+ begin
+ case (state)
+
+ `LM32_ITLB_STATE_CHECK:
+ begin
+ if (flush == `TRUE)
+ begin
+ flush_set <= {index_width{1'b1}};
+ state <= `LM32_ITLB_STATE_FLUSH;
+ end
+ end
+
+ `LM32_ITLB_STATE_FLUSH:
+ begin
+ if (flush_set == {index_width{1'b0}})
+ state <= `LM32_ITLB_STATE_CHECK;
+ flush_set <= flush_set - 1'b1;
+ end
+
+ endcase
+ end
+end
+
+endmodule
+
+`endif
+
View
1 test/Makefile
@@ -20,6 +20,7 @@ SOURCES += $(RTL)/lm32_instruction_unit.v $(RTL)/lm32_interrupt.v
SOURCES += $(RTL)/lm32_jtag.v $(RTL)/lm32_load_store_unit.v
SOURCES += $(RTL)/lm32_logic_op.v $(RTL)/lm32_mc_arithmetic.v
SOURCES += $(RTL)/lm32_multiplier.v $(RTL)/lm32_ram.v $(RTL)/lm32_shifter.v
+SOURCES += $(RTL)/lm32_itlb.v
SOURCES += $(RTL)/lm32_top.v
all: tb_lm32_system

0 comments on commit 63e18e5

Please sign in to comment.