diff --git a/Makefile b/Makefile index 9ce91d7..714345e 100644 --- a/Makefile +++ b/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 diff --git a/doc/system_architecture.md b/doc/system_architecture.md index bcc502c..79c87ff 100644 --- a/doc/system_architecture.md +++ b/doc/system_architecture.md @@ -4,7 +4,7 @@ Manta works by having a set of configurable cores daisy-chained together across ## Bus -This daisy-chaining is done to make place-and-route as easy as possible - the critical timing path only exists between adjacent cores, instead of rouing back to some central core in a hub-and-spoke arrangement. This relaxed routing helps designs that span multiple clock domains and require BRAMs placed on the edges of clock domains for CDC. +This daisy-chaining is done to make place-and-route as easy as possible - the critical timing path only exists between adjacent cores, instead of rouing back to some central core in a hub-and-spoke arrangement. This relaxed routing helps designs that span multiple clock domains and require BRAMs placed on the edges of clock domains for CDC. ## Memory @@ -12,11 +12,11 @@ The memory is built of 16-bit registers living on a 16-bit address bus. Address ## Read/Write Transactions -As you'd expect, reading from some address will elicit a response from the FGPA. However, writing to some address __will not__. If you want to verify that the data you wrote to some location is valid, read from it after the write. This is done to keep state machines simple and interfaces fast. +As you'd expect, reading from some address will elicit a response from the FGPA. However, writing to some address __will not__. If you want to verify that the data you wrote to some location is valid, read from it after the write. This is done to keep state machines simple and interfaces fast. Data moves between the host computer and the FPGA over UART. UART's just an interface though, so the choice of what data to send is arbitrary. Manta encodes data exchanged between devices as messages, which are ASCII text in the following format: -```[preamble] [address] [data (optional)] [EOL]``` +```[preamble] [address] [data (optional)] [EOL]``` - The __preamble__ is just the character `M`, encoded as ASCII. @@ -46,7 +46,7 @@ The Python API has two main purposes: to generate the Verilog required to instan ### Loading configuration -Let's use the following configuration as an example: +Let's use the following configuration as an example: ```yaml @@ -68,19 +68,19 @@ cores: my_logic_analyzer: type: logic_analyzer sample_depth: 4096 - + probes: larry: 1 curly: 1 moe: 1 shemp: 4 - + triggers: - larry && curly && ~moe my_lut_ram: - type: lut_ram - size: 64 + type: lut_ram + size: 64 uart: port: "/dev/tty.usbserial-2102926963071" @@ -94,13 +94,13 @@ For each core in the config file, an instance of the corresponding Python object my_logic_analyzer: type: logic_analyzer sample_depth: 4096 - + probes: larry: 1 curly: 1 moe: 1 shemp: 4 - + triggers: - larry && curly && ~moe ``` @@ -156,4 +156,12 @@ Once manta's been generated, included in your project, and built, the Python API ### Block Diagram
- \ No newline at end of file + + +Nominal interaction with the logic analyzer core should be: +- Check state - if it's in anything other than idle, request to stop the existing capture +- Once state's in IDLE, go ahead and configure trigger positions and conditions and request start. Also set it back down to zero. +- Wait for state to be in captured. If you want a timeout, then pulse stop_request once the timeout has expired. +- Read out contents from memory +- Pulse stop_request to end the capture and return the state back to IDLE + diff --git a/src/manta/__init__.py b/src/manta/__init__.py index 08e9d6b..828c699 100644 --- a/src/manta/__init__.py +++ b/src/manta/__init__.py @@ -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): diff --git a/src/manta/logic_analyzer_controller.v b/src/manta/logic_analyzer_controller.v index 4443d85..492014a 100644 --- a/src/manta/logic_analyzer_controller.v +++ b/src/manta/logic_analyzer_controller.v @@ -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 diff --git a/src/manta/logic_analyzer_def_tmpl.v b/src/manta/logic_analyzer_def_tmpl.v index 2f8107c..d21d21c 100644 --- a/src/manta/logic_analyzer_def_tmpl.v +++ b/src/manta/logic_analyzer_def_tmpl.v @@ -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), diff --git a/src/manta/logic_analyzer_fsm_registers.v b/src/manta/logic_analyzer_fsm_registers.v index fc60324..3c06ad5 100644 --- a/src/manta/logic_analyzer_fsm_registers.v +++ b/src/manta/logic_analyzer_fsm_registers.v @@ -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; diff --git a/test/functional_sim/logic_analyzer_tb/gen_logic_analyzer.py b/test/functional_sim/logic_analyzer_tb/gen_logic_analyzer.py new file mode 100644 index 0000000..46bdcdb --- /dev/null +++ b/test/functional_sim/logic_analyzer_tb/gen_logic_analyzer.py @@ -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) \ No newline at end of file diff --git a/test/functional_sim/logic_analyzer_tb/logic_analyzer.v b/test/functional_sim/logic_analyzer_tb/logic_analyzer.v index 48e5e77..a41ea4c 100644 --- a/test/functional_sim/logic_analyzer_tb/logic_analyzer.v +++ b/test/functional_sim/logic_analyzer_tb/logic_analyzer.v @@ -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 \ No newline at end of file + // 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= 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 diff --git a/test/functional_sim/logic_analyzer_tb/logic_analyzer_tb.sv b/test/functional_sim/logic_analyzer_tb/logic_analyzer_tb.sv index 8dfa87b..c0dee09 100644 --- a/test/functional_sim/logic_analyzer_tb/logic_analyzer_tb.sv +++ b/test/functional_sim/logic_analyzer_tb/logic_analyzer_tb.sv @@ -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 diff --git a/test/functional_sim/logic_analyzer_tb/manta.yaml b/test/functional_sim/logic_analyzer_tb/manta.yaml new file mode 100644 index 0000000..ce1ac6b --- /dev/null +++ b/test/functional_sim/logic_analyzer_tb/manta.yaml @@ -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 \ No newline at end of file diff --git a/test/functional_sim/logic_analyzer_tb/sample_mem.v b/test/functional_sim/logic_analyzer_tb/sample_mem.v deleted file mode 100644 index 2d68aa3..0000000 --- a/test/functional_sim/logic_analyzer_tb/sample_mem.v +++ /dev/null @@ -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 \ No newline at end of file diff --git a/test/functional_sim/logic_analyzer_tb/trigger_block.v b/test/functional_sim/logic_analyzer_tb/trigger_block.v deleted file mode 100644 index 114a831..0000000 --- a/test/functional_sim/logic_analyzer_tb/trigger_block.v +++ /dev/null @@ -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 \ No newline at end of file