add semi-working trigger block autogen

This commit is contained in:
Fischer Moseley 2023-04-03 16:43:28 -04:00
parent 8f08dffc70
commit aab1b5ac10
3 changed files with 170 additions and 27 deletions

3
.gitignore vendored
View File

@ -1,6 +1,9 @@
# macOS being lame
.DS_Store
# VSCode being lame
*.vscode/
# Vivado output products
*.log
*.jou

View File

@ -467,11 +467,108 @@ class LogicAnalyzerCore:
return hdl
def generate_trigger_block(self):
trigger_block_hdl = pkgutil.get_data(__name__, "trigger_block_template.v").decode()
# 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 = []
for name, width in self.probes.items():
if width == 1:
probe_ports.append(f"input wire {name}")
else:
probe_ports.append(f"input wire [{width-1}:0] {name}")
probe_ports = ",\n\t".join(probe_ports)
probe_ports = probe_ports + ","
trigger_block_hdl = trigger_block_hdl.replace("// @PROBE_PORTS", probe_ports)
# add trigger cores to module definition
# - these are instances of the trigger module, of which one gets wired
# into each probe
trigger_module_insts = []
for name, width in self.probes.items():
trigger_module_inst = f"reg [3:0] {name}_trigger_op = 0;\n\t"
if width == 1:
trigger_module_inst += f"reg {name}_trigger_arg = 0;\n\t"
else:
trigger_module_inst += f"reg [{width-1}:0] {name}_trigger_arg = 0;\n\t"
trigger_module_inst += f"reg {name}_trig;\n\t"
trigger_module_inst += f"""
trigger #(.INPUT_WIDTH({width})) {name}_trigger (
.clk(clk),
.probe({name}),
.op({name}_trigger_op),
.arg({name}_trigger_arg),
.trig({name}_trig)
);
"""
trigger_module_insts.append(trigger_module_inst)
trigger_module_insts = "".join(trigger_module_insts)
trigger_module_insts = trigger_module_insts.rstrip()
trigger_block_hdl = trigger_block_hdl.replace("// @TRIGGER_MODULE_INSTS", trigger_module_insts)
# add combined individual triggers
combined_individual_triggers = [f"{name}_trig" for name in self.probes]
combined_individual_triggers = " || ".join(combined_individual_triggers)
combined_individual_triggers = f"assign trig = {combined_individual_triggers};"
trigger_block_hdl = trigger_block_hdl.replace("// @COMBINE_INDIV_TRIGGERS", combined_individual_triggers)
# add read and write block case statement bodies
rcsb = "" # read case statement body
wcsb = "" # write case statement body
addr = 0
for i, name in enumerate(self.probes):
addr = 2 * i
rcsb += f"\t\t\t\t\tBASE_ADDR + {addr}: rdata_o <= {name}_trigger_op;\n"
wcsb += f"\t\t\t\t\tBASE_ADDR + {addr}: {name}_trigger_op <= wdata_i;\n"
addr = (2 * i) + 1
rcsb += f"\t\t\t\t\tBASE_ADDR + {addr}: rdata_o <= {name}_trigger_arg;\n"
wcsb += f"\t\t\t\t\tBASE_ADDR + {addr}: {name}_trigger_arg <= wdata_i;\n"
rcsb = rcsb.strip()
wcsb = wcsb.strip()
trigger_block_hdl = trigger_block_hdl.replace("// @READ_CASE_STATEMENT_BODY", rcsb)
trigger_block_hdl = trigger_block_hdl.replace("// @WRITE_CASE_STATEMENT_BODY", wcsb)
trigger_block_hdl = trigger_block_hdl.replace("// @MAX_ADDR", str(addr))
return trigger_block_hdl
def hdl_def(self):
# Return an autogenerated verilog module definition for the core.
# load source files
logic_analyzer_hdl = pkgutil.get_data(__name__, "logic_analyzer.v").decode()
la_fsm_hdl = pkgutil.get_data(__name__, "la_fsm.v").decode()
sample_mem_hdl = pkgutil.get_data(__name__, "sample_mem.v").decode()
xilinx_bram_hdl = pkgutil.get_data(__name__, "xilinx_true_dual_port_read_first_2_clock_ram.v").decode()
trigger_hdl = pkgutil.get_data(__name__, "trigger.v").decode()
# generate trigger block
trigger_block_hdl = self.generate_trigger_block()
return logic_analyzer_hdl + la_fsm_hdl + sample_mem_hdl + xilinx_bram_hdl + trigger_block_hdl + trigger_hdl
def hdl_top_level_ports(self):
# this should return the probes that we want to connect to top-level, but as a list of verilog ports
ports = []
for name, width in self.probes.items():
if width == 1:
ports.append(f"input wire {name}")
else:
ports.append(f"input wire [{width-1}:0] {name}")
return ports
def run(self):
self.interface.open()
self.interface.flushInput()
self.interface.write(b"\x30")
data = self.interface.read(4096)
pass
def part_select(self, data, width):
top, bottom = width
@ -538,29 +635,6 @@ class LogicAnalyzerCore:
writer.change(probe, timestamp, val)
vcd_file.close()
def hdl_def(self):
# Return an autogenerated verilog module definition for the core.
# load source files
logic_analyzer_hdl = pkgutil.get_data(__name__, "logic_analyzer.v").decode()
la_fsm_hdl = pkgutil.get_data(__name__, "la_fsm.v").decode()
sample_mem_hdl = pkgutil.get_data(__name__, "sample_mem.v").decode()
xilinx_bram_hdl = pkgutil.get_data(__name__, "xilinx_true_dual_port_read_first_2_clock_ram.v").decode()
trigger_block_hdl= pkgutil.get_data(__name__, "trigger_block.v").decode()
trigger_hdl = pkgutil.get_data(__name__, "trigger.v").decode()
return logic_analyzer_hdl + la_fsm_hdl + sample_mem_hdl + xilinx_bram_hdl + trigger_block_hdl + trigger_hdl
def hdl_top_level_ports(self):
# this should return the probes that we want to connect to top-level, but as a list of verilog ports
ports = []
for name, width in self.probes.items():
if width == 1:
ports.append(f"input wire {name}")
else:
ports.append(f"input wire [{width-1}:0] {name}")
return ports
class Manta:
def __init__(self, config_filepath):

View File

@ -0,0 +1,66 @@
`default_nettype none
`timescale 1ns/1ps
module trigger_block (
input wire clk,
// probes
// @PROBE_PORTS
// 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 = // @MAX_ADDR;
// 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
// @TRIGGER_MODULE_INSTS
// @COMBINE_INDIV_TRIGGERS
// 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)
// @READ_CASE_STATEMENT_BODY
endcase
end
// writes
else if(valid_i && rw_i) begin
case (addr_i)
// @WRITE_CASE_STATEMENT_BODY
endcase
end
end
end
endmodule
`default_nettype wire