add boilerplate for new modules - just gotta rewrite the fsm

This commit is contained in:
Fischer Moseley 2023-04-13 23:05:19 -04:00
parent 4d2c3d08e6
commit bdca8e01e7
10 changed files with 325 additions and 467 deletions

View File

@ -32,10 +32,7 @@ auto_gen:
functional_sim: io_core_tb logic_analyzer_tb bit_fifo_tb bridge_rx_tb bridge_tx_tb lut_ram_tb
block_memory_tb:
cd test/functional_sim/block_memory_tb/ && python3 foo.py
iverilog -g2012 -o sim.out -y src/manta \
test/functional_sim/block_memory_tb/block_memory_tb.sv \
test/functional_sim/block_memory_tb/block_memory.v
iverilog -g2012 -o sim.out -y src/manta test/functional_sim/block_memory_tb.sv
vvp sim.out
rm sim.out

View File

@ -1,132 +0,0 @@
`default_nettype none
`timescale 1ns/1ps
module la_fsm(
input wire clk,
input wire trig,
input wire [$clog2(SAMPLE_DEPTH):0] fifo_size,
output reg fifo_acquire,
output reg fifo_pop,
output reg fifo_clear,
// input port
input wire [15:0] addr_i,
input wire [15:0] wdata_i,
input wire [15:0] rdata_i,
input wire rw_i,
input wire valid_i,
// output port
output reg [15:0] addr_o,
output reg [15:0] wdata_o,
output reg [15:0] rdata_o,
output reg rw_o,
output reg valid_o);
parameter BASE_ADDR = 0;
parameter SAMPLE_DEPTH = 0;
// state machine
localparam IDLE = 0;
localparam START_CAPTURE = 1;
localparam MOVE_TO_POSITION = 2;
localparam IN_POSITION = 3;
localparam FILLING_BUFFER = 4;
localparam FILLED = 5;
reg [3:0] state;
reg signed [15:0] trigger_loc;
reg signed [15:0] present_loc;
initial state = IDLE;
initial trigger_loc = 0;
initial present_loc = 0;
// perform register operations
always @(posedge clk) begin
addr_o <= addr_i;
wdata_o <= wdata_i;
rdata_o <= rdata_i;
rw_o <= rw_i;
valid_o <= valid_i;
// check if address is valid
if( (valid_i) && (addr_i >= BASE_ADDR) && (addr_i <= BASE_ADDR + 2)) begin
if(!rw_i) begin // reads
case (addr_i)
BASE_ADDR + 0: rdata_o <= state;
BASE_ADDR + 1: rdata_o <= trigger_loc;
BASE_ADDR + 2: rdata_o <= present_loc;
endcase
end
else begin // writes
case (addr_i)
BASE_ADDR + 0: state <= wdata_i;
BASE_ADDR + 1: trigger_loc <= wdata_i;
//BASE_ADDR + 2: present_loc <= wdata_i;
endcase
end
end
// end
// run state machine
// always @(posedge clk) begin
if(state == IDLE) begin
present_loc <= (trigger_loc < 0) ? trigger_loc : 0;
end
else if(state == START_CAPTURE) begin
// perform whatever setup is needed before starting the next capture
fifo_clear <= 1;
state <= MOVE_TO_POSITION;
end
else if(state == MOVE_TO_POSITION) begin
fifo_clear <= 0;
// if trigger location is negative or zero,
// then we're already in position
if(trigger_loc <= 0) state <= IN_POSITION;
// otherwise we'll need to wait a little,
// but we'll need to buffer along the way
else begin
present_loc <= present_loc + 1;
// add code to add samples to word FIFO
fifo_acquire <= 1;
if (present_loc == trigger_loc) state <= IN_POSITION;
end
end
else if(state == IN_POSITION) begin
// pop stuff out of the word FIFO in addition to pulling it in
fifo_acquire <= 1;
fifo_pop <= 1;
if(trig) state <= FILLING_BUFFER;
end
else if(state == FILLING_BUFFER) begin
fifo_acquire <= 1;
fifo_pop <= 0;
if(fifo_size == SAMPLE_DEPTH) state <= FILLED;
end
else if(state == FILLED) begin
// don't automatically go back to IDLE, the host will move
// the state to MOVE_TO_POSITION
present_loc <= (trigger_loc < 0) ? trigger_loc : 0;
end
// return to IDLE state if somehow we get to a state that doesn't exist
else begin
state <= IDLE;
end
end
endmodule
`default_nettype wire

View File

@ -0,0 +1,113 @@
`default_nettype none
`timescale 1ns/1ps
module logic_analyzer_controller (
input wire clk,
// from register file
output reg [3:0] state,
input wire signed [15:0] trigger_loc,
output reg signed [15:0] current_loc,
input wire request_start,
input wire request_stop,
output reg read_pointer,
// from trigger block
input wire trig,
// block memory user port
output [ADDR_WIDTH-1:0] bram_addr,
output bram_we
);
parameter DEPTH = 0;
localparam ADDR_WIDTH = $clog2(DEPTH);
// fsm
localparam IDLE = 0;
localparam START_CAPTURE = 1;
localparam MOVE_TO_POSITION = 2;
localparam IN_POSITION = 3;
localparam FILLING_BUFFER = 4;
localparam FILLED = 5;
initial state = IDLE;
initial current_loc = 0;
initial read_pointer = 0;
initial write_pointer = 0;
always @(posedge clk) begin
if(state == IDLE) begin
current_loc <= (trigger_loc < 0) ? trigger_loc : 0;
end
else if(state == START_CAPTURE) begin
// perform whatever setup is needed before starting the next capture
fifo_clear <= 1;
state <= MOVE_TO_POSITION;
end
else if(state == MOVE_TO_POSITION) begin
fifo_clear <= 0;
// if trigger location is negative or zero,
// then we're already in position
if(trigger_loc <= 0) state <= IN_POSITION;
// otherwise we'll need to wait a little,
// but we'll need to buffer along the way
else begin
current_loc <= current_loc + 1;
// add code to add samples to word FIFO
fifo_acquire <= 1;
if (current_loc == trigger_loc) state <= IN_POSITION;
end
end
else if(state == IN_POSITION) begin
// pop stuff out of the word FIFO in addition to pulling it in
fifo_acquire <= 1;
fifo_pop <= 1;
if(trig) state <= FILLING_BUFFER;
end
else if(state == FILLING_BUFFER) begin
fifo_acquire <= 1;
fifo_pop <= 0;
if(fifo_size == SAMPLE_DEPTH) state <= FILLED;
end
else if(state == FILLED) begin
// don't automatically go back to IDLE, the host will move
// the state to MOVE_TO_POSITION
current_loc <= (trigger_loc < 0) ? trigger_loc : 0;
end
// return to IDLE state if somehow we get to a state that doesn't exist
else begin
state <= IDLE;
end
end
// fifo
reg acquire;
reg pop;
reg [ADDR_WIDTH:0] size,
reg clear,
reg [ADDR_WIDTH:0] write_pointer = 0;
reg [ADDR_WIDTH:0] read_pointer = 0;
assign size = write_pointer - read_pointer;
always @(posedge clk) begin
if (clear) read_pointer <= write_pointer;
if (acquire && size < DEPTH) write_pointer <= write_pointer + 1'd1;
if (pop && size > 0) read_pointer <= read_pointer + 1'd1;
end
endmodule
`default_nettype wire

View File

@ -22,18 +22,48 @@ module logic_analyzer (
output reg valid_o
);
// fsm
la_fsm #(
.BASE_ADDR(/* FSM_BASE_ADDR */),
.SAMPLE_DEPTH(/* SAMPLE_DEPTH */)
) fsm (
parameter SAMPLE_DEPTH = 0;
localparam ADDR_WIDTH = $clog2(SAMPLE_DEPTH);
reg [3:0] state;
reg signed [15:0] trigger_loc;
reg signed [15:0] current_loc;
reg request_start;
reg request_stop;
reg [ADDR_WIDTH-1:0] read_pointer;
reg trig;
reg [ADDR_WIDTH-1:0] bram_addr;
reg bram_we;
localparam TOTAL_PROBE_WIDTH = 0;
reg [TOTAL_PROBE_WIDTH-1:0] probes_concat;
assign probes_concat = /* PROBES_CONCAT */;
logic_analyzer_controller la_controller (
.clk(clk),
// from register file
.state(state),
.trigger_loc(trigger_loc),
.current_loc(current_loc),
.request_start(request_start),
.request_stop(request_stop),
.read_pointer(read_pointer),
// from trigger block
.trig(trig),
.fifo_size(fifo_size),
.fifo_acquire(fifo_acquire),
.fifo_pop(fifo_pop),
.fifo_clear(fifo_clear),
// from block memory user port
.bram_addr(bram_addr),
.bram_we(bram_we)
);
logic_analyzer_fsm_registers #(
.BASE_ADDR(/* FSM_BASE_ADDR */)
) fsm_registers (
.clk(clk),
.addr_i(addr_i),
.wdata_i(wdata_i),
@ -41,24 +71,26 @@ module logic_analyzer (
.rw_i(rw_i),
.valid_i(valid_i),
.addr_o(fsm_trig_blk_addr),
.wdata_o(fsm_trig_blk_wdata),
.rdata_o(fsm_trig_blk_rdata),
.rw_o(fsm_trig_blk_rw),
.valid_o(fsm_trig_blk_valid));
.addr_o(fsm_reg_trig_blk_addr),
.wdata_o(fsm_reg_trig_blk_wdata),
.rdata_o(fsm_reg_trig_blk_rdata),
.rw_o(fsm_reg_trig_blk_rw),
.valid_o(fsm_reg_trig_blk_valid),
reg [15:0] fsm_trig_blk_addr;
reg [15:0] fsm_trig_blk_wdata;
reg [15:0] fsm_trig_blk_rdata;
reg fsm_trig_blk_rw;
reg fsm_trig_blk_valid;
.state(state),
.trigger_loc(trigger_loc),
.current_loc(current_loc),
.request_start(request_start),
.request_stop(request_stop),
.read_pointer(read_pointer));
reg [15:0] fsm_reg_trig_blk_addr;
reg [15:0] fsm_reg_trig_blk_wdata;
reg [15:0] fsm_reg_trig_blk_rdata;
reg fsm_reg_trig_blk_rw;
reg fsm_reg_trig_blk_valid;
reg trig;
reg [$clog2(/* SAMPLE_DEPTH */):0] fifo_size;
reg fifo_acquire;
reg fifo_pop;
reg fifo_clear;
// trigger block
trigger_block #(.BASE_ADDR(/* TRIGGER_BLOCK_BASE_ADDR */)) trig_blk (
@ -68,53 +100,52 @@ module logic_analyzer (
.trig(trig),
.addr_i(fsm_trig_blk_addr),
.wdata_i(fsm_trig_blk_wdata),
.rdata_i(fsm_trig_blk_rdata),
.rw_i(fsm_trig_blk_rw),
.valid_i(fsm_trig_blk_valid),
.addr_i(fsm_reg_trig_blk_addr),
.wdata_i(fsm_reg_trig_blk_wdata),
.rdata_i(fsm_reg_trig_blk_rdata),
.rw_i(fsm_reg_trig_blk_rw),
.valid_i(fsm_reg_trig_blk_valid),
.addr_o(trig_blk_sample_mem_addr),
.wdata_o(trig_blk_sample_mem_wdata),
.rdata_o(trig_blk_sample_mem_rdata),
.rw_o(trig_blk_sample_mem_rw),
.valid_o(trig_blk_sample_mem_valid));
.addr_o(trig_blk_block_mem_addr),
.wdata_o(trig_blk_block_mem_wdata),
.rdata_o(trig_blk_block_mem_rdata),
.rw_o(trig_blk_block_mem_rw),
.valid_o(trig_blk_block_mem_valid));
reg [15:0] trig_blk_sample_mem_addr;
reg [15:0] trig_blk_sample_mem_wdata;
reg [15:0] trig_blk_sample_mem_rdata;
reg trig_blk_sample_mem_rw;
reg trig_blk_sample_mem_valid;
reg [15:0] trig_blk_block_mem_addr;
reg [15:0] trig_blk_block_mem_wdata;
reg [15:0] trig_blk_block_mem_rdata;
reg trig_blk_block_mem_rw;
reg trig_blk_block_mem_valid;
// sample memory
sample_mem #(
block_memory #(
.BASE_ADDR(/* SAMPLE_MEM_BASE_ADDR */),
.SAMPLE_DEPTH(/* SAMPLE_DEPTH */)
) sample_mem (
.WIDTH(),
.DEPTH(/* SAMPLE_DEPTH */)
) block_mem (
.clk(clk),
// fifo
.acquire(fifo_acquire),
.pop(fifo_pop),
.size(fifo_size),
.clear(fifo_clear),
// probes
/* SAMPLE_MEM_PROBE_PORTS */
// input port
.addr_i(trig_blk_sample_mem_addr),
.wdata_i(trig_blk_sample_mem_wdata),
.rdata_i(trig_blk_sample_mem_rdata),
.rw_i(trig_blk_sample_mem_rw),
.valid_i(trig_blk_sample_mem_valid),
.addr_i(trig_blk_block_mem_addr),
.wdata_i(trig_blk_block_mem_wdata),
.rdata_i(trig_blk_block_mem_rdata),
.rw_i(trig_blk_block_mem_rw),
.valid_i(trig_blk_block_mem_valid),
// output port
.addr_o(addr_o),
.wdata_o(wdata_o),
.rdata_o(rdata_o),
.rw_o(rw_o),
.valid_o(valid_o));
.valid_o(valid_o),
// BRAM itself
.user_clk(clk),
.user_addr(bram_addr),
.user_din(probes_concat),
.user_dout(),
.user_we(bram_we));
endmodule
`default_nettype wire

View File

@ -0,0 +1,68 @@
`default_nettype none
`timescale 1ns/1ps
module logic_analyzer_fsm_registers(
input wire clk,
// input port
input wire [15:0] addr_i,
input wire [15:0] wdata_i,
input wire [15:0] rdata_i,
input wire rw_i,
input wire valid_i,
// output port
output reg [15:0] addr_o,
output reg [15:0] wdata_o,
output reg [15:0] rdata_o,
output reg rw_o,
output reg valid_o,
// registers
input wire [3:0] state,
output reg signed [15:0] trigger_loc,
input wire signed [15:0] current_loc,
output reg request_start,
output reg request_stop,
input wire [15:0] read_pointer
);
parameter BASE_ADDR = 0;
localparam MAX_ADDR = BASE_ADDR + 5;
always @(posedge clk) begin
addr_o <= addr_i;
wdata_o <= wdata_i;
rdata_o <= rdata_i;
rw_o <= rw_i;
valid_o <= valid_i;
// check if address is valid
if( (valid_i) && (addr_i >= BASE_ADDR) && (addr_i <= MAX_ADDR)) begin
// reads
if(!rw_i) begin
case (addr_i)
BASE_ADDR + 0: rdata_o <= state;
BASE_ADDR + 1: rdata_o <= trigger_loc;
BASE_ADDR + 2: rdata_o <= current_loc;
BASE_ADDR + 3: rdata_o <= request_start;
BASE_ADDR + 4: rdata_o <= request_stop;
BASE_ADDR + 5: rdata_o <= read_pointer;
endcase
end
// writes
else begin
case (addr_i)
BASE_ADDR + 1: trigger_loc <= wdata_i;
BASE_ADDR + 3: request_start <= wdata_i;
BASE_ADDR + 4: request_stop <= wdata_i;
endcase
end
end
end
endmodule
`default_nettype wire

View File

@ -1,113 +0,0 @@
`default_nettype none
`timescale 1ns/1ps
module sample_mem (
input wire clk,
// fifo
input wire acquire,
input wire pop,
output logic [BRAM_ADDR_WIDTH:0] size,
input wire clear,
// probes
/* PROBE_PORTS */
// input port
input wire [15:0] addr_i,
input wire [15:0] wdata_i,
input wire [15:0] rdata_i,
input wire rw_i,
input wire valid_i,
// output port
output reg [15:0] addr_o,
output reg [15:0] wdata_o,
output reg [15:0] rdata_o,
output reg rw_o,
output reg valid_o);
parameter BASE_ADDR = 0;
parameter SAMPLE_DEPTH = 0;
localparam BRAM_ADDR_WIDTH = $clog2(SAMPLE_DEPTH);
// bus controller
reg [BRAM_ADDR_WIDTH-1:0] bram_read_addr;
reg [15:0] bram_read_data;
always @(*) begin
// if address is valid
if ( (addr_i >= BASE_ADDR) && (addr_i <= BASE_ADDR + SAMPLE_DEPTH) ) begin
// figure out proper place to read from
// want to read from the read pointer, and then loop back around
if(read_pointer + (addr_i - BASE_ADDR) > SAMPLE_DEPTH)
bram_read_addr = read_pointer + (addr_i - BASE_ADDR) - SAMPLE_DEPTH;
else
bram_read_addr = read_pointer + (addr_i - BASE_ADDR);
end
else bram_read_addr = 0;
end
// pipeline bus to compensate for 2-cycles of delay in BRAM
reg [15:0] addr_pip;
reg [15:0] wdata_pip;
reg [15:0] rdata_pip;
reg rw_pip;
reg valid_pip;
always @(posedge clk) begin
addr_pip <= addr_i;
wdata_pip <= wdata_i;
rdata_pip <= rdata_i;
rw_pip <= rw_i;
valid_pip <= valid_i;
addr_o <= addr_pip;
wdata_o <= wdata_pip;
rdata_o <= rdata_pip;
rw_o <= rw_pip;
valid_o <= valid_pip;
if( valid_pip && !rw_pip && (addr_pip >= BASE_ADDR) && (addr_pip <= BASE_ADDR + SAMPLE_DEPTH) )
rdata_o <= bram_read_data;
end
// bram
dual_port_bram #(
.RAM_WIDTH(16),
.RAM_DEPTH(SAMPLE_DEPTH)
) bram (
// read port (controlled by bus)
.clka(clk),
.addra(bram_read_addr),
.dina(16'b0),
.wea(1'b0),
.douta(bram_read_data),
// write port (controlled by FIFO)
.clkb(clk),
.addrb(write_pointer[BRAM_ADDR_WIDTH-1:0]),
.dinb(/* CONCAT */),
.web(acquire),
.doutb());
// fifo
reg [BRAM_ADDR_WIDTH:0] write_pointer = 0;
reg [BRAM_ADDR_WIDTH:0] read_pointer = 0;
assign size = write_pointer - read_pointer;
always @(posedge clk) begin
if (clear) read_pointer <= write_pointer;
if (acquire && size < SAMPLE_DEPTH) write_pointer <= write_pointer + 1'd1;
if (pop && size > 0) read_pointer <= read_pointer + 1'd1;
end
endmodule
`default_nettype wire

View File

@ -3,10 +3,13 @@
`define CP 10
`define HCP 5
task read_reg (
`define BRAM_DEPTH 256
`define BRAM_WIDTH 33
`define ADDR_WIDTH $clog2(`BRAM_DEPTH)
task read_reg_bus_side (
input [15:0] addr,
output [15:0] data,
input string desc
output [15:0] data
);
block_memory_tb.tb_bc_addr = addr;
@ -18,13 +21,12 @@ task read_reg (
while (!block_memory_tb.bc_tb_valid) #`CP;
data = block_memory_tb.bc_tb_rdata;
$display(" -> read 0x%h from addr 0x%h (%s)", data, addr, desc);
$display(" -> bus read 0x%h from addr 0x%h", data, addr);
endtask
task write_reg(
task write_reg_bus_side(
input [15:0] addr,
input [15:0] data,
input string desc
input [15:0] data
);
block_memory_tb.tb_bc_addr = addr;
@ -36,22 +38,44 @@ task write_reg(
block_memory_tb.tb_bc_valid = 0;
while (!block_memory_tb.bc_tb_valid) #`CP;
$display(" -> wrote 0x%h to addr 0x%h (%s)", data, addr, desc);
$display(" -> bus wrote 0x%h to addr 0x%h", data, addr);
endtask
task write_and_verify(
task write_and_verify_bus_side(
input [15:0] addr,
input [15:0] write_data,
input string desc
input [15:0] write_data
);
reg [15:0] read_data;
write_reg(addr, write_data, desc);
read_reg(addr, read_data, desc);
write_reg_bus_side(addr, write_data);
read_reg_bus_side(addr, read_data);
assert(read_data == write_data) else $error("data read does not match data written!");
endtask
task read_user_side(
input [`ADDR_WIDTH-1:0] addr
);
block_memory_tb.bram_user_we = 0;
block_memory_tb.bram_user_addr = addr;
#(2*`CP);
$display("user read 0x%h from addr 0x%h", block_memory_tb.bram_user_dout, addr);
endtask
task write_user_side(
input [`ADDR_WIDTH-1:0] addr,
input [`BRAM_WIDTH-1:0] data
);
block_memory_tb.bram_user_we = 1;
block_memory_tb.bram_user_addr = addr;
block_memory_tb.bram_user_din = data;
#(2*`CP);
$display("user wrote 0x%h to addr 0x%h", data, addr);
endtask
module block_memory_tb;
// boilerplate
@ -74,15 +98,15 @@ module block_memory_tb;
logic bc_tb_valid;
// bram itself
localparam BRAM_DEPTH = 256;
localparam BRAM_WIDTH = 33;
localparam ADDR_WIDTH = $clog2(BRAM_WIDTH);
localparam BRAM_DEPTH = `BRAM_DEPTH;
localparam BRAM_WIDTH = `BRAM_WIDTH;
localparam ADDR_WIDTH = $clog2(BRAM_DEPTH);
logic [ADDR_WIDTH-1:0] bram_user_addr = 0;
logic [BRAM_WIDTH-1:0] bram_user_din = 0;
logic [BRAM_WIDTH-1:0] bram_user_dout;
logic bram_user_we = 0;
block_memory #(.BRAM_DEPTH(BRAM_DEPTH), .BRAM_WIDTH(BRAM_WIDTH)) my_bram_inst(
block_memory #(.DEPTH(BRAM_DEPTH), .WIDTH(BRAM_WIDTH)) block_mem (
.clk(clk),
.addr_i(tb_bc_addr),
@ -112,8 +136,6 @@ module block_memory_tb;
$dumpfile("block_memory_tb.vcd");
$dumpvars(0, block_memory_tb);
$display("i am going to vomit %d", my_bram_inst.N_BRAMS);
// setup and reset
clk = 0;
test_num = 0;
@ -137,14 +159,22 @@ module block_memory_tb;
/* ==== Test 1 Begin ==== */
$display("\n=== test 1: read/write from BRAM, verify ===");
test_num = 1;
write_and_verify(3, 'h1234, "");
write_and_verify(4, 'h5678, "");
write_and_verify(5, 'h0001, "");
write_and_verify_bus_side(0, 'h6789);
write_and_verify_bus_side(1, 'h2345);
write_and_verify_bus_side(2, 'h0001);
// now query what's on the the user side at address 0
bram_user_addr = 1;
#(3*`CP);
$display("Found 0x%h on the other side", bram_user_dout);
read_user_side(0);
write_and_verify_bus_side(3, 'h1111);
write_and_verify_bus_side(4, 'h1111);
write_and_verify_bus_side(5, 'h0001);
// now query what's on the the user side at address 0
read_user_side(1);
write_user_side(1, 0);
read_user_side(1);
#(10*`CP);

View File

@ -1,116 +0,0 @@
module block_memory (
input wire clk,
// input port
input wire [15:0] addr_i,
input wire [15:0] wdata_i,
input wire [15:0] rdata_i,
input wire rw_i,
input wire valid_i,
// output port
output reg [15:0] addr_o,
output reg [15:0] wdata_o,
output reg [15:0] rdata_o,
output reg rw_o,
output reg valid_o,
// BRAM itself
input wire user_clk,
input wire [ADDR_WIDTH-1:0] user_addr,
input wire [BRAM_WIDTH-1:0] user_din,
output reg [BRAM_WIDTH-1:0] user_dout,
input wire user_we);
parameter BASE_ADDR = 0;
parameter BRAM_WIDTH = 0;
parameter BRAM_DEPTH = 0;
localparam ADDR_WIDTH = $clog2(BRAM_DEPTH);
// ugly typecasting, but just computes ceil(BRAM_WIDTH / 16)
localparam N_BRAMS = int'($ceil(real'(BRAM_WIDTH) / 16.0));
localparam MAX_ADDR = BASE_ADDR + (BRAM_DEPTH * N_BRAMS);
// Port A of BRAMs
reg [N_BRAMS-1:0][ADDR_WIDTH-1:0] addra = 0;
reg [N_BRAMS-1:0][15:0] dina = 0;
reg [N_BRAMS-1:0][15:0] douta;
reg [N_BRAMS-1:0] wea = 0;
// Port B of BRAMs
reg [N_BRAMS-1:0][15:0] dinb;
reg [N_BRAMS-1:0][15:0] doutb;
assign dinb = user_din;
// kind of a hack to part select from a 2d array that's been flattened to 1d
reg [(N_BRAMS*16)-1:0] doutb_flattened;
assign doutb_flattened = doutb;
assign user_dout = doutb_flattened[BRAM_WIDTH-1:0];
// Pipelining
reg [3:0][15:0] addr_pipe = 0;
reg [3:0][15:0] wdata_pipe = 0;
reg [3:0][15:0] rdata_pipe = 0;
reg [3:0] valid_pipe = 0;
reg [3:0] rw_pipe = 0;
always @(posedge clk) begin
addr_pipe[0] <= addr_i;
wdata_pipe[0] <= wdata_i;
rdata_pipe[0] <= rdata_i;
valid_pipe[0] <= valid_i;
rw_pipe[0] <= rw_i;
addr_o <= addr_pipe[2];
wdata_o <= wdata_pipe[2];
rdata_o <= rdata_pipe[2];
valid_o <= valid_pipe[2];
rw_o <= rw_pipe[2];
for(int i=1; i<4; i=i+1) begin
addr_pipe[i] <= addr_pipe[i-1];
wdata_pipe[i] <= wdata_pipe[i-1];
rdata_pipe[i] <= rdata_pipe[i-1];
valid_pipe[i] <= valid_pipe[i-1];
rw_pipe[i] <= rw_pipe[i-1];
end
// throw BRAM operations into the front of the pipeline
wea <= 0;
if( (valid_i) && (addr_i >= BASE_ADDR) && (addr_i <= MAX_ADDR)) begin
wea[addr_i % N_BRAMS] <= rw_i;
addra[addr_i % N_BRAMS] <= (addr_i - BASE_ADDR) / N_BRAMS;
dina[addr_i % N_BRAMS] <= wdata_i;
end
// pull BRAM reads from the back of the pipeline
if( (valid_pipe[2]) && (addr_pipe[2] >= BASE_ADDR) && (addr_pipe[2] <= MAX_ADDR)) begin
rdata_o <= douta[addr_pipe[2] % N_BRAMS];
end
end
// generate the BRAMs
genvar i;
generate
for(i=0; i<N_BRAMS; i=i+1) begin
dual_port_bram #(
.RAM_WIDTH(16),
.RAM_DEPTH(BRAM_DEPTH)
) bram_full_width_i (
// port A is controlled by the bus
.clka(clk),
.addra(addra[i]),
.dina(dina[i]),
.douta(douta[i]),
.wea(wea[i]),
// port B is exposed to the user
.clkb(user_clk),
.addrb(user_addr),
.dinb(dinb[i]),
.doutb(doutb[i]),
.web(user_we));
end
endgenerate
endmodule

View File

@ -1,9 +0,0 @@
from manta import Manta
m = Manta('manta.yaml')
bram_def = m.my_bram.hdl_def()
with open("block_memory.v", "w") as f:
f.write(bram_def)
print(m.my_bram.hdl_top_level_ports())

View File

@ -1,11 +0,0 @@
---
cores:
my_bram:
type: block_memory
width: 18
depth: 256
uart:
port: "auto"
baudrate: 115200
clock_freq: 100000000