blob: abe174a97dde664d8546339d6eb7fdb42c000aae [file] [log] [blame]
/*
* LatticeMico32
* Data 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_DTLB_STATE_RNG 1:0
`define LM32_DTLB_STATE_CHECK 2'b01
`define LM32_DTLB_STATE_FLUSH 2'b10
`define LM32_DTLB_OFFSET_RNG offset_msb:offset_lsb
`define LM32_DTLB_IDX_RNG index_msb:index_lsb
`define LM32_DTLB_VPFN_RNG vpfn_msb:vpfn_lsb
`define LM32_DTLB_TAG_RNG tag_msb:tag_lsb
`define LM32_DTLB_ADDR_RNG (index_width-1):0
`define LM32_DTLB_DATA_WIDTH (vpfn_width+tag_width+3) // +3 for valid, ci, ro
`define LM32_DTLB_DATA_RNG (`LM32_DTLB_DATA_WIDTH-1):0
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_dtlb (
// ----- Inputs -------
clk_i,
rst_i,
enable,
stall_x,
stall_m,
address_x,
address_m,
load_d,
store_d,
load_q_x,
store_q_x,
load_q_m,
store_q_m,
tlbpaddr,
tlbvaddr,
update,
flush,
invalidate,
// ----- Outputs -----
physical_load_store_address_m,
stall_request,
miss_vfn,
miss_x,
fault_x,
cache_inhibit_x
);
/////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////
parameter entries = 1024; // Number of entries in DTLB
parameter page_size = 4096; // DTLB page size
localparam offset_width = `CLOG2(page_size);
localparam index_width = `CLOG2(entries);
localparam offset_lsb = 0;
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; // Data TLB enable
input stall_x; // Stall X stage
input stall_m; // Stall M stage
input [`LM32_WORD_RNG] address_x; // X stage load/store address
input [`LM32_WORD_RNG] address_m; // M stage load/store address
input load_d; // Load instruction in D stage
input store_d; // Store instruction in D stage
input load_q_x; // Load instruction in X stage
input store_q_x; // Store instruction in X stage
input load_q_m; // Load instruction in M stage
input store_q_m; // Store instruction in M stage
input [`LM32_WORD_RNG] tlbpaddr;
input [`LM32_WORD_RNG] tlbvaddr;
input update;
input flush;
input invalidate;
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output [`LM32_WORD_RNG] physical_load_store_address_m;
wire [`LM32_WORD_RNG] physical_load_store_address_m;
output stall_request;
wire stall_request;
output [`LM32_WORD_RNG] miss_vfn;
wire [`LM32_WORD_RNG] miss_vfn;
output miss_x;
wire miss_x;
output fault_x;
wire fault_x;
output cache_inhibit_x;
wire cache_inhibit_x;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
wire [`LM32_DTLB_ADDR_RNG] read_address;
wire [`LM32_DTLB_ADDR_RNG] write_address;
wire [`LM32_DTLB_DATA_RNG] write_data;
wire [`LM32_DTLB_DATA_RNG] tlbe;
wire [`LM32_DTLB_DATA_RNG] tlbe_inval;
wire [`LM32_DTLB_TAG_RNG] tlbe_tag_x;
wire [`LM32_DTLB_VPFN_RNG] tlbe_pfn_x;
wire tlbe_valid_x;
wire tlbe_ro_x;
wire tlbe_ci_x;
wire checking;
wire flushing;
wire write_port_enable;
reg [`LM32_DTLB_STATE_RNG] state; // Current state of FSM
reg [`LM32_DTLB_ADDR_RNG] flush_set;
reg [`LM32_DTLB_VPFN_RNG] tlbe_pfn_m;
reg lookup;
/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////
////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
lm32_ram
#(
// ----- Parameters -------
.data_width (`LM32_DTLB_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 (lookup),
.write_address (write_address),
.enable_write (`TRUE),
.write_enable (write_port_enable),
.write_data (write_data),
// ----- Outputs -------
.read_data ({tlbe_pfn_x, tlbe_tag_x, tlbe_ci_x, tlbe_ro_x, tlbe_valid_x})
);
/////////////////////////////////////////////////////
// Combinational logic
/////////////////////////////////////////////////////
// Compute address to use to index into the DTLB data memory
assign read_address = address_x[`LM32_DTLB_IDX_RNG];
// tlb_update_address will receive data from a CSR register
assign write_address = (flushing == `TRUE)
? flush_set
: tlbvaddr[`LM32_DTLB_IDX_RNG];
assign write_port_enable = (update == `TRUE) || (invalidate == `TRUE) || (flushing == `TRUE);
assign physical_load_store_address_m = (enable == `FALSE)
? address_m
: {tlbe_pfn_m, address_m[`LM32_DTLB_OFFSET_RNG]};
assign tlbe = {
tlbpaddr[`LM32_DTLB_VPFN_RNG], // pfn
tlbvaddr[`LM32_DTLB_TAG_RNG], // tag
tlbpaddr[2], // cache inhibit
tlbpaddr[1], // read only
`TRUE}; // valid
assign tlbe_inval = {{`LM32_DTLB_DATA_WIDTH-1{1'b0}}, `FALSE};
assign write_data = ((invalidate == `TRUE) || (flushing)) ? tlbe_inval : tlbe;
assign tlbe_match = ({tlbe_tag_x, tlbe_valid_x} == {address_x[`LM32_DTLB_TAG_RNG], `TRUE});
assign miss_vfn = {address_x[`LM32_DTLB_VPFN_RNG], {offset_width{1'b0}}};
assign miss_x = ((enable == `TRUE) && ((load_q_x == `TRUE) || (store_q_x == `TRUE)) && (tlbe_match == `FALSE) && (lookup == `FALSE));
assign cache_inhibit_x = ((enable == `TRUE) && (tlbe_ci_x == `TRUE));
assign fault_x = ((enable == `TRUE) && (store_q_x == `TRUE) && (tlbe_match == `TRUE) && (tlbe_ro_x == `TRUE));
assign checking = state[0];
assign flushing = state[1];
assign stall_request = (flushing == `TRUE) || (lookup == `TRUE);
/////////////////////////////////////////////////////
// Sequential logic
/////////////////////////////////////////////////////
// Lookup logic
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
lookup <= `FALSE;
else
begin
if ((enable == `TRUE) && (stall_x == `FALSE) && ((load_d == `TRUE) || (store_d == `TRUE)))
lookup <= `TRUE;
else
lookup <= `FALSE;
end
end
// X/M stage registers
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
tlbe_pfn_m <= {vpfn_width{1'bx}};
else if (stall_m == `FALSE)
tlbe_pfn_m <= tlbe_pfn_x;
end
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
flush_set <= {index_width{1'b1}};
state <= `LM32_DTLB_STATE_FLUSH;
end
else
begin
case (state)
`LM32_DTLB_STATE_CHECK:
begin
if (flush == `TRUE) begin
flush_set <= {index_width{1'b1}};
state <= `LM32_DTLB_STATE_FLUSH;
end
end
`LM32_DTLB_STATE_FLUSH:
begin
if (flush_set == {index_width{1'b0}})
state <= `LM32_DTLB_STATE_CHECK;
flush_set <= flush_set - 1'b1;
end
endcase
end
end
endmodule
`endif