mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 04:57:25 -04:00
[examples] Add Dual-Port Memory to Simple System
This commit adds a separate memory ports for instruction and data fetches to the Simple System example. * Add Dual-Port RAM with 1 cycle read/write delay, 32 bit words. * Introduce parametric signal width definitions for bus implementation to work with a single host / device. * Modify Simple System top module to instantiate the new dual-port RAM.
This commit is contained in:
parent
230c282c36
commit
86979e603f
4 changed files with 172 additions and 30 deletions
|
@ -24,8 +24,7 @@ module ibex_simple_system (
|
|||
logic clk_sys = 1'b0, rst_sys_n;
|
||||
|
||||
typedef enum {
|
||||
CoreD,
|
||||
CoreI
|
||||
CoreD
|
||||
} bus_host_e;
|
||||
|
||||
typedef enum {
|
||||
|
@ -35,7 +34,7 @@ module ibex_simple_system (
|
|||
} bus_device_e;
|
||||
|
||||
localparam NrDevices = 3;
|
||||
localparam NrHosts = 2;
|
||||
localparam NrHosts = 1;
|
||||
|
||||
// interrupts
|
||||
logic timer_irq;
|
||||
|
@ -71,6 +70,16 @@ module ibex_simple_system (
|
|||
assign cfg_device_addr_base[Timer] = 32'h30000;
|
||||
assign cfg_device_addr_mask[Timer] = ~32'h3FF; // 1 kB
|
||||
|
||||
// Instruction fetch signals
|
||||
logic instr_req;
|
||||
logic instr_gnt;
|
||||
logic instr_rvalid;
|
||||
logic [31:0] instr_addr;
|
||||
logic [31:0] instr_rdata;
|
||||
logic instr_err;
|
||||
|
||||
assign instr_gnt = instr_req;
|
||||
assign instr_err = '0;
|
||||
|
||||
`ifdef VERILATOR
|
||||
assign clk_sys = IO_CLK;
|
||||
|
@ -123,10 +132,6 @@ module ibex_simple_system (
|
|||
.cfg_device_addr_mask
|
||||
);
|
||||
|
||||
assign host_we[CoreI] = 1'b0;
|
||||
assign host_be[CoreI] = 4'b1111;
|
||||
assign host_wdata[CoreI] = 32'b0;
|
||||
|
||||
ibex_core_tracing #(
|
||||
.MHPMCounterNum(29),
|
||||
.DmHaltAddr(32'h00100000),
|
||||
|
@ -143,12 +148,12 @@ module ibex_simple_system (
|
|||
// First instruction executed is at 0x0 + 0x80
|
||||
.boot_addr_i (32'h00100000),
|
||||
|
||||
.instr_req_o (host_req[CoreI]),
|
||||
.instr_gnt_i (host_gnt[CoreI]),
|
||||
.instr_rvalid_i (host_rvalid[CoreI]),
|
||||
.instr_addr_o (host_addr[CoreI]),
|
||||
.instr_rdata_i (host_rdata[CoreI]),
|
||||
.instr_err_i (host_err[CoreI]),
|
||||
.instr_req_o (instr_req),
|
||||
.instr_gnt_i (instr_gnt),
|
||||
.instr_rvalid_i (instr_rvalid),
|
||||
.instr_addr_o (instr_addr),
|
||||
.instr_rdata_i (instr_rdata),
|
||||
.instr_err_i (instr_err),
|
||||
|
||||
.data_req_o (host_req[CoreD]),
|
||||
.data_gnt_i (host_gnt[CoreD]),
|
||||
|
@ -173,18 +178,27 @@ module ibex_simple_system (
|
|||
);
|
||||
|
||||
// SRAM block for instruction and data storage
|
||||
ram_1p #(
|
||||
ram_2p #(
|
||||
.Depth(1024*1024/4)
|
||||
) u_ram (
|
||||
.clk_i (clk_sys),
|
||||
.rst_ni (rst_sys_n),
|
||||
.req_i (device_req[Ram]),
|
||||
.we_i (device_we[Ram]),
|
||||
.be_i (device_be[Ram]),
|
||||
.addr_i (device_addr[Ram]),
|
||||
.wdata_i (device_wdata[Ram]),
|
||||
.rvalid_o (device_rvalid[Ram]),
|
||||
.rdata_o (device_rdata[Ram])
|
||||
.clk_i (clk_sys),
|
||||
.rst_ni (rst_sys_n),
|
||||
|
||||
.a_req_i (device_req[Ram]),
|
||||
.a_we_i (device_we[Ram]),
|
||||
.a_be_i (device_be[Ram]),
|
||||
.a_addr_i (device_addr[Ram]),
|
||||
.a_wdata_i (device_wdata[Ram]),
|
||||
.a_rvalid_o (device_rvalid[Ram]),
|
||||
.a_rdata_o (device_rdata[Ram]),
|
||||
|
||||
.b_req_i (instr_req),
|
||||
.b_we_i (1'b0),
|
||||
.b_be_i (4'b0),
|
||||
.b_addr_i (instr_addr),
|
||||
.b_wdata_i (32'b0),
|
||||
.b_rvalid_o (instr_rvalid),
|
||||
.b_rdata_o (instr_rdata)
|
||||
);
|
||||
|
||||
simulator_ctrl #(
|
||||
|
|
|
@ -51,14 +51,17 @@ module bus #(
|
|||
input [AddressWidth-1:0] cfg_device_addr_mask [NrDevices]
|
||||
);
|
||||
|
||||
logic [$clog2(NrHosts)-1:0] host_sel_req, host_sel_resp;
|
||||
logic [$clog2(NrDevices)-1:0] device_sel_req, device_sel_resp;
|
||||
localparam int unsigned NumBitsHostSel = NrHosts > 1 ? $clog2(NrHosts) : 1;
|
||||
localparam int unsigned NumBitsDeviceSel = NrDevices > 1 ? $clog2(NrDevices) : 1;
|
||||
|
||||
logic [NumBitsHostSel-1:0] host_sel_req, host_sel_resp;
|
||||
logic [NumBitsDeviceSel-1:0] device_sel_req, device_sel_resp;
|
||||
|
||||
// Master select prio arbiter
|
||||
always_comb begin
|
||||
for (integer host = NrHosts - 1; host >= 0; host = host - 1) begin
|
||||
if (host_req_i[host]) begin
|
||||
host_sel_req = $clog2(NrHosts)'(host);
|
||||
host_sel_req = NumBitsHostSel'(host);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -68,7 +71,7 @@ module bus #(
|
|||
for (integer device = 0; device < NrDevices; device = device + 1) begin
|
||||
if ((host_addr_i[host_sel_req] & cfg_device_addr_mask[device])
|
||||
== cfg_device_addr_base[device]) begin
|
||||
device_sel_req = $clog2(NrDevices)'(device);
|
||||
device_sel_req = NumBitsDeviceSel'(device);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -86,7 +89,7 @@ module bus #(
|
|||
|
||||
always_comb begin
|
||||
for (integer device = 0; device < NrDevices; device = device + 1) begin
|
||||
if ($clog2(NrDevices)'(device) == device_sel_req) begin
|
||||
if (NumBitsDeviceSel'(device) == device_sel_req) begin
|
||||
device_req_o[device] = host_req_i[host_sel_req];
|
||||
device_we_o[device] = host_we_i[host_sel_req];
|
||||
device_addr_o[device] = host_addr_i[host_sel_req];
|
||||
|
@ -105,8 +108,7 @@ module bus #(
|
|||
always_comb begin
|
||||
for (integer host = 0; host < NrHosts; host = host + 1) begin
|
||||
host_gnt_o[host] = 1'b0;
|
||||
|
||||
if ($clog2(NrHosts)'(host) == host_sel_resp) begin
|
||||
if (NumBitsHostSel'(host) == host_sel_resp) begin
|
||||
host_rvalid_o[host] = device_rvalid_i[device_sel_resp];
|
||||
host_err_o[host] = device_err_i[device_sel_resp];
|
||||
host_rdata_o[host] = device_rdata_i[device_sel_resp];
|
||||
|
|
125
shared/rtl/ram_2p.sv
Normal file
125
shared/rtl/ram_2p.sv
Normal file
|
@ -0,0 +1,125 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* Dual-port RAM with 1 cycle read/write delay, 32 bit words.
|
||||
*
|
||||
* The two ports are in Read-First Mode: when reading from and writing to the same address
|
||||
* simultaneously, the old content is returned, before the new content is written. New content
|
||||
* is made available to both ports with one cycle delay.
|
||||
*
|
||||
* Simultaneous write operations by both ports to the same address are to be avoided: The data
|
||||
* written to memory is not determined.
|
||||
*/
|
||||
module ram_2p #(
|
||||
parameter int Depth = 128
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input a_req_i,
|
||||
input a_we_i,
|
||||
input [ 3:0] a_be_i,
|
||||
input [31:0] a_addr_i,
|
||||
input [31:0] a_wdata_i,
|
||||
output logic a_rvalid_o,
|
||||
output logic [31:0] a_rdata_o,
|
||||
|
||||
input b_req_i,
|
||||
input b_we_i,
|
||||
input [ 3:0] b_be_i,
|
||||
input [31:0] b_addr_i,
|
||||
input [31:0] b_wdata_i,
|
||||
output logic b_rvalid_o,
|
||||
output logic [31:0] b_rdata_o
|
||||
);
|
||||
|
||||
localparam int Aw = $clog2(Depth);
|
||||
|
||||
logic [31:0] mem [Depth];
|
||||
|
||||
logic [Aw-1:0] a_addr_idx;
|
||||
assign a_addr_idx = a_addr_i[Aw-1+2:2];
|
||||
logic [31-Aw:0] unused_a_addr_parts;
|
||||
assign unused_a_addr_parts = {a_addr_i[31:Aw+2], a_addr_i[1:0]};
|
||||
|
||||
logic [Aw-1:0] b_addr_idx;
|
||||
assign b_addr_idx = b_addr_i[Aw-1+2:2];
|
||||
logic [31-Aw:0] unused_b_addr_parts;
|
||||
assign unused_b_addr_parts = {b_addr_i[31:Aw+2], b_addr_i[1:0]};
|
||||
|
||||
always @(posedge clk_i) begin
|
||||
if (a_req_i) begin
|
||||
if (a_we_i) begin
|
||||
for (int i = 0; i < 4; i = i + 1) begin
|
||||
if (a_be_i[i] == 1'b1) begin
|
||||
mem[a_addr_idx][i*8 +: 8] <= a_wdata_i[i*8 +: 8];
|
||||
end
|
||||
end
|
||||
end
|
||||
a_rdata_o <= mem[a_addr_idx];
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_i) begin
|
||||
if (b_req_i) begin
|
||||
if (b_we_i) begin
|
||||
for (int i = 0; i < 4; i = i + 1) begin
|
||||
if (b_be_i[i] == 1'b1) begin
|
||||
mem[b_addr_idx][i*8 +: 8] <= b_wdata_i[i*8 +: 8];
|
||||
end
|
||||
end
|
||||
end
|
||||
b_rdata_o <= mem[b_addr_idx];
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
a_rvalid_o <= '0;
|
||||
end else begin
|
||||
a_rvalid_o <= a_req_i;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
b_rvalid_o <= '0;
|
||||
end else begin
|
||||
b_rvalid_o <= b_req_i;
|
||||
end
|
||||
end
|
||||
|
||||
`ifdef VERILATOR
|
||||
// Task for loading 'mem' with SystemVerilog system task $readmemh()
|
||||
export "DPI-C" task simutil_verilator_memload;
|
||||
// Function for setting a specific 32 bit element in |mem|
|
||||
// Returns 1 (true) for success, 0 (false) for errors.
|
||||
export "DPI-C" function simutil_verilator_set_mem;
|
||||
|
||||
task simutil_verilator_memload;
|
||||
input string file;
|
||||
$readmemh(file, mem);
|
||||
endtask
|
||||
|
||||
// TODO: Allow 'val' to have other widths than 32 bit
|
||||
function int simutil_verilator_set_mem(input int index,
|
||||
input logic[31:0] val);
|
||||
if (index >= Depth) begin
|
||||
return 0;
|
||||
end
|
||||
|
||||
mem[index] = val;
|
||||
return 1;
|
||||
endfunction
|
||||
`endif
|
||||
|
||||
`ifdef SRAM_INIT_FILE
|
||||
localparam MEM_FILE = `"`SRAM_INIT_FILE`";
|
||||
initial begin
|
||||
$display("Initializing SRAM from %s", MEM_FILE);
|
||||
$readmemh(MEM_FILE, mem);
|
||||
end
|
||||
`endif
|
||||
endmodule
|
|
@ -11,6 +11,7 @@ filesets:
|
|||
files:
|
||||
- ./rtl/prim_clock_gating.sv
|
||||
- ./rtl/ram_1p.sv
|
||||
- ./rtl/ram_2p.sv
|
||||
- ./rtl/bus.sv
|
||||
- ./rtl/sim/simulator_ctrl.sv
|
||||
- ./rtl/timer.sv
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue