simbench/source/picorv32_tcm.sv

180 lines
5.7 KiB
Systemverilog
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

`timescale 1ps/1ps
module picorv32_tcm #(parameter ADDR_WIDTH = 8,
parameter USE_LOOK_AHEAD = 0,
parameter USE_ADDR_MUX = 1,
parameter MEM_INIT_FILE = "")
(input wire clock,
/* verilator lint_off UNUSED */
// Not used in look-ahead mode
input wire reset,
/* verilator lint_on UNUSED */
/* PicoRV32 bus interface */
input wire mem_valid,
output wire mem_ready,
input wire [ADDR_WIDTH-1:0] mem_addr,
input wire [31:0] mem_wdata,
input wire [3:0] mem_wstrb,
output reg [31:0] mem_rdata,
// PicoRV32 look-ahead address.
// Not used in non-look-ahead mode.
/* verilator lint_off UNUSED */
input wire [ADDR_WIDTH-1:0] mem_la_addr
/* verilator lint_off UNUSED */
);
logic [31:0] ram[0:(2 ** (ADDR_WIDTH-2))-1];
if (MEM_INIT_FILE != "")
initial $readmemh(MEM_INIT_FILE, ram);
/* verilator lint_off UNUSED */
// Bits [1:0] are not used
logic [ADDR_WIDTH-1:0] byte_addr;
/* verilator lint_on UNUSED */
logic [ADDR_WIDTH-3:0] word_addr;
logic write;
assign word_addr = byte_addr[ADDR_WIDTH-1:2];
always @(posedge clock) begin
for (int n = 0; n < 4; n += 1)
if (write && mem_wstrb[n])
ram[word_addr][n*8 +: 8] <= mem_wdata[n*8 +: 8];
mem_rdata <= ram[word_addr];
end
if (USE_LOOK_AHEAD == 0) begin : no_look_ahead
logic data_ready;
always_ff @(posedge clock)
if (reset) data_ready <= 1'b0;
else
// Don't use ternary operator to prevent
// X-propagation from PicoRV32 core
// data_ready <= mem_valid & ~(|mem_wstrb);
if (mem_valid && mem_wstrb == '0)
data_ready <= 1'b1;
else
data_ready <= 1'b0;
assign byte_addr = mem_addr;
assign write = mem_valid & (|mem_wstrb);
assign mem_ready = data_ready | write;
end
else begin : look_ahead
logic data_ready;
always_ff @(posedge clock)
if (reset) data_ready <= 1'b0;
else
// Don't use ternary operator to prevent
// X-propagation from PicoRV32 core
// data_ready <= ~(mem_valid && (|mem_wstrb));
if (mem_valid && mem_wstrb != '0)
data_ready <= 1'b0;
else
data_ready <= 1'b1;
/* mem_la_addr валиден как минимум один такт после поднятия mem_valid.
* Т.е. в принципе можно обойтись без мультиплескора. В формальной части
* добавлено соответствуюшее утверждение. */
if (USE_ADDR_MUX == 0)
assign byte_addr = mem_la_addr[ADDR_WIDTH-1:0];
else
assign byte_addr = mem_valid ?
mem_addr[ADDR_WIDTH-1:0] :
mem_la_addr[ADDR_WIDTH-1:0];
assign write = mem_valid & (|mem_wstrb);
assign mem_ready = data_ready;
end
`ifdef FORMAL
// Past valid flag
logic have_past = 1'b0;
always_ff @(posedge clock) have_past <= 1'b1;
// Assumptions
always @(*) assume(reset == 1'b0);
always @(posedge clock)
if (have_past) begin
// mem_addr <= mem_la_addr
if ($rose(mem_valid))
assume(mem_addr == $past(mem_la_addr));
// Stable mem_addr and mem_data when mem_valid is active
if (mem_valid) begin
assume($stable(mem_addr));
assume($stable(mem_wdata));
assume($stable(mem_wstrb));
end
// Assume mem_valid will not cleared while mem_ready is not active
if ($past(mem_valid) && !$past(mem_ready))
assume(mem_valid == 1'b1);
// Assume mem_valid will cleared after memory transaction complete
if ($past(mem_valid) && $past(mem_ready))
assume(mem_valid == 1'b0);
// WARN: May be wrong assumption
// Assume mem_add == mem_la_addr on first clock cycle of mem_valid activity
if ($rose(mem_valid))
assume(mem_addr == mem_la_addr);
end
else begin
// Initial mem_valid = 1'b0
assume(mem_valid == 1'b0);
end
// Data read
always_ff @(posedge clock)
if (have_past)
if (mem_valid && mem_ready && mem_wstrb == '0)
assert(mem_rdata == ram[mem_addr[ADDR_WIDTH-1:2]]);
// Data write
always_ff @(posedge clock) begin
logic [3:0] mem_wstrb_past;
if (have_past) begin
mem_wstrb_past = $past(mem_wstrb);
if ($past(mem_valid) && $past(mem_ready) && mem_wstrb_past != '0)
for (int n = 0; n < 4; n += 1)
if (mem_wstrb_past[n])
assert(ram[$past(mem_addr[ADDR_WIDTH-1:2])][n*8 +: 8] == $past(mem_wdata[n*8 +: 8]));
end
end
// Mem ready
always_ff @(posedge clock)
if (have_past)
if (USE_LOOK_AHEAD == 0) begin
// Write transaction
if (mem_wstrb != '0 && mem_valid)
assert(mem_ready);
// First cycle of read transaction
if (mem_wstrb == '0 && !$past(mem_valid)&& mem_valid)
assert(!mem_ready);
// Second cycle of read transaction
if ($past(mem_wstrb) == '0 && $past(mem_valid) && mem_valid)
assert(mem_ready);
end
else begin
// In look-ahead mode mem_ready always active
if (mem_valid)
assert(mem_ready);
end
`endif
endmodule // picorv32_tcm