add boilerplate for new modules - just gotta rewrite the fsm
This commit is contained in:
parent
4d2c3d08e6
commit
bdca8e01e7
5
Makefile
5
Makefile
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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())
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
cores:
|
||||
my_bram:
|
||||
type: block_memory
|
||||
width: 18
|
||||
depth: 256
|
||||
|
||||
uart:
|
||||
port: "auto"
|
||||
baudrate: 115200
|
||||
clock_freq: 100000000
|
||||
Loading…
Reference in New Issue