From fade79433320476ce13d4104f9511c8bb426e8f9 Mon Sep 17 00:00:00 2001 From: Fischer Moseley <42497969+fischermoseley@users.noreply.github.com> Date: Wed, 15 Mar 2023 15:57:42 -0400 Subject: [PATCH] add initialls logic_analyzer core --- .github/workflows/build_docs.yml | 1 - Makefile | 13 +- src/manta/fifo.v | 52 ++++--- src/manta/la_template.v | 0 src/manta/logic_analyzer.v | 226 ++++++++++++++++++++++++++++++ src/manta/trigger.v | 47 +++++++ test/logic_analyzer_tb.sv | 231 +++++++++++++++++++++++++++++++ 7 files changed, 537 insertions(+), 33 deletions(-) delete mode 100644 src/manta/la_template.v create mode 100644 src/manta/logic_analyzer.v create mode 100644 src/manta/trigger.v create mode 100644 test/logic_analyzer_tb.sv diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 915007b..3c0d632 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -3,7 +3,6 @@ on: push: branches: - main - - rearch permissions: contents: write jobs: diff --git a/Makefile b/Makefile index 858bb10..68431d2 100644 --- a/Makefile +++ b/Makefile @@ -8,19 +8,24 @@ lint: python3 -m black src/manta/__init__.py python3 -m black src/manta/__main__.py -sim: sim_bit_fifo sim_bridge_rx sim_bridge_tx fifo_tb lut_ram_tb uart_tx_tb +sim: bit_fifo_tb bridge_rx_tb bridge_tx_tb fifo_tb lut_ram_tb uart_tx_tb -sim_bit_fifo: +logic_analyzer_tb: + iverilog -g2012 -o sim.out test/logic_analyzer_tb.sv src/manta/logic_analyzer.v src/manta/fifo.v src/manta/trigger.v src/manta/xilinx_true_dual_port_read_first_2_clock_ram.v + vvp sim.out + rm sim.out + +bit_fifo_tb: iverilog -g2012 -o sim.out test/bit_fifo_tb.sv src/manta/bit_fifo.v vvp sim.out rm sim.out -sim_bridge_rx: +bridge_rx_tb: iverilog -g2012 -o sim.out test/bridge_rx_tb.sv src/manta/bridge_rx.v vvp sim.out rm sim.out -sim_bridge_tx: +bridge_tx_tb: iverilog -g2012 -o sim.out test/bridge_tx_tb.sv src/manta/bridge_tx.v src/manta/uart_tx.v vvp sim.out rm sim.out diff --git a/src/manta/fifo.v b/src/manta/fifo.v index 6a90a67..3385d70 100644 --- a/src/manta/fifo.v +++ b/src/manta/fifo.v @@ -3,14 +3,14 @@ module fifo ( input wire clk, - input wire rst, + input wire bram_rst, - input wire [WIDTH - 1:0] data_in, - input wire input_ready, + input wire [WIDTH - 1:0] in, + input wire in_valid, - input wire request_output, - output reg [WIDTH - 1:0] data_out, - output reg output_valid, + output reg [WIDTH - 1:0] out, + input wire out_req, + output reg out_valid, output reg [AW:0] size, output reg empty, @@ -28,28 +28,24 @@ module fifo ( assign empty_int = (write_pointer[AW] == read_pointer[AW]); reg full_or_empty; - assign full_or_empty = (write_pointer[AW-1:0] == read_pointer[AW-1:0]); + assign full_or_empty = (write_pointer[AW-1:0] == read_pointer[AW-1:0]); assign full = full_or_empty & !empty_int; assign empty = full_or_empty & empty_int; assign size = write_pointer - read_pointer; - reg output_valid_pip_0; - reg output_valid_pip_1; + reg out_valid_pip_0; + reg out_valid_pip_1; always @(posedge clk) begin - if (input_ready && ~full) + if (in_valid && ~full) write_pointer <= write_pointer + 1'd1; - if (request_output && ~empty) + if (out_req && ~empty) begin read_pointer <= read_pointer + 1'd1; - output_valid_pip_0 <= request_output; - output_valid_pip_1 <= output_valid_pip_0; - output_valid <= output_valid_pip_1; - - if (rst) begin - read_pointer <= 0; - write_pointer <= 0; + out_valid_pip_0 <= out_req; + out_valid_pip_1 <= out_valid_pip_0; + out_valid <= out_valid_pip_1; end end @@ -62,23 +58,23 @@ module fifo ( // write port .clka(clk), - .rsta(rst), - .ena(1), + .rsta(bram_rst), + .ena(1'b1), .addra(write_pointer), - .dina(data_in), - .wea(input_ready), - .regcea(1), + .dina(in), + .wea(in_valid), + .regcea(1'b1), .douta(), // read port .clkb(clk), - .rstb(rst), - .enb(1), + .rstb(bram_rst), + .enb(1'b1), .addrb(read_pointer), .dinb(), - .web(0), - .regceb(1), - .doutb(data_out)); + .web(1'b0), + .regceb(1'b1), + .doutb(out)); endmodule `default_nettype wire diff --git a/src/manta/la_template.v b/src/manta/la_template.v deleted file mode 100644 index e69de29..0000000 diff --git a/src/manta/logic_analyzer.v b/src/manta/logic_analyzer.v new file mode 100644 index 0000000..21f3479 --- /dev/null +++ b/src/manta/logic_analyzer.v @@ -0,0 +1,226 @@ +`default_nettype none +`timescale 1ns/1ps + +module logic_analyzer( + input wire clk, + + // 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 = 4096; + + // trigger configuration registers + // - each probe gets an operation and a compare register + // - at the end we AND them all together. along with any custom probes the user specs + + reg [3:0] larry_trigger_op; + reg larry_trigger_arg; + 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; + reg curly_trigger_arg; + 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; + reg moe_trigger_arg; + 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; + reg [3:0] shemp_trigger_arg; + reg shemp_trig; + trigger #(.INPUT_WIDTH(4)) shemp_trigger( + .clk(clk), + + .probe(shemp), + .op(shemp_trigger_op), + .arg(shemp_trigger_arg), + .trig(shemp_trig)); + + reg triggered; + assign triggered = larry_trig || curly_trig || moe_trig || shemp_trig; + + reg [6:0] concatenated; + assign concatenated = {larry, curly, moe, shemp}; + + // word-wise fifo + fifo #(.WIDTH(FIFO_WIDTH), .DEPTH(SAMPLE_DEPTH)) wfifo( + .clk(clk), + .bram_rst(1'b0), + + .in(concatenated), + .in_valid(wfifo_in_valid), + + .out(wfifo_out), + .out_req(wfifo_out_req), + .out_valid(wfifo_out_valid), + + .size(wfifo_size), + .empty(), + .full()); + + reg wfifo_in_valid; + localparam FIFO_WIDTH = 7; + reg [FIFO_WIDTH-1:0] wfifo_out; + reg wfifo_out_req; + reg wfifo_out_valid; + + reg [$clog2(SAMPLE_DEPTH):0] wfifo_size; + + + // state machine + localparam IDLE = 0; + localparam START = 1; + localparam MOVE_TO_POSITION = 2; + localparam IN_POSITION = 3; + localparam FILLING_BUFFER = 4; + localparam FILLED = 5; + + reg [3:0] state; + initial state = IDLE; + + reg signed [15:0] trigger_loc; + initial trigger_loc = 0; + + reg signed [15:0] present_loc; + initial present_loc = 0; + + always @(posedge clk) begin + if(state == IDLE) begin + present_loc <= (trigger_loc < 0) ? trigger_loc : 0; + end + + else if(state == MOVE_TO_POSITION) begin + // if trigger location is negative or zero, + // then we're already in position + if(trigger_loc <= 0) state <= IN_POSITION; + + // otherwise we'll need to wait a little, + // but we'll need to buffer along the way + else begin + present_loc <= present_loc + 1; + // add code to add samples to word FIFO + wfifo_in_valid <= 1; + if (present_loc == trigger_loc) state <= IN_POSITION; + end + end + + else if(state == IN_POSITION) begin + // pop stuff out of the word FIFO in addition to pulling it in + wfifo_in_valid <= 1; + wfifo_out_req <= 1; + + if(triggered) state <= FILLING_BUFFER; + end + + else if(state == FILLING_BUFFER) begin + if(wfifo_size == SAMPLE_DEPTH) state <= FILLED; + end + + else if(state == FILLED) begin + // don't automatically go back to IDLE, the host will move + // the state to MOVE_TO_POSITION + + present_loc <= (trigger_loc < 0) ? trigger_loc : 0; + end + end + + + + // memory servicing + // - TODO: add support for comparision values > 16 bits, + // we'll have to concat them somwehere up here + + always @(posedge clk) begin + + addr_o <= addr_i; + wdata_o <= wdata_i; + rdata_o <= rdata_i; + rw_o <= rw_i; + valid_o <= valid_i; + + // operations to configuration registers + if( (addr_i >= BASE_ADDR) && (addr_i <= BASE_ADDR + 9) ) begin + + // reads + if(valid_i && !rw_i) begin + case (addr_i) + BASE_ADDR + 0: rdata_o <= state; + BASE_ADDR + 1: rdata_o <= trigger_loc; + BASE_ADDR + 2: rdata_o <= larry_trigger_op; + BASE_ADDR + 3: rdata_o <= larry_trigger_arg; + BASE_ADDR + 4: rdata_o <= curly_trigger_op; + BASE_ADDR + 5: rdata_o <= curly_trigger_arg; + BASE_ADDR + 6: rdata_o <= moe_trigger_op; + BASE_ADDR + 7: rdata_o <= moe_trigger_arg; + BASE_ADDR + 8: rdata_o <= shemp_trigger_op; + BASE_ADDR + 9: rdata_o <= shemp_trigger_arg; + default: rdata_o <= rdata_i; + endcase + end + + // writes + else if(valid_i && rw_i) begin + case (addr_i) + BASE_ADDR + 0: state <= wdata_i; + BASE_ADDR + 1: trigger_loc <= wdata_i; + BASE_ADDR + 2: larry_trigger_op <= wdata_i; + BASE_ADDR + 3: larry_trigger_arg <= wdata_i; + BASE_ADDR + 4: curly_trigger_op <= wdata_i; + BASE_ADDR + 5: curly_trigger_arg <= wdata_i; + BASE_ADDR + 6: moe_trigger_op <= wdata_i; + BASE_ADDR + 7: moe_trigger_arg <= wdata_i; + BASE_ADDR + 8: shemp_trigger_op <= wdata_i; + BASE_ADDR + 9: shemp_trigger_arg <= wdata_i; + default: wdata_o <= wdata_i; + endcase + end + end + + // operations to BRAM + else if( (addr_i >= BASE_ADDR + 10) && (addr_i <= BASE_ADDR + 10 + SAMPLE_DEPTH) ) begin + end + end +endmodule + +`default_nettype wire \ No newline at end of file diff --git a/src/manta/trigger.v b/src/manta/trigger.v new file mode 100644 index 0000000..5c12cab --- /dev/null +++ b/src/manta/trigger.v @@ -0,0 +1,47 @@ +`default_nettype none +`timescale 1ns/1ps + +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; + initial probe_prev = probe; + 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 + +`default_nettype wire \ No newline at end of file diff --git a/test/logic_analyzer_tb.sv b/test/logic_analyzer_tb.sv new file mode 100644 index 0000000..d151a70 --- /dev/null +++ b/test/logic_analyzer_tb.sv @@ -0,0 +1,231 @@ +`default_nettype none + +`define CP 10 +`define HCP 5 + +module logic_analyzer_tb; + + // boilerplate + logic clk; + integer test_num; + + // signal generator + logic larry; + logic curly; + logic moe; + logic [3:0] shemp; + + // tb -> la bus + logic [15:0] tb_la_addr; + logic [15:0] tb_la_wdata; + logic [15:0] tb_la_rdata; + logic tb_la_rw; + logic tb_la_valid; + + // la -> tb bus + logic [15:0] la_tb_addr; + logic [15:0] la_tb_wdata; + logic [15:0] la_tb_rdata; + logic la_tb_rw; + logic la_tb_valid; + + + logic_analyzer la( + .clk(clk), + + // probes + .larry(larry), + .curly(curly), + .moe(moe), + .shemp(shemp), + + // input port + .addr_i(tb_la_addr), + .wdata_i(tb_la_wdata), + .rdata_i(tb_la_rdata), + .rw_i(tb_la_rw), + .valid_i(tb_la_valid), + + // output port + .addr_o(la_tb_addr), + .wdata_o(la_tb_wdata), + .rdata_o(la_tb_rdata), + .rw_o(la_tb_rw), + .valid_o(la_tb_valid)); + + always begin + #`HCP + clk = !clk; + end + + initial begin + $dumpfile("logic_analyzer_tb.vcd"); + $dumpvars(0, logic_analyzer_tb); + + // setup and reset + clk = 0; + test_num = 0; + + tb_la_addr = 0; + tb_la_rdata = 0; + tb_la_wdata = 0; + tb_la_rw = 0; + tb_la_valid = 0; + + larry = 0; + curly = 0; + moe = 0; + shemp = 0; + #`HCP + #(10*`CP); + + /* ==== Test 1 Begin ==== */ + $display("\n=== test 1: read state register ==="); + test_num = 1; + + tb_la_addr = 0; + tb_la_valid = 1; + #`CP + tb_la_valid = 0; + while (!la_tb_valid) #`CP; + $display(" -> read 0x%h from state reg (addr 0x0000)", la_tb_rdata); + + + #(10*`CP); + /* ==== Test 1 End ==== */ + + + + /* ==== Test 2 Begin ==== */ + $display("\n=== test 2: write to state register and verify ==="); + test_num = 2; + + // write + tb_la_addr = 0; + tb_la_valid = 1; + tb_la_rw = 1; + tb_la_wdata = 5; + #`CP + tb_la_valid = 0; + #`CP + $display(" -> wrote 0x0005 to state reg (addr 0x0000)"); + + // read + tb_la_valid = 1; + tb_la_rw = 0; + #`CP + tb_la_valid = 0; + while (!la_tb_valid) #`CP; + $display(" -> read 0x%h from state reg (addr 0x0000)", la_tb_rdata); + + + #(10*`CP); + /* ==== Test 2 End ==== */ + + + + /* ==== Test 3 Begin ==== */ + $display("\n=== test 3: write to trigger_loc register and verify ==="); + test_num = 3; + + // write + tb_la_addr = 1; + tb_la_valid = 1; + tb_la_rw = 1; + tb_la_wdata = -16'sd69; + #`CP + tb_la_valid = 0; + #`CP + $display(" -> wrote -0d69 to trigger_loc reg (addr 0x0001)"); + + // read + tb_la_valid = 1; + tb_la_rw = 0; + #`CP + tb_la_valid = 0; + while (!la_tb_valid) #`CP; + $display(" -> read 0d%d from trigger_loc reg (addr 0x0001)", $signed(la_tb_rdata)); + + + #(10*`CP); + /* ==== Test 3 End ==== */ + + + + /* ==== Test 4 Begin ==== */ + $display("\n=== test 4: configure larry_op for equality and verify ==="); + test_num = 4; + + // write + tb_la_addr = 2; + tb_la_valid = 1; + tb_la_rw = 1; + tb_la_wdata = 8; + #`CP + tb_la_valid = 0; + #`CP + $display(" -> wrote 0x0008 to larry_op reg (addr 0x0002)"); + + // read + tb_la_valid = 1; + tb_la_rw = 0; + #`CP + tb_la_valid = 0; + while (!la_tb_valid) #`CP; + $display(" -> read 0x%h from larry_op reg (addr 0x0002)", la_tb_rdata); + + + #(10*`CP); + /* ==== Test 4 End ==== */ + + + + /* ==== Test 5 Begin ==== */ + $display("\n=== test 5: write 0x0001 to larry_arg register and verify ==="); + test_num = 5; + + // write + tb_la_addr = 3; + tb_la_valid = 1; + tb_la_rw = 1; + tb_la_wdata = 1; + #`CP + tb_la_valid = 0; + #`CP + $display(" -> wrote 0x0001 to larry_arg reg (addr 0x0003)"); + + // read + tb_la_valid = 1; + tb_la_rw = 0; + #`CP + tb_la_valid = 0; + while (!la_tb_valid) #`CP; + $display(" -> read 0x%h from larry_arg reg (addr 0x0003)", la_tb_rdata); + + + #(10*`CP); + /* ==== Test 5 End ==== */ + + + + /* ==== Test 6 Begin ==== */ + $display("\n=== test 6: set larry = 1, verify core does not trigger ==="); + test_num = 6; + + larry = 1; + $display(" -> set larry = 1"); + + // read + $display(" -> la core is in state 0x%h", la.state); + #`CP + $display(" -> la core is in state 0x%h", la.state); + + + #(10*`CP); + /* ==== Test 6 End ==== */ + + $finish(); + end +endmodule + +`default_nettype wire \ No newline at end of file