modify sim and generator, seems to work in simulation
This commit is contained in:
parent
518f49cc29
commit
a2ad90a66a
5
Makefile
5
Makefile
|
|
@ -44,11 +44,10 @@ io_core_tb:
|
|||
rm sim.out
|
||||
|
||||
logic_analyzer_tb:
|
||||
cd test/functional_sim/logic_analyzer_tb && python3 gen_logic_analyzer.py
|
||||
iverilog -g2012 -o sim.out -y src/manta \
|
||||
test/functional_sim/logic_analyzer_tb/logic_analyzer_tb.sv \
|
||||
test/functional_sim/logic_analyzer_tb/logic_analyzer.v \
|
||||
test/functional_sim/logic_analyzer_tb/sample_mem.v \
|
||||
test/functional_sim/logic_analyzer_tb/trigger_block.v
|
||||
test/functional_sim/logic_analyzer_tb/logic_analyzer.v
|
||||
vvp sim.out
|
||||
rm sim.out
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,5 @@
|
|||
import pkgutil
|
||||
import math
|
||||
from sys import argv
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
|
@ -428,14 +429,14 @@ class LogicAnalyzerCore:
|
|||
self.triggers = config["triggers"]
|
||||
|
||||
|
||||
# compute addresses
|
||||
# - need 3 addresses for configuration (state, current_loc, trigger_loc)
|
||||
# and 2 address for each trigger (operation and argument)
|
||||
|
||||
# compute base addresses
|
||||
self.fsm_base_addr = self.base_addr
|
||||
self.trigger_block_base_addr = self.fsm_base_addr + 3
|
||||
self.sample_mem_base_addr = self.trigger_block_base_addr + (2*len(self.probes))
|
||||
self.max_addr = self.sample_mem_base_addr + self.sample_depth
|
||||
self.trigger_block_base_addr = self.fsm_base_addr + 6
|
||||
|
||||
self.total_probe_width = sum(self.probes.values())
|
||||
n_brams = math.ceil(self.total_probe_width / 16)
|
||||
self.block_memory_base_addr = self.trigger_block_base_addr + (2*len(self.probes))
|
||||
self.max_addr = self.block_memory_base_addr + (n_brams * self.sample_depth)
|
||||
|
||||
def hdl_inst(self):
|
||||
la_inst = VerilogManipulator("logic_analyzer_inst_tmpl.v")
|
||||
|
|
@ -514,29 +515,6 @@ class LogicAnalyzerCore:
|
|||
|
||||
return trigger_block.get_hdl()
|
||||
|
||||
def gen_sample_mem_def(self):
|
||||
sample_mem = VerilogManipulator("sample_mem_def_tmpl.v")
|
||||
|
||||
# add probe ports to module declaration
|
||||
# - these are the ports that belong to the logic analyzer, but
|
||||
# need to be included in the trigger_block module declaration
|
||||
probe_ports = sample_mem.net_dec(self.probes, "input wire", trailing_comma=True)
|
||||
sample_mem.sub(probe_ports, "/* PROBE_PORTS */")
|
||||
|
||||
# concatenate probes to BRAM input
|
||||
total_probe_width = sum([width for name, width in self.probes.items()])
|
||||
|
||||
if total_probe_width > 16:
|
||||
# TODO: implement > 16 bit addressing
|
||||
raise NotImplementedError("ummm i'm getting around to it calm down calm down")
|
||||
|
||||
zero_pad_width = 16 - total_probe_width
|
||||
concat = ", ".join([name for name in self.probes])
|
||||
concat = f"{{{zero_pad_width}'b0, {concat}}}"
|
||||
|
||||
sample_mem.sub(concat, "/* CONCAT */")
|
||||
return sample_mem.get_hdl()
|
||||
|
||||
def gen_logic_analyzer_def(self):
|
||||
la = VerilogManipulator("logic_analyzer_def_tmpl.v")
|
||||
|
||||
|
|
@ -547,7 +525,7 @@ class LogicAnalyzerCore:
|
|||
# assign base addresses to the FSM, trigger block, and sample mem
|
||||
la.sub(self.fsm_base_addr, "/* FSM_BASE_ADDR */")
|
||||
la.sub(self.trigger_block_base_addr, "/* TRIGGER_BLOCK_BASE_ADDR */")
|
||||
la.sub(self.sample_mem_base_addr, "/* SAMPLE_MEM_BASE_ADDR */")
|
||||
la.sub(self.block_memory_base_addr, "/* BLOCK_MEMORY_BASE_ADDR */")
|
||||
|
||||
# set sample depth
|
||||
la.sub(self.sample_depth, "/* SAMPLE_DEPTH */")
|
||||
|
|
@ -555,21 +533,25 @@ class LogicAnalyzerCore:
|
|||
# set probe ports for the trigger block and sample mem
|
||||
probe_ports = la.net_conn(self.probes, trailing_comma=True)
|
||||
la.sub(probe_ports, "/* TRIGGER_BLOCK_PROBE_PORTS */")
|
||||
la.sub(probe_ports, "/* SAMPLE_MEM_PROBE_PORTS */")
|
||||
|
||||
la.sub(self.total_probe_width, "/* TOTAL_PROBE_WIDTH */")
|
||||
|
||||
probes_concat = '{' + ', '.join(self.probes.keys()) + '}'
|
||||
la.sub(probes_concat, "/* PROBES_CONCAT */")
|
||||
|
||||
return la.get_hdl()
|
||||
|
||||
def hdl_def(self):
|
||||
# Return an autogenerated verilog module definition for the core.
|
||||
# load source files
|
||||
la_fsm = VerilogManipulator("la_fsm.v").get_hdl()
|
||||
dual_port_bram = VerilogManipulator("dual_port_bram.v").get_hdl()
|
||||
trigger = VerilogManipulator("trigger.v").get_hdl()
|
||||
trigger_block = self.gen_trigger_block_def()
|
||||
sample_mem = self.gen_sample_mem_def()
|
||||
logic_analyzer = self.gen_logic_analyzer_def()
|
||||
hdl = self.gen_logic_analyzer_def() + "\n"
|
||||
hdl += VerilogManipulator("logic_analyzer_controller.v").get_hdl() + "\n"
|
||||
hdl += VerilogManipulator("block_memory.v").get_hdl() + "\n"
|
||||
hdl += VerilogManipulator("dual_port_bram.v").get_hdl() + "\n"
|
||||
hdl += self.gen_trigger_block_def() + "\n"
|
||||
hdl += VerilogManipulator("trigger.v").get_hdl() + "\n"
|
||||
|
||||
return logic_analyzer + la_fsm + sample_mem + dual_port_bram + trigger_block + trigger
|
||||
return hdl
|
||||
|
||||
def hdl_top_level_ports(self):
|
||||
# the probes that we want as ports on the top-level manta module
|
||||
|
|
@ -677,9 +659,8 @@ class BlockMemoryCore:
|
|||
assert isinstance(config["width"], int), "Block Memory core must have integer width."
|
||||
self.width = config["width"]
|
||||
|
||||
from math import ceil, floor, log2
|
||||
self.addr_width = ceil(log2(self.depth))
|
||||
self.n_brams = ceil(self.width / 16)
|
||||
self.addr_width = math.ceil(math.log2(self.depth))
|
||||
self.n_brams = math.ceil(self.width / 16)
|
||||
self.max_addr = self.base_addr + (self.depth * self.n_brams)
|
||||
|
||||
def hdl_inst(self):
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ module logic_analyzer_controller (
|
|||
output reg signed [15:0] current_loc,
|
||||
input wire request_start,
|
||||
input wire request_stop,
|
||||
output reg read_pointer,
|
||||
output reg [ADDR_WIDTH-1:0] read_pointer,
|
||||
|
||||
// from trigger block
|
||||
input wire trig,
|
||||
|
|
@ -20,8 +20,11 @@ module logic_analyzer_controller (
|
|||
output bram_we
|
||||
);
|
||||
|
||||
parameter DEPTH = 0;
|
||||
localparam ADDR_WIDTH = $clog2(DEPTH);
|
||||
assign bram_addr = write_pointer;
|
||||
assign bram_we = acquire;
|
||||
|
||||
parameter SAMPLE_DEPTH= 0;
|
||||
localparam ADDR_WIDTH = $clog2(SAMPLE_DEPTH);
|
||||
|
||||
/* ----- FSM ----- */
|
||||
localparam IDLE = 0;
|
||||
|
|
@ -53,17 +56,18 @@ module logic_analyzer_controller (
|
|||
// go into MOVE_TO_POSITION or IN_POSITION. that's for
|
||||
// the morning
|
||||
state <= MOVE_TO_POSITION;
|
||||
clear <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
if(state == MOVE_TO_POSITION) begin
|
||||
else if(state == MOVE_TO_POSITION) begin
|
||||
acquire <= 1;
|
||||
current_loc <= current_loc + 1;
|
||||
|
||||
if(current_loc == trigger_loc) state <= IN_POSITION
|
||||
if(current_loc == trigger_loc) state <= IN_POSITION;
|
||||
end
|
||||
|
||||
if(state == IN_POSITION) begin
|
||||
else if(state == IN_POSITION) begin
|
||||
acquire <= 1;
|
||||
pop <= 1;
|
||||
|
||||
|
|
@ -71,25 +75,30 @@ module logic_analyzer_controller (
|
|||
if(trig) state <= CAPTURING;
|
||||
end
|
||||
|
||||
if(state == CAPTURING) begin
|
||||
if(size == DEPTH) state <= CAPTURED;
|
||||
else if(state == CAPTURING) begin
|
||||
acquire <= 1;
|
||||
|
||||
if(size == SAMPLE_DEPTH) begin
|
||||
state <= CAPTURED;
|
||||
acquire <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
if(state == CAPTURED) begin
|
||||
else if(state == CAPTURED) begin
|
||||
// actually nothing to do here doooodeeedoooo
|
||||
end
|
||||
|
||||
if(request_stop && ~prev_request_stop) state <= IDLE;
|
||||
else if(request_stop && ~prev_request_stop) state <= IDLE;
|
||||
|
||||
else state <= IDLE;
|
||||
end
|
||||
|
||||
|
||||
// fifo
|
||||
/* ----- FIFO ----- */
|
||||
reg acquire;
|
||||
reg pop;
|
||||
reg [ADDR_WIDTH:0] size,
|
||||
reg clear,
|
||||
reg [ADDR_WIDTH:0] size;
|
||||
reg clear;
|
||||
|
||||
reg [ADDR_WIDTH:0] write_pointer = 0;
|
||||
initial read_pointer = 0;
|
||||
|
|
@ -99,7 +108,7 @@ module logic_analyzer_controller (
|
|||
|
||||
always @(posedge clk) begin
|
||||
if (clear) read_pointer <= write_pointer;
|
||||
if (acquire && size < DEPTH) write_pointer <= write_pointer + 1'd1;
|
||||
if (acquire && size < SAMPLE_DEPTH) write_pointer <= write_pointer + 1'd1;
|
||||
if (pop && size > 0) read_pointer <= read_pointer + 1'd1;
|
||||
end
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@ module logic_analyzer (
|
|||
output reg rw_o,
|
||||
output reg valid_o
|
||||
);
|
||||
|
||||
parameter SAMPLE_DEPTH = 0;
|
||||
localparam SAMPLE_DEPTH = /* SAMPLE_DEPTH */;
|
||||
localparam ADDR_WIDTH = $clog2(SAMPLE_DEPTH);
|
||||
|
||||
reg [3:0] state;
|
||||
|
|
@ -37,11 +36,11 @@ module logic_analyzer (
|
|||
reg [ADDR_WIDTH-1:0] bram_addr;
|
||||
reg bram_we;
|
||||
|
||||
localparam TOTAL_PROBE_WIDTH = 0;
|
||||
localparam TOTAL_PROBE_WIDTH = /* TOTAL_PROBE_WIDTH */;
|
||||
reg [TOTAL_PROBE_WIDTH-1:0] probes_concat;
|
||||
assign probes_concat = /* PROBES_CONCAT */;
|
||||
|
||||
logic_analyzer_controller la_controller (
|
||||
logic_analyzer_controller #(.SAMPLE_DEPTH(SAMPLE_DEPTH)) la_controller (
|
||||
.clk(clk),
|
||||
|
||||
// from register file
|
||||
|
|
@ -61,7 +60,8 @@ module logic_analyzer (
|
|||
);
|
||||
|
||||
logic_analyzer_fsm_registers #(
|
||||
.BASE_ADDR(/* FSM_BASE_ADDR */)
|
||||
.BASE_ADDR(/* FSM_BASE_ADDR */),
|
||||
.SAMPLE_DEPTH(SAMPLE_DEPTH)
|
||||
) fsm_registers (
|
||||
.clk(clk),
|
||||
|
||||
|
|
@ -90,8 +90,6 @@ module logic_analyzer (
|
|||
reg fsm_reg_trig_blk_rw;
|
||||
reg fsm_reg_trig_blk_valid;
|
||||
|
||||
reg trig;
|
||||
|
||||
// trigger block
|
||||
trigger_block #(.BASE_ADDR(/* TRIGGER_BLOCK_BASE_ADDR */)) trig_blk (
|
||||
.clk(clk),
|
||||
|
|
@ -120,9 +118,9 @@ module logic_analyzer (
|
|||
|
||||
// sample memory
|
||||
block_memory #(
|
||||
.BASE_ADDR(/* SAMPLE_MEM_BASE_ADDR */),
|
||||
.WIDTH(),
|
||||
.DEPTH(/* SAMPLE_DEPTH */)
|
||||
.BASE_ADDR(/* BLOCK_MEMORY_BASE_ADDR */),
|
||||
.WIDTH(TOTAL_PROBE_WIDTH),
|
||||
.DEPTH(SAMPLE_DEPTH)
|
||||
) block_mem (
|
||||
.clk(clk),
|
||||
|
||||
|
|
|
|||
|
|
@ -24,11 +24,17 @@ module logic_analyzer_fsm_registers(
|
|||
input wire signed [15:0] current_loc,
|
||||
output reg request_start,
|
||||
output reg request_stop,
|
||||
input wire [15:0] read_pointer
|
||||
input wire [ADDR_WIDTH-1:0] read_pointer
|
||||
);
|
||||
|
||||
initial trigger_loc = 0;
|
||||
initial request_start = 0;
|
||||
initial request_stop = 0;
|
||||
|
||||
parameter BASE_ADDR = 0;
|
||||
localparam MAX_ADDR = BASE_ADDR + 5;
|
||||
parameter SAMPLE_DEPTH = 0;
|
||||
parameter ADDR_WIDTH = $clog2(SAMPLE_DEPTH);
|
||||
|
||||
always @(posedge clk) begin
|
||||
addr_o <= addr_i;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
from manta import Manta
|
||||
|
||||
m = Manta('manta.yaml')
|
||||
la = m.my_logic_analyzer.hdl_def()
|
||||
|
||||
with open('logic_analyzer.v', 'w') as f:
|
||||
f.write(la)
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
`default_nettype none
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module logic_analyzer(
|
||||
module logic_analyzer (
|
||||
input wire clk,
|
||||
|
||||
// probes
|
||||
|
|
@ -24,19 +21,49 @@ module logic_analyzer(
|
|||
output reg rw_o,
|
||||
output reg valid_o
|
||||
);
|
||||
localparam SAMPLE_DEPTH = 128;
|
||||
localparam ADDR_WIDTH = $clog2(SAMPLE_DEPTH);
|
||||
|
||||
parameter BASE_ADDR = 0;
|
||||
parameter SAMPLE_DEPTH = 0;
|
||||
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;
|
||||
|
||||
// fsm
|
||||
la_fsm #(.BASE_ADDR(BASE_ADDR), .SAMPLE_DEPTH(SAMPLE_DEPTH)) fsm (
|
||||
reg trig;
|
||||
|
||||
reg [ADDR_WIDTH-1:0] bram_addr;
|
||||
reg bram_we;
|
||||
|
||||
localparam TOTAL_PROBE_WIDTH = 7;
|
||||
reg [TOTAL_PROBE_WIDTH-1:0] probes_concat;
|
||||
assign probes_concat = {larry, curly, moe, shemp};
|
||||
|
||||
logic_analyzer_controller #(.SAMPLE_DEPTH(SAMPLE_DEPTH)) 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(0),
|
||||
.SAMPLE_DEPTH(SAMPLE_DEPTH)
|
||||
) fsm_registers (
|
||||
.clk(clk),
|
||||
|
||||
.addr_i(addr_i),
|
||||
.wdata_i(wdata_i),
|
||||
|
|
@ -44,27 +71,27 @@ 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;
|
||||
|
||||
reg trig;
|
||||
reg [$clog2(SAMPLE_DEPTH):0] fifo_size;
|
||||
reg fifo_acquire;
|
||||
reg fifo_pop;
|
||||
reg fifo_clear;
|
||||
.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;
|
||||
|
||||
// trigger block
|
||||
trigger_block #(.BASE_ADDR(BASE_ADDR + 3)) trig_blk(
|
||||
trigger_block #(.BASE_ADDR(6)) trig_blk (
|
||||
.clk(clk),
|
||||
|
||||
.larry(larry),
|
||||
|
|
@ -74,53 +101,497 @@ 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 #(.BASE_ADDR(BASE_ADDR + 11), .SAMPLE_DEPTH(SAMPLE_DEPTH)) sample_mem(
|
||||
block_memory #(
|
||||
.BASE_ADDR(14),
|
||||
.WIDTH(TOTAL_PROBE_WIDTH),
|
||||
.DEPTH(SAMPLE_DEPTH)
|
||||
) block_mem (
|
||||
.clk(clk),
|
||||
|
||||
// fifo
|
||||
.acquire(fifo_acquire),
|
||||
.pop(fifo_pop),
|
||||
.size(fifo_size),
|
||||
.clear(fifo_clear),
|
||||
|
||||
// probes
|
||||
.larry(larry),
|
||||
.curly(curly),
|
||||
.moe(moe),
|
||||
.shemp(shemp),
|
||||
|
||||
// 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));
|
||||
endmodule
|
||||
.valid_o(valid_o),
|
||||
|
||||
`default_nettype wire
|
||||
// BRAM itself
|
||||
.user_clk(clk),
|
||||
.user_addr(bram_addr),
|
||||
.user_din(probes_concat),
|
||||
.user_dout(),
|
||||
.user_we(bram_we));
|
||||
endmodule
|
||||
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 [ADDR_WIDTH-1:0] read_pointer,
|
||||
|
||||
// from trigger block
|
||||
input wire trig,
|
||||
|
||||
// block memory user port
|
||||
output [ADDR_WIDTH-1:0] bram_addr,
|
||||
output bram_we
|
||||
);
|
||||
|
||||
assign bram_addr = write_pointer;
|
||||
assign bram_we = acquire;
|
||||
|
||||
parameter SAMPLE_DEPTH= 0;
|
||||
localparam ADDR_WIDTH = $clog2(SAMPLE_DEPTH);
|
||||
|
||||
/* ----- FSM ----- */
|
||||
localparam IDLE = 0;
|
||||
localparam MOVE_TO_POSITION = 1;
|
||||
localparam IN_POSITION = 2;
|
||||
localparam CAPTURING = 3;
|
||||
localparam CAPTURED = 4;
|
||||
|
||||
initial state = IDLE;
|
||||
initial current_loc = 0;
|
||||
|
||||
// rising edge detection for start/stop requests
|
||||
reg prev_request_start;
|
||||
always @(posedge clk) prev_request_start <= request_start;
|
||||
|
||||
reg prev_request_stop;
|
||||
always @(posedge clk) prev_request_stop <= request_stop;
|
||||
|
||||
always @(posedge clk) begin
|
||||
// don't do anything to the FIFO unless told to
|
||||
acquire <= 0;
|
||||
pop <= 0;
|
||||
|
||||
if(state == IDLE) begin
|
||||
clear <= 1;
|
||||
|
||||
if(request_start && ~prev_request_start) begin
|
||||
// TODO: figure out what determines whether or not we
|
||||
// go into MOVE_TO_POSITION or IN_POSITION. that's for
|
||||
// the morning
|
||||
state <= MOVE_TO_POSITION;
|
||||
clear <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
else if(state == MOVE_TO_POSITION) begin
|
||||
acquire <= 1;
|
||||
current_loc <= current_loc + 1;
|
||||
|
||||
if(current_loc == trigger_loc) state <= IN_POSITION;
|
||||
end
|
||||
|
||||
else if(state == IN_POSITION) begin
|
||||
acquire <= 1;
|
||||
pop <= 1;
|
||||
|
||||
if(trig) pop <= 0;
|
||||
if(trig) state <= CAPTURING;
|
||||
end
|
||||
|
||||
else if(state == CAPTURING) begin
|
||||
acquire <= 1;
|
||||
|
||||
if(size == SAMPLE_DEPTH) begin
|
||||
state <= CAPTURED;
|
||||
acquire <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
else if(state == CAPTURED) begin
|
||||
// actually nothing to do here doooodeeedoooo
|
||||
end
|
||||
|
||||
else if(request_stop && ~prev_request_stop) state <= IDLE;
|
||||
|
||||
else state <= IDLE;
|
||||
end
|
||||
|
||||
|
||||
/* ----- FIFO ----- */
|
||||
reg acquire;
|
||||
reg pop;
|
||||
reg [ADDR_WIDTH:0] size;
|
||||
reg clear;
|
||||
|
||||
reg [ADDR_WIDTH:0] write_pointer = 0;
|
||||
initial read_pointer = 0;
|
||||
initial write_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
|
||||
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 [WIDTH-1:0] user_din,
|
||||
output reg [WIDTH-1:0] user_dout,
|
||||
input wire user_we);
|
||||
|
||||
parameter BASE_ADDR = 0;
|
||||
parameter WIDTH = 0;
|
||||
parameter DEPTH = 0;
|
||||
localparam ADDR_WIDTH = $clog2(DEPTH);
|
||||
|
||||
// ugly typecasting, but just computes ceil(WIDTH / 16)
|
||||
localparam N_BRAMS = int'($ceil(real'(WIDTH) / 16.0));
|
||||
localparam MAX_ADDR = BASE_ADDR + (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[WIDTH-1:0];
|
||||
|
||||
// Pipelining
|
||||
reg [2:0][15:0] addr_pipe = 0;
|
||||
reg [2:0][15:0] wdata_pipe = 0;
|
||||
reg [2:0][15:0] rdata_pipe = 0;
|
||||
reg [2:0] valid_pipe = 0;
|
||||
reg [2: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<3; 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(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
|
||||
// Xilinx True Dual Port RAM, Read First, Dual Clock
|
||||
// This code implements a parameterizable true dual port memory (both ports can read and write).
|
||||
// The behavior of this RAM is when data is written, the prior memory contents at the write
|
||||
// address are presented on the output port. If the output data is
|
||||
// not needed during writes or the last read value is desired to be retained,
|
||||
// it is suggested to use a no change RAM as it is more power efficient.
|
||||
// If a reset or enable is not necessary, it may be tied off or removed from the code.
|
||||
|
||||
// Modified from the xilinx_true_dual_port_read_first_2_clock_ram verilog language template.
|
||||
|
||||
module dual_port_bram #(
|
||||
parameter RAM_WIDTH = 0,
|
||||
parameter RAM_DEPTH = 0
|
||||
) (
|
||||
input wire [$clog2(RAM_DEPTH-1)-1:0] addra,
|
||||
input wire [$clog2(RAM_DEPTH-1)-1:0] addrb,
|
||||
input wire [RAM_WIDTH-1:0] dina,
|
||||
input wire [RAM_WIDTH-1:0] dinb,
|
||||
input wire clka,
|
||||
input wire clkb,
|
||||
input wire wea,
|
||||
input wire web,
|
||||
output wire [RAM_WIDTH-1:0] douta,
|
||||
output wire [RAM_WIDTH-1:0] doutb
|
||||
);
|
||||
|
||||
// The following code either initializes the memory values to a specified file or to all zeros to match hardware
|
||||
generate
|
||||
integer i;
|
||||
initial begin
|
||||
for (i = 0; i < RAM_DEPTH; i = i + 1)
|
||||
BRAM[i] = {RAM_WIDTH{1'b0}};
|
||||
end
|
||||
endgenerate
|
||||
|
||||
reg [RAM_WIDTH-1:0] BRAM [RAM_DEPTH-1:0];
|
||||
reg [RAM_WIDTH-1:0] ram_data_a = {RAM_WIDTH{1'b0}};
|
||||
reg [RAM_WIDTH-1:0] ram_data_b = {RAM_WIDTH{1'b0}};
|
||||
|
||||
always @(posedge clka) begin
|
||||
if (wea) BRAM[addra] <= dina;
|
||||
ram_data_a <= BRAM[addra];
|
||||
end
|
||||
|
||||
always @(posedge clkb) begin
|
||||
if (web) BRAM[addrb] <= dinb;
|
||||
ram_data_b <= BRAM[addrb];
|
||||
end
|
||||
|
||||
// Add a 2 clock cycle read latency to improve clock-to-out timing
|
||||
reg [RAM_WIDTH-1:0] douta_reg = {RAM_WIDTH{1'b0}};
|
||||
reg [RAM_WIDTH-1:0] doutb_reg = {RAM_WIDTH{1'b0}};
|
||||
|
||||
always @(posedge clka) douta_reg <= ram_data_a;
|
||||
always @(posedge clkb) doutb_reg <= ram_data_b;
|
||||
|
||||
assign douta = douta_reg;
|
||||
assign doutb = doutb_reg;
|
||||
endmodule
|
||||
module trigger_block (
|
||||
input wire clk,
|
||||
|
||||
// probes
|
||||
input wire larry,
|
||||
input wire curly,
|
||||
input wire moe,
|
||||
input wire [3:0] shemp,
|
||||
|
||||
// trigger
|
||||
output reg trig,
|
||||
|
||||
// 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;
|
||||
localparam MAX_ADDR = 7;
|
||||
|
||||
// trigger configuration registers
|
||||
// - each probe gets an operation and a compare register
|
||||
// - at the end we OR them all together. along with any custom probes the user specs
|
||||
|
||||
reg [3:0] larry_op = 0;
|
||||
reg larry_arg = 0;
|
||||
reg larry_trig;
|
||||
|
||||
trigger #(.INPUT_WIDTH(1)) larry_trigger (
|
||||
.clk(clk),
|
||||
|
||||
.probe(larry),
|
||||
.op(larry_op),
|
||||
.arg(larry_arg),
|
||||
.trig(larry_trig));
|
||||
reg [3:0] curly_op = 0;
|
||||
reg curly_arg = 0;
|
||||
reg curly_trig;
|
||||
|
||||
trigger #(.INPUT_WIDTH(1)) curly_trigger (
|
||||
.clk(clk),
|
||||
|
||||
.probe(curly),
|
||||
.op(curly_op),
|
||||
.arg(curly_arg),
|
||||
.trig(curly_trig));
|
||||
reg [3:0] moe_op = 0;
|
||||
reg moe_arg = 0;
|
||||
reg moe_trig;
|
||||
|
||||
trigger #(.INPUT_WIDTH(1)) moe_trigger (
|
||||
.clk(clk),
|
||||
|
||||
.probe(moe),
|
||||
.op(moe_op),
|
||||
.arg(moe_arg),
|
||||
.trig(moe_trig));
|
||||
reg [3:0] shemp_op = 0;
|
||||
reg [3:0] shemp_arg = 0;
|
||||
reg shemp_trig;
|
||||
|
||||
trigger #(.INPUT_WIDTH(4)) shemp_trigger (
|
||||
.clk(clk),
|
||||
|
||||
.probe(shemp),
|
||||
.op(shemp_op),
|
||||
.arg(shemp_arg),
|
||||
.trig(shemp_trig));
|
||||
|
||||
assign trig = larry_trig || curly_trig || moe_trig || shemp_trig;
|
||||
|
||||
// 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;
|
||||
rdata_o <= rdata_i;
|
||||
|
||||
if( (addr_i >= BASE_ADDR) && (addr_i <= BASE_ADDR + MAX_ADDR) ) begin
|
||||
|
||||
// reads
|
||||
if(valid_i && !rw_i) begin
|
||||
case (addr_i)
|
||||
BASE_ADDR + 0: rdata_o <= larry_op;
|
||||
BASE_ADDR + 1: rdata_o <= larry_arg;
|
||||
BASE_ADDR + 2: rdata_o <= curly_op;
|
||||
BASE_ADDR + 3: rdata_o <= curly_arg;
|
||||
BASE_ADDR + 4: rdata_o <= moe_op;
|
||||
BASE_ADDR + 5: rdata_o <= moe_arg;
|
||||
BASE_ADDR + 6: rdata_o <= shemp_op;
|
||||
BASE_ADDR + 7: rdata_o <= shemp_arg;
|
||||
endcase
|
||||
end
|
||||
|
||||
// writes
|
||||
else if(valid_i && rw_i) begin
|
||||
case (addr_i)
|
||||
BASE_ADDR + 0: larry_op <= wdata_i;
|
||||
BASE_ADDR + 1: larry_arg <= wdata_i;
|
||||
BASE_ADDR + 2: curly_op <= wdata_i;
|
||||
BASE_ADDR + 3: curly_arg <= wdata_i;
|
||||
BASE_ADDR + 4: moe_op <= wdata_i;
|
||||
BASE_ADDR + 5: moe_arg <= wdata_i;
|
||||
BASE_ADDR + 6: shemp_op <= wdata_i;
|
||||
BASE_ADDR + 7: shemp_arg <= wdata_i;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
module trigger (
|
||||
input wire clk,
|
||||
|
||||
input wire [INPUT_WIDTH-1:0] probe,
|
||||
input wire [3:0] op,
|
||||
input wire [INPUT_WIDTH-1:0] arg,
|
||||
|
||||
output reg trig);
|
||||
|
||||
parameter INPUT_WIDTH = 0;
|
||||
|
||||
localparam DISABLE = 0;
|
||||
localparam RISING = 1;
|
||||
localparam FALLING = 2;
|
||||
localparam CHANGING = 3;
|
||||
localparam GT = 4;
|
||||
localparam LT = 5;
|
||||
localparam GEQ = 6;
|
||||
localparam LEQ = 7;
|
||||
localparam EQ = 8;
|
||||
localparam NEQ = 9;
|
||||
|
||||
reg [INPUT_WIDTH-1:0] probe_prev = 0;
|
||||
always @(posedge clk) probe_prev <= probe;
|
||||
|
||||
always @(*) begin
|
||||
case (op)
|
||||
RISING : trig = (probe > probe_prev);
|
||||
FALLING : trig = (probe < probe_prev);
|
||||
CHANGING : trig = (probe != probe_prev);
|
||||
GT: trig = (probe > arg);
|
||||
LT: trig = (probe < arg);
|
||||
GEQ: trig = (probe >= arg);
|
||||
LEQ: trig = (probe <= arg);
|
||||
EQ: trig = (probe == arg);
|
||||
NEQ: trig = (probe != arg);
|
||||
default: trig = 0;
|
||||
endcase
|
||||
end
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -51,13 +51,12 @@ task write_and_verify(
|
|||
endtask
|
||||
|
||||
task read_all_reg();
|
||||
|
||||
string desc;
|
||||
for(int i = 0; i < (logic_analyzer_tb.la.sample_mem.BASE_ADDR + logic_analyzer_tb.la.SAMPLE_DEPTH); i++) begin
|
||||
for(int i = 0; i < (logic_analyzer_tb.la.block_mem.MAX_ADDR); i++) begin
|
||||
|
||||
if(i == logic_analyzer_tb.la.fsm.BASE_ADDR) desc = "FSM";
|
||||
if(i == logic_analyzer_tb.la.fsm_registers.BASE_ADDR) desc = "FSM";
|
||||
if(i == logic_analyzer_tb.la.trig_blk.BASE_ADDR) desc = "TRIG BLK";
|
||||
if(i == logic_analyzer_tb.la.sample_mem.BASE_ADDR) desc = "SAMPLE MEM";
|
||||
if(i == logic_analyzer_tb.la.block_mem.BASE_ADDR) desc = "SAMPLE MEM";
|
||||
|
||||
read_reg(i, logic_analyzer_tb.read_value, desc);
|
||||
end
|
||||
|
|
@ -90,7 +89,7 @@ module logic_analyzer_tb;
|
|||
logic la_tb_valid;
|
||||
|
||||
|
||||
logic_analyzer #(.BASE_ADDR(0), .SAMPLE_DEPTH(128)) la(
|
||||
logic_analyzer la(
|
||||
.clk(clk),
|
||||
|
||||
// probes
|
||||
|
|
@ -141,127 +140,77 @@ module logic_analyzer_tb;
|
|||
#`HCP
|
||||
#(10*`CP);
|
||||
|
||||
/* ==== Test 1 Begin ==== */
|
||||
$display("\n=== test 1: read/write to FSM registers, verify ===");
|
||||
test_num = 1;
|
||||
|
||||
// state register
|
||||
write_and_verify(0, la.fsm.IDLE, "state reg");
|
||||
write_and_verify(0, la.fsm.FILLED, "state reg");
|
||||
write_and_verify(0, la.fsm.IDLE, "state reg");
|
||||
// /* ==== Test 2 Begin ==== */
|
||||
// $display("\n=== test 2: read/write to trigger block registers, verify ===");
|
||||
// test_num = 2;
|
||||
|
||||
// trigger_loc register
|
||||
write_and_verify(1, 0, "trigger_loc reg");
|
||||
write_and_verify(1, 'h69, "trigger_loc reg");
|
||||
write_and_verify(1, 'h0612, "trigger_loc reg");
|
||||
// // larry
|
||||
// write_and_verify(3, 0, "larry_op");
|
||||
// write_and_verify(3, 2, "larry_op");
|
||||
// write_and_verify(3, 0, "larry_op");
|
||||
|
||||
// since we just moved the trigger location, the core has started moving into position
|
||||
// if it's functioning correctly. this means we need to reset the position and state
|
||||
// before testing the present_loc register.
|
||||
// write_and_verify(4, 0, "larry_arg");
|
||||
// write_and_verify(4, 1, "larry_arg");
|
||||
// write_and_verify(4, 0, "larry_arg");
|
||||
|
||||
// write_and_verify(1, 0, "trigger_loc reg");
|
||||
// write_and_verify(0, 0, "state reg");
|
||||
// // curly
|
||||
// write_and_verify(5, 0, "curly_op");
|
||||
// write_and_verify(5, 3, "curly_op");
|
||||
// write_and_verify(5, 0, "curly_op");
|
||||
|
||||
// // present_loc register
|
||||
// write_and_verify(2, 0, "present_loc reg");
|
||||
// write_and_verify(2, 0, "present_loc reg");
|
||||
#(10*`CP);
|
||||
// write_and_verify(6, 0, "curly_arg");
|
||||
// write_and_verify(6, 1, "curly_arg");
|
||||
// write_and_verify(6, 0, "curly_arg");
|
||||
|
||||
/* ==== Test 1 End ==== */
|
||||
// // moe
|
||||
// write_and_verify(7, 0, "moe_op");
|
||||
// write_and_verify(7, 5, "moe_op");
|
||||
// write_and_verify(7, 0, "moe_op");
|
||||
|
||||
// write_and_verify(8, 0, "moe_arg");
|
||||
// write_and_verify(8, 1, "moe_arg");
|
||||
// write_and_verify(8, 0, "moe_arg");
|
||||
|
||||
/* ==== Test 2 Begin ==== */
|
||||
$display("\n=== test 2: read/write to trigger block registers, verify ===");
|
||||
test_num = 2;
|
||||
// // shemp
|
||||
// write_and_verify(9, 0, "shemp_op");
|
||||
// write_and_verify(9, 7, "shemp_op");
|
||||
// write_and_verify(9, 0, "shemp_op");
|
||||
|
||||
// larry
|
||||
write_and_verify(3, 0, "larry_op");
|
||||
write_and_verify(3, 2, "larry_op");
|
||||
write_and_verify(3, 0, "larry_op");
|
||||
// write_and_verify(10, 0, "shemp_arg");
|
||||
// write_and_verify(10, 7, "shemp_arg");
|
||||
// write_and_verify(10, 0, "shemp_arg");
|
||||
|
||||
write_and_verify(4, 0, "larry_arg");
|
||||
write_and_verify(4, 1, "larry_arg");
|
||||
write_and_verify(4, 0, "larry_arg");
|
||||
// #(10*`CP);
|
||||
|
||||
// curly
|
||||
write_and_verify(5, 0, "curly_op");
|
||||
write_and_verify(5, 3, "curly_op");
|
||||
write_and_verify(5, 0, "curly_op");
|
||||
|
||||
write_and_verify(6, 0, "curly_arg");
|
||||
write_and_verify(6, 1, "curly_arg");
|
||||
write_and_verify(6, 0, "curly_arg");
|
||||
|
||||
// moe
|
||||
write_and_verify(7, 0, "moe_op");
|
||||
write_and_verify(7, 5, "moe_op");
|
||||
write_and_verify(7, 0, "moe_op");
|
||||
|
||||
write_and_verify(8, 0, "moe_arg");
|
||||
write_and_verify(8, 1, "moe_arg");
|
||||
write_and_verify(8, 0, "moe_arg");
|
||||
|
||||
// shemp
|
||||
write_and_verify(9, 0, "shemp_op");
|
||||
write_and_verify(9, 7, "shemp_op");
|
||||
write_and_verify(9, 0, "shemp_op");
|
||||
|
||||
write_and_verify(10, 0, "shemp_arg");
|
||||
write_and_verify(10, 7, "shemp_arg");
|
||||
write_and_verify(10, 0, "shemp_arg");
|
||||
|
||||
#(10*`CP);
|
||||
|
||||
/* ==== Test 2 End ==== */
|
||||
|
||||
|
||||
/* ==== Test 3 Begin ==== */
|
||||
$display("\n=== test 3: verify FSM doesn't move out of IDLE when not running ===");
|
||||
test_num = 3;
|
||||
|
||||
write_and_verify(3, 8, "larry_op"); // set operation to eq
|
||||
write_and_verify(4, 1, "larry_arg"); // set argument to 1
|
||||
|
||||
// set larry = 1, verify core doesn't trigger
|
||||
$display(" -> set larry = 1");
|
||||
larry = 1;
|
||||
|
||||
$display(" -> la core is in state 0x%h", la.fsm.state);
|
||||
assert(la.fsm.state == la.fsm.IDLE) else $error("core moved outside of IDLE state when not running!");
|
||||
|
||||
$display(" -> wait a clock cycle");
|
||||
#`CP
|
||||
|
||||
$display(" -> la core is in state 0x%h", la.fsm.state);
|
||||
assert(la.fsm.state == la.fsm.IDLE) else $error("core moved outside of IDLE state when not running!");
|
||||
|
||||
$display(" -> set larry = 0");
|
||||
larry = 0;
|
||||
|
||||
#(10*`CP);
|
||||
/* ==== Test 3 End ==== */
|
||||
// /* ==== Test 2 End ==== */
|
||||
|
||||
|
||||
/* ==== Test 4 Begin ==== */
|
||||
$display("\n=== test 4: verify FSM does move out of IDLE when running ===");
|
||||
test_num = 4;
|
||||
|
||||
$display(" -> moving core to START_CAPTURE");
|
||||
write_reg(0, 1, "state");
|
||||
$display(" -> setting up trigger (larry == 1)");
|
||||
write_reg(la.trig_blk.BASE_ADDR + 0, 8, "larry_op");
|
||||
write_reg(la.trig_blk.BASE_ADDR + 1, 1, "larry_arg");
|
||||
|
||||
$display(" -> requesting start");
|
||||
write_reg(3, 1, "request_start");
|
||||
write_reg(3, 0, "request_start");
|
||||
#`CP
|
||||
|
||||
$display(" -> set larry = 1");
|
||||
larry = 1;
|
||||
|
||||
// read
|
||||
$display(" -> la core is in state 0x%h", la.fsm.state);
|
||||
$display(" -> la core is in state 0x%h", la.fsm_registers.state);
|
||||
$display(" -> wait a clock cycle");
|
||||
#`CP
|
||||
$display(" -> la core is in state 0x%h", la.fsm.state);
|
||||
$display(" -> la core is in state 0x%h", la.fsm_registers.state);
|
||||
|
||||
// run until the FILLED state is reached
|
||||
$display(" -> wait until FILLED state is reached");
|
||||
while (la.fsm.state != la.fsm.FILLED) begin
|
||||
while (la.fsm_registers.state != la.la_controller.CAPTURED) begin
|
||||
{larry, curly, moe, shemp} = {larry, curly, moe, shemp} + 1;
|
||||
#`CP;
|
||||
end
|
||||
|
|
@ -272,38 +221,39 @@ module logic_analyzer_tb;
|
|||
#(200*`CP);
|
||||
/* ==== Test 4 End ==== */
|
||||
|
||||
/* ==== Test 5 Begin ==== */
|
||||
$display("\n=== test 5: change trigger to fire on shemp > 3, and verify ===");
|
||||
test_num = 5;
|
||||
// /* ==== Test 5 Begin ==== */
|
||||
// $display("\n=== test 5: change trigger to fire on shemp > 3, and verify ===");
|
||||
// test_num = 5;
|
||||
|
||||
write_and_verify(9, 6, "shemp_op"); // set operation to GT
|
||||
write_and_verify(10, 3, "shemp_arg"); // set argument to 3
|
||||
// write_and_verify(9, 6, "shemp_op"); // set operation to GT
|
||||
// write_and_verify(10, 3, "shemp_arg"); // set argument to 3
|
||||
|
||||
assert( (la.fsm.state == la.fsm.IDLE) || (la.fsm.state == la.fsm.FILLED) )
|
||||
else $error("core is running when it shouldn't be!");
|
||||
// assert( (la.fsm_registers.state == la.la_controller.IDLE) || (la.fsm_registers.state == la.la_controller.CAPTURED) )
|
||||
// else $error("core is running when it shouldn't be!");
|
||||
|
||||
larry = 0;
|
||||
curly = 0;
|
||||
moe = 0;
|
||||
shemp = 0;
|
||||
// larry = 0;
|
||||
// curly = 0;
|
||||
// moe = 0;
|
||||
// shemp = 0;
|
||||
|
||||
write_reg(0, la.fsm.START_CAPTURE, "state");
|
||||
// // start the core
|
||||
// // TODO: start the core
|
||||
|
||||
shemp = 4;
|
||||
$display(" -> set shemp = 4");
|
||||
// shemp = 4;
|
||||
// $display(" -> set shemp = 4");
|
||||
|
||||
// run until the FILLED state is reached
|
||||
$display(" -> wait until FILLED state is reached");
|
||||
while (la.fsm.state != la.fsm.FILLED) begin
|
||||
{larry, curly, moe, shemp} = {larry, curly, moe, shemp} + 2;
|
||||
#`CP;
|
||||
end
|
||||
// // run until the FILLED state is reached
|
||||
// $display(" -> wait until FILLED state is reached");
|
||||
// while (la.fsm_registers.state != la.la_controller.CAPTURED) begin
|
||||
// {larry, curly, moe, shemp} = {larry, curly, moe, shemp} + 2;
|
||||
// #`CP;
|
||||
// end
|
||||
|
||||
$display(" -> read from sample memory:");
|
||||
read_all_reg();
|
||||
// $display(" -> read from sample memory:");
|
||||
// read_all_reg();
|
||||
|
||||
#(10*`CP);
|
||||
/* ==== Test 5 End ==== */
|
||||
// #(10*`CP);
|
||||
// /* ==== Test 5 End ==== */
|
||||
|
||||
$finish();
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
cores:
|
||||
my_logic_analyzer:
|
||||
type: logic_analyzer
|
||||
sample_depth: 128
|
||||
|
||||
probes:
|
||||
larry: 1
|
||||
curly: 1
|
||||
moe: 1
|
||||
shemp: 4
|
||||
|
||||
triggers:
|
||||
- larry && curly && ~moe
|
||||
|
||||
uart:
|
||||
port: "auto"
|
||||
baudrate: 115200
|
||||
clock_freq: 100000000
|
||||
|
|
@ -1,116 +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
|
||||
input wire larry,
|
||||
input wire curly,
|
||||
input wire moe,
|
||||
input wire [3:0] shemp,
|
||||
|
||||
// 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({9'b0, larry, curly, moe, shemp}),
|
||||
.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
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
`default_nettype none
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module trigger_block(
|
||||
input wire clk,
|
||||
|
||||
// probes
|
||||
input wire larry,
|
||||
input wire curly,
|
||||
input wire moe,
|
||||
input wire [3:0] shemp,
|
||||
|
||||
// trigger
|
||||
output reg trig,
|
||||
|
||||
// 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;
|
||||
|
||||
// trigger configuration registers
|
||||
// - each probe gets an operation and a compare register
|
||||
// - at the end we OR them all together. along with any custom probes the user specs
|
||||
|
||||
reg [3:0] larry_trigger_op = 0;
|
||||
reg larry_trigger_arg = 0;
|
||||
reg larry_trig;
|
||||
trigger #(.INPUT_WIDTH(1)) larry_trigger(
|
||||
.clk(clk),
|
||||
|
||||
.probe(larry),
|
||||
.op(larry_trigger_op),
|
||||
.arg(larry_trigger_arg),
|
||||
.trig(larry_trig));
|
||||
|
||||
reg [3:0] curly_trigger_op = 0;
|
||||
reg curly_trigger_arg = 0;
|
||||
reg curly_trig;
|
||||
trigger #(.INPUT_WIDTH(1)) curly_trigger(
|
||||
.clk(clk),
|
||||
|
||||
.probe(curly),
|
||||
.op(curly_trigger_op),
|
||||
.arg(curly_trigger_arg),
|
||||
.trig(curly_trig));
|
||||
|
||||
|
||||
reg [3:0] moe_trigger_op = 0;
|
||||
reg moe_trigger_arg = 0;
|
||||
reg moe_trig;
|
||||
trigger #(.INPUT_WIDTH(1)) moe_trigger(
|
||||
.clk(clk),
|
||||
|
||||
.probe(moe),
|
||||
.op(moe_trigger_op),
|
||||
.arg(moe_trigger_arg),
|
||||
.trig(moe_trig));
|
||||
|
||||
reg [3:0] shemp_trigger_op = 0;
|
||||
reg [3:0] shemp_trigger_arg = 0;
|
||||
reg shemp_trig;
|
||||
trigger #(.INPUT_WIDTH(4)) shemp_trigger(
|
||||
.clk(clk),
|
||||
|
||||
.probe(shemp),
|
||||
.op(shemp_trigger_op),
|
||||
.arg(shemp_trigger_arg),
|
||||
.trig(shemp_trig));
|
||||
|
||||
assign trig = larry_trig || curly_trig || moe_trig || shemp_trig;
|
||||
|
||||
// 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;
|
||||
rdata_o <= rdata_i;
|
||||
|
||||
if( (addr_i >= BASE_ADDR) && (addr_i <= BASE_ADDR + 7) ) begin
|
||||
|
||||
// reads
|
||||
if(valid_i && !rw_i) begin
|
||||
case (addr_i)
|
||||
BASE_ADDR + 0: rdata_o <= larry_trigger_op;
|
||||
BASE_ADDR + 1: rdata_o <= larry_trigger_arg;
|
||||
BASE_ADDR + 2: rdata_o <= curly_trigger_op;
|
||||
BASE_ADDR + 3: rdata_o <= curly_trigger_arg;
|
||||
BASE_ADDR + 4: rdata_o <= moe_trigger_op;
|
||||
BASE_ADDR + 5: rdata_o <= moe_trigger_arg;
|
||||
BASE_ADDR + 6: rdata_o <= shemp_trigger_op;
|
||||
BASE_ADDR + 7: rdata_o <= shemp_trigger_arg;
|
||||
endcase
|
||||
end
|
||||
|
||||
// writes
|
||||
else if(valid_i && rw_i) begin
|
||||
case (addr_i)
|
||||
BASE_ADDR + 0: larry_trigger_op <= wdata_i;
|
||||
BASE_ADDR + 1: larry_trigger_arg <= wdata_i;
|
||||
BASE_ADDR + 2: curly_trigger_op <= wdata_i;
|
||||
BASE_ADDR + 3: curly_trigger_arg <= wdata_i;
|
||||
BASE_ADDR + 4: moe_trigger_op <= wdata_i;
|
||||
BASE_ADDR + 5: moe_trigger_arg <= wdata_i;
|
||||
BASE_ADDR + 6: shemp_trigger_op <= wdata_i;
|
||||
BASE_ADDR + 7: shemp_trigger_arg <= wdata_i;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
`default_nettype wire
|
||||
Loading…
Reference in New Issue