mirror of
https://github.com/lowRISC/ibex.git
synced 2025-06-28 01:12:02 -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;
|
logic clk_sys = 1'b0, rst_sys_n;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CoreD,
|
CoreD
|
||||||
CoreI
|
|
||||||
} bus_host_e;
|
} bus_host_e;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -35,7 +34,7 @@ module ibex_simple_system (
|
||||||
} bus_device_e;
|
} bus_device_e;
|
||||||
|
|
||||||
localparam NrDevices = 3;
|
localparam NrDevices = 3;
|
||||||
localparam NrHosts = 2;
|
localparam NrHosts = 1;
|
||||||
|
|
||||||
// interrupts
|
// interrupts
|
||||||
logic timer_irq;
|
logic timer_irq;
|
||||||
|
@ -71,6 +70,16 @@ module ibex_simple_system (
|
||||||
assign cfg_device_addr_base[Timer] = 32'h30000;
|
assign cfg_device_addr_base[Timer] = 32'h30000;
|
||||||
assign cfg_device_addr_mask[Timer] = ~32'h3FF; // 1 kB
|
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
|
`ifdef VERILATOR
|
||||||
assign clk_sys = IO_CLK;
|
assign clk_sys = IO_CLK;
|
||||||
|
@ -123,10 +132,6 @@ module ibex_simple_system (
|
||||||
.cfg_device_addr_mask
|
.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 #(
|
ibex_core_tracing #(
|
||||||
.MHPMCounterNum(29),
|
.MHPMCounterNum(29),
|
||||||
.DmHaltAddr(32'h00100000),
|
.DmHaltAddr(32'h00100000),
|
||||||
|
@ -143,12 +148,12 @@ module ibex_simple_system (
|
||||||
// First instruction executed is at 0x0 + 0x80
|
// First instruction executed is at 0x0 + 0x80
|
||||||
.boot_addr_i (32'h00100000),
|
.boot_addr_i (32'h00100000),
|
||||||
|
|
||||||
.instr_req_o (host_req[CoreI]),
|
.instr_req_o (instr_req),
|
||||||
.instr_gnt_i (host_gnt[CoreI]),
|
.instr_gnt_i (instr_gnt),
|
||||||
.instr_rvalid_i (host_rvalid[CoreI]),
|
.instr_rvalid_i (instr_rvalid),
|
||||||
.instr_addr_o (host_addr[CoreI]),
|
.instr_addr_o (instr_addr),
|
||||||
.instr_rdata_i (host_rdata[CoreI]),
|
.instr_rdata_i (instr_rdata),
|
||||||
.instr_err_i (host_err[CoreI]),
|
.instr_err_i (instr_err),
|
||||||
|
|
||||||
.data_req_o (host_req[CoreD]),
|
.data_req_o (host_req[CoreD]),
|
||||||
.data_gnt_i (host_gnt[CoreD]),
|
.data_gnt_i (host_gnt[CoreD]),
|
||||||
|
@ -173,18 +178,27 @@ module ibex_simple_system (
|
||||||
);
|
);
|
||||||
|
|
||||||
// SRAM block for instruction and data storage
|
// SRAM block for instruction and data storage
|
||||||
ram_1p #(
|
ram_2p #(
|
||||||
.Depth(1024*1024/4)
|
.Depth(1024*1024/4)
|
||||||
) u_ram (
|
) u_ram (
|
||||||
.clk_i (clk_sys),
|
.clk_i (clk_sys),
|
||||||
.rst_ni (rst_sys_n),
|
.rst_ni (rst_sys_n),
|
||||||
.req_i (device_req[Ram]),
|
|
||||||
.we_i (device_we[Ram]),
|
.a_req_i (device_req[Ram]),
|
||||||
.be_i (device_be[Ram]),
|
.a_we_i (device_we[Ram]),
|
||||||
.addr_i (device_addr[Ram]),
|
.a_be_i (device_be[Ram]),
|
||||||
.wdata_i (device_wdata[Ram]),
|
.a_addr_i (device_addr[Ram]),
|
||||||
.rvalid_o (device_rvalid[Ram]),
|
.a_wdata_i (device_wdata[Ram]),
|
||||||
.rdata_o (device_rdata[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 #(
|
simulator_ctrl #(
|
||||||
|
|
|
@ -51,14 +51,17 @@ module bus #(
|
||||||
input [AddressWidth-1:0] cfg_device_addr_mask [NrDevices]
|
input [AddressWidth-1:0] cfg_device_addr_mask [NrDevices]
|
||||||
);
|
);
|
||||||
|
|
||||||
logic [$clog2(NrHosts)-1:0] host_sel_req, host_sel_resp;
|
localparam int unsigned NumBitsHostSel = NrHosts > 1 ? $clog2(NrHosts) : 1;
|
||||||
logic [$clog2(NrDevices)-1:0] device_sel_req, device_sel_resp;
|
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
|
// Master select prio arbiter
|
||||||
always_comb begin
|
always_comb begin
|
||||||
for (integer host = NrHosts - 1; host >= 0; host = host - 1) begin
|
for (integer host = NrHosts - 1; host >= 0; host = host - 1) begin
|
||||||
if (host_req_i[host]) begin
|
if (host_req_i[host]) begin
|
||||||
host_sel_req = $clog2(NrHosts)'(host);
|
host_sel_req = NumBitsHostSel'(host);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -68,7 +71,7 @@ module bus #(
|
||||||
for (integer device = 0; device < NrDevices; device = device + 1) begin
|
for (integer device = 0; device < NrDevices; device = device + 1) begin
|
||||||
if ((host_addr_i[host_sel_req] & cfg_device_addr_mask[device])
|
if ((host_addr_i[host_sel_req] & cfg_device_addr_mask[device])
|
||||||
== cfg_device_addr_base[device]) begin
|
== cfg_device_addr_base[device]) begin
|
||||||
device_sel_req = $clog2(NrDevices)'(device);
|
device_sel_req = NumBitsDeviceSel'(device);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -86,7 +89,7 @@ module bus #(
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
for (integer device = 0; device < NrDevices; device = device + 1) 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_req_o[device] = host_req_i[host_sel_req];
|
||||||
device_we_o[device] = host_we_i[host_sel_req];
|
device_we_o[device] = host_we_i[host_sel_req];
|
||||||
device_addr_o[device] = host_addr_i[host_sel_req];
|
device_addr_o[device] = host_addr_i[host_sel_req];
|
||||||
|
@ -105,8 +108,7 @@ module bus #(
|
||||||
always_comb begin
|
always_comb begin
|
||||||
for (integer host = 0; host < NrHosts; host = host + 1) begin
|
for (integer host = 0; host < NrHosts; host = host + 1) begin
|
||||||
host_gnt_o[host] = 1'b0;
|
host_gnt_o[host] = 1'b0;
|
||||||
|
if (NumBitsHostSel'(host) == host_sel_resp) begin
|
||||||
if ($clog2(NrHosts)'(host) == host_sel_resp) begin
|
|
||||||
host_rvalid_o[host] = device_rvalid_i[device_sel_resp];
|
host_rvalid_o[host] = device_rvalid_i[device_sel_resp];
|
||||||
host_err_o[host] = device_err_i[device_sel_resp];
|
host_err_o[host] = device_err_i[device_sel_resp];
|
||||||
host_rdata_o[host] = device_rdata_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:
|
files:
|
||||||
- ./rtl/prim_clock_gating.sv
|
- ./rtl/prim_clock_gating.sv
|
||||||
- ./rtl/ram_1p.sv
|
- ./rtl/ram_1p.sv
|
||||||
|
- ./rtl/ram_2p.sv
|
||||||
- ./rtl/bus.sv
|
- ./rtl/bus.sv
|
||||||
- ./rtl/sim/simulator_ctrl.sv
|
- ./rtl/sim/simulator_ctrl.sv
|
||||||
- ./rtl/timer.sv
|
- ./rtl/timer.sv
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue