From 13aed4be39dd1460562b2177559d124286dbd3ff Mon Sep 17 00:00:00 2001 From: drewnotdrew Date: Thu, 24 Apr 2025 15:04:21 -0400 Subject: [PATCH 01/10] add partially completed i2s receive --- hardware/hdl/interfaces/i2s.sv | 103 +++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 hardware/hdl/interfaces/i2s.sv diff --git a/hardware/hdl/interfaces/i2s.sv b/hardware/hdl/interfaces/i2s.sv new file mode 100644 index 0000000..475aab9 --- /dev/null +++ b/hardware/hdl/interfaces/i2s.sv @@ -0,0 +1,103 @@ +/* +I2S Codec interface + +@param A_PARAMETER +*/ + +`begin_keywords "1800-2017" // Use SystemVerilog 2017 keywords +`default_nettype none + +module i2s +#( + parameter BIT_WIDTH = 24 + // parameter +) +( + input logic rst_n, + input logic clk, + + // i2s common + output mclk, + output blck, + + // i2s rx + output rx_lr_clk, + input rx_data, + + // i2s tx + output tx_lr_clk, + output tx_data, + + // device specific //TODO: move to higher level module + output mute + + +); + timeunit 1ns; timeprecision 100ps; + + // local parameters + localparam BUFFER_COUNTER_BITS = $clog2(BIT_WIDTH); + + // i2s states + typedef enum logic [2:0] { + RESET = 3'b000, + LEFT = 3'b001, + RIGHT = 3'b010, + ERROR = 3'b100 + } i2s_state_t; + +/* + * ============================================================================= + * receive + * ============================================================================= + */ + + // internal rx variables + i2s_state_t rx_state, rx_next_state; + logic rx_shift_en, rx_bit_counter_rst_n; + + // rx current state logic + always_ff @( posedge clk ) begin : _rx_current_state_logic + if (!rst_n) + rx_state <= RESET; + else + rx_state <= rx_next_state; + end + + // rx next state logic + always_comb begin : _rx_next_state_logic + unique case (rx_state) + RESET: + rx_next_state = LEFT; + LEFT: + rx_next_state = RIGHT; + RIGHT: + rx_next_state = LEFT; + ERROR: + rx_next_state = ERROR; + default: + rx_next_state = ERROR; // catch glitches + endcase + end + + // rx fsm outputs + always_comb begin : _rx_fsm_outputs + unique case (rx_state) + end + + // receive shift register + always_ff @( posedge bclk) begin : _rx_shift_register + if (!rst_n) + rx_data <= '0; + else if (rx_shift_en) + rx_data <= {rx_data[], rx_data} // msb first + else + rx_data <= rx_data; + end + + + +endmodule : i2s + +`default_nettype wire +`end_keywords From 7395e5101fd78ef39029d729c1c8ead6b25fd6da Mon Sep 17 00:00:00 2001 From: Drew Date: Wed, 30 Apr 2025 17:03:45 -0400 Subject: [PATCH 02/10] complete i2s receive, untested --- hardware/hdl/interfaces/i2s.sv | 72 ++++++++++++++++++++++----------- hardware/hdl/interfaces/uart.sv | 2 +- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/hardware/hdl/interfaces/i2s.sv b/hardware/hdl/interfaces/i2s.sv index 475aab9..6345d6d 100644 --- a/hardware/hdl/interfaces/i2s.sv +++ b/hardware/hdl/interfaces/i2s.sv @@ -1,7 +1,7 @@ /* I2S Codec interface -@param A_PARAMETER +@param BIT_DEPTH: The bit depth of the codec. */ `begin_keywords "1800-2017" // Use SystemVerilog 2017 keywords @@ -9,41 +9,45 @@ I2S Codec interface module i2s #( - parameter BIT_WIDTH = 24 - // parameter + parameter BIT_DEPTH = 24 ) ( - input logic rst_n, - input logic clk, + input wire rst_n, + input wire clk, // i2s common - output mclk, - output blck, + output logic mclk, + output logic blck, // i2s rx - output rx_lr_clk, - input rx_data, + output logic rx, + output logic rx_lr_clk, + output logic [BIT_DEPTH-1:0] rx_data, + input wire rx_ready, + output logic rx_valid, // i2s tx - output tx_lr_clk, - output tx_data, + input wire tx, + output logic tx_lr_clk, + input logic [BIT_DEPTH-1:0] tx_data, + input wire tx_ready, + input wire tx_valid, // device specific //TODO: move to higher level module - output mute - - + output logic mute ); timeunit 1ns; timeprecision 100ps; // local parameters - localparam BUFFER_COUNTER_BITS = $clog2(BIT_WIDTH); + localparam BUFFER_COUNTER_BITS = $clog2(BIT_DEPTH); // i2s states - typedef enum logic [2:0] { - RESET = 3'b000, - LEFT = 3'b001, - RIGHT = 3'b010, - ERROR = 3'b100 + typedef enum logic [3:0] { + RESET = 4'b0000, + IDLE = 4'b0001, + LEFT = 4'b0010, + RIGHT = 4'b0100, + ERROR = 4'b1000 } i2s_state_t; /* @@ -54,7 +58,9 @@ module i2s // internal rx variables i2s_state_t rx_state, rx_next_state; + logic [BUFFER_COUNTER_BITS-1:0] rx_bit_counter; logic rx_shift_en, rx_bit_counter_rst_n; + logic [BIT_DEPTH-1:0] input_buffer; // rx current state logic always_ff @( posedge clk ) begin : _rx_current_state_logic @@ -69,9 +75,13 @@ module i2s unique case (rx_state) RESET: rx_next_state = LEFT; + IDLE: + rx_next_state = LEFT; LEFT: - rx_next_state = RIGHT; + if (rx_bit_counter == '0) + rx_next_state = RIGHT; RIGHT: + if (rx_bit_counter == '0) rx_next_state = LEFT; ERROR: rx_next_state = ERROR; @@ -83,19 +93,33 @@ module i2s // rx fsm outputs always_comb begin : _rx_fsm_outputs unique case (rx_state) + RESET, ERROR: {rx_shift_en, rx_bit_counter_rst_n} = 2'b01; + IDLE: {rx_shift_en, rx_bit_counter_rst_n} = 2'b10; + LEFT: {rx_shift_en, rx_bit_counter_rst_n} = 2'b11; + RIGHT: {rx_shift_en, rx_bit_counter_rst_n} = 2'b11; + default: {rx_shift_en, rx_bit_counter_rst_n} = 2'b01; + endcase end // receive shift register - always_ff @( posedge bclk) begin : _rx_shift_register + always_ff @( posedge clk) begin : _rx_shift_register if (!rst_n) rx_data <= '0; else if (rx_shift_en) - rx_data <= {rx_data[], rx_data} // msb first + rx_data <= {rx_data[BIT_DEPTH-2:0], rx}; // msb first else rx_data <= rx_data; end - + // rx bit counter + always_ff @( posedge clk ) begin : _rx_bit_counter + if (!rx_bit_counter_rst_n) + rx_bit_counter <= BIT_DEPTH; + else if (rx_bit_counter == '0) + rx_bit_counter <= BIT_DEPTH - 1; + else + rx_bit_counter <= rx_bit_counter - 1; + end endmodule : i2s diff --git a/hardware/hdl/interfaces/uart.sv b/hardware/hdl/interfaces/uart.sv index c64235c..1ed3bdf 100644 --- a/hardware/hdl/interfaces/uart.sv +++ b/hardware/hdl/interfaces/uart.sv @@ -80,7 +80,7 @@ module uart /* * ======================================= - * Receive + * receive * ======================================= */ From 39200d0e59bc18a05f3a9775eb7b10649d4c614e Mon Sep 17 00:00:00 2001 From: Drew Date: Thu, 1 May 2025 15:11:46 -0400 Subject: [PATCH 03/10] complete i2s receive, tested --- hardware/hdl/interfaces/i2s.sv | 183 +++++++++++++++++++--- hardware/verif/py/interfaces/test_i2s.py | 169 ++++++++++++++++++++ hardware/verif/py/interfaces/test_uart.py | 6 +- 3 files changed, 330 insertions(+), 28 deletions(-) create mode 100644 hardware/verif/py/interfaces/test_i2s.py diff --git a/hardware/hdl/interfaces/i2s.sv b/hardware/hdl/interfaces/i2s.sv index 6345d6d..937d591 100644 --- a/hardware/hdl/interfaces/i2s.sv +++ b/hardware/hdl/interfaces/i2s.sv @@ -9,26 +9,29 @@ I2S Codec interface module i2s #( - parameter BIT_DEPTH = 24 + parameter BIT_DEPTH = 24, + parameter WORD_LENGTH = 32, + parameter MCLK_FREQ = 125_000_000, + parameter BCLK_DIV = 4, + parameter LRCLK_DIV = 256 ) ( input wire rst_n, - input wire clk, // i2s common - output logic mclk, - output logic blck, + input wire mclk, + output logic bclk, // i2s rx output logic rx, - output logic rx_lr_clk, + output logic rx_lrclk, output logic [BIT_DEPTH-1:0] rx_data, input wire rx_ready, output logic rx_valid, // i2s tx input wire tx, - output logic tx_lr_clk, + output logic tx_lrclk, input logic [BIT_DEPTH-1:0] tx_data, input wire tx_ready, input wire tx_valid, @@ -38,18 +41,73 @@ module i2s ); timeunit 1ns; timeprecision 100ps; - // local parameters +/* + * ============================================================================= + * local parameters + * ============================================================================= + */ + // general localparam BUFFER_COUNTER_BITS = $clog2(BIT_DEPTH); - // i2s states - typedef enum logic [3:0] { - RESET = 4'b0000, - IDLE = 4'b0001, - LEFT = 4'b0010, - RIGHT = 4'b0100, - ERROR = 4'b1000 + // clk dividers + localparam BCLK_COUNTER_BITS = $clog2(BCLK_DIV); + localparam LRCLK_COUNTER_BITS = $clog2(LRCLK_DIV); + + +/* + * ============================================================================= + * states + * ============================================================================= + */ + // I2S states + typedef enum logic [7:0] { + RESET = 8'b00000000, + IDLE = 8'b00000001, + LEFT_START = 8'b00000010, + LEFT = 8'b00000100, + LEFT_IDLE = 8'b00001000, + RIGHT_START = 8'b00010000, + RIGHT = 8'b00100000, + RIGHT_IDLE = 8'b01000000, + ERROR = 8'b10000000 } i2s_state_t; + +/* + * ============================================================================= + * bclk clk divider + * ============================================================================= + */ +logic [BCLK_COUNTER_BITS-1:0] bclk_counter; + +// bclk counter +always_ff @( posedge mclk ) begin : _bclk_clk_counter + if (!rst_n) + bclk_counter <= '0; + else if (bclk_counter == '0) + bclk_counter <= (BCLK_COUNTER_BITS)'(LRCLK_DIV - 1); + else + bclk_counter <= bclk_counter - 1; +end + +// bclk_output +always_comb begin : _bclk_clk_divider + if (bclk_counter[BCLK_COUNTER_BITS-1:0] >= (BCLK_COUNTER_BITS)'(BCLK_DIV / 2)) + bclk = 0; + else + bclk = 1; +end + +// always_ff @( posedge mclk ) begin : _bclk_clk_divider +// if (!rst_n) +// bclk <= 0; +// else if (clk_counter[BCLK_COUNTER_BITS-1:0] >= (BCLK_COUNTER_BITS)'(BCLK_DIV / 2)) +// bclk <= 0; +// else +// bclk <= 1; +// end + + /* * ============================================================================= * receive @@ -63,7 +121,7 @@ module i2s logic [BIT_DEPTH-1:0] input_buffer; // rx current state logic - always_ff @( posedge clk ) begin : _rx_current_state_logic + always_ff @( posedge mclk ) begin : _rx_current_state_logic if (!rst_n) rx_state <= RESET; else @@ -74,15 +132,27 @@ module i2s always_comb begin : _rx_next_state_logic unique case (rx_state) RESET: - rx_next_state = LEFT; + rx_next_state = LEFT_START; IDLE: - rx_next_state = LEFT; + rx_next_state = LEFT_START; + LEFT_START: + if (bclk_counter == '0) + rx_next_state = LEFT; LEFT: if (rx_bit_counter == '0) + rx_next_state = LEFT_IDLE; + LEFT_IDLE: + if (rx_lrclk == 1) // unsure if this will work with 32 bit words + rx_next_state = RIGHT_START; + RIGHT_START: + if (bclk_counter == '0) rx_next_state = RIGHT; RIGHT: if (rx_bit_counter == '0) - rx_next_state = LEFT; + rx_next_state = RIGHT_IDLE; + RIGHT_IDLE: + if (rx_lrclk == 0) // unsure if this will work with 32 bit words + rx_next_state = LEFT_START; ERROR: rx_next_state = ERROR; default: @@ -93,16 +163,56 @@ module i2s // rx fsm outputs always_comb begin : _rx_fsm_outputs unique case (rx_state) - RESET, ERROR: {rx_shift_en, rx_bit_counter_rst_n} = 2'b01; - IDLE: {rx_shift_en, rx_bit_counter_rst_n} = 2'b10; - LEFT: {rx_shift_en, rx_bit_counter_rst_n} = 2'b11; - RIGHT: {rx_shift_en, rx_bit_counter_rst_n} = 2'b11; - default: {rx_shift_en, rx_bit_counter_rst_n} = 2'b01; + RESET, ERROR: begin + {rx_shift_en, rx_bit_counter_rst_n} = 2'b00; + {rx_lrclk_rst_n} = 1'b0; + {rx_valid} = 1'b0; + end + IDLE: begin + {rx_shift_en, rx_bit_counter_rst_n} = 2'b00; + {rx_lrclk_rst_n} = 1'b0; + {rx_valid} = 1'b0; + end + LEFT_START: begin + {rx_shift_en, rx_bit_counter_rst_n} = 2'b00; + {rx_lrclk_rst_n} = 1'b1; + {rx_valid} = 1'b1; // TODO: this will not be valid first sample after reset + end + LEFT: begin + {rx_shift_en, rx_bit_counter_rst_n} = 2'b11; + {rx_lrclk_rst_n} = 1'b1; + {rx_valid} = 1'b0; + end + LEFT_IDLE: begin + {rx_shift_en, rx_bit_counter_rst_n} = 2'b00; + {rx_lrclk_rst_n} = 1'b1; + {rx_valid} = 1'b1; + end + RIGHT_START: begin + {rx_shift_en, rx_bit_counter_rst_n} = 2'b00; + {rx_lrclk_rst_n} = 1'b1; + {rx_valid} = 1'b1; // TODO: this will not be valid first sample after reset + end + RIGHT: begin + {rx_shift_en, rx_bit_counter_rst_n} = 2'b11; + {rx_lrclk_rst_n} = 1'b1; + {rx_valid} = 1'b0; + end + RIGHT_IDLE: begin + {rx_shift_en, rx_bit_counter_rst_n} = 2'b00; + {rx_lrclk_rst_n} = 1'b1; + {rx_valid} = 1'b1; + end + default: begin + {rx_shift_en, rx_bit_counter_rst_n} = 2'b00; + {rx_lrclk_rst_n} = 1'b0; + {rx_valid} = 1'b0; + end endcase end // receive shift register - always_ff @( posedge clk) begin : _rx_shift_register + always_ff @( posedge bclk ) begin : _rx_shift_register if (!rst_n) rx_data <= '0; else if (rx_shift_en) @@ -112,7 +222,7 @@ module i2s end // rx bit counter - always_ff @( posedge clk ) begin : _rx_bit_counter + always_ff @( posedge bclk ) begin : _rx_bit_counter if (!rx_bit_counter_rst_n) rx_bit_counter <= BIT_DEPTH; else if (rx_bit_counter == '0) @@ -121,6 +231,29 @@ module i2s rx_bit_counter <= rx_bit_counter - 1; end + logic rx_lrclk_rst_n; + logic [LRCLK_COUNTER_BITS-1:0] rx_lrclk_counter; + + // rx lrclk counter + always_ff @( posedge mclk ) begin : _rx_lrclk_clk_counter + if (!rx_lrclk_rst_n) + rx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 1); + else if (rx_lrclk_counter == '0) + rx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 1); + else + rx_lrclk_counter <= rx_lrclk_counter - 1; + end + + // rx lrclk output + always_comb begin : _rx_lrclk_clk_div + if (!rx_lrclk_rst_n) + rx_lrclk = 1; + else if (rx_lrclk_counter[LRCLK_COUNTER_BITS-1:0] >= (LRCLK_COUNTER_BITS)'(LRCLK_DIV / 2)) + rx_lrclk = 0; + else + rx_lrclk = 1; + end + endmodule : i2s `default_nettype wire diff --git a/hardware/verif/py/interfaces/test_i2s.py b/hardware/verif/py/interfaces/test_i2s.py new file mode 100644 index 0000000..dc2bc3e --- /dev/null +++ b/hardware/verif/py/interfaces/test_i2s.py @@ -0,0 +1,169 @@ +""" +Tests for I2S module. +""" + +import random +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import ClockCycles, RisingEdge, FallingEdge + +import hardware.verif.py.cocotb_runner + +from hardware.util.verif import repeat, parameterize + + +@cocotb.test() +@repeat(num_repeats=3) +async def i2s_random_read(dut, bit_depth: int = None): + """ + Test random reads with a I2S main. + """ + # setup module parameters and variables + bit_depth = 24 + + # setup clock + clock_period_ns = int(1e9 / 12e6) + clock = Clock(signal=dut.mclk, period=clock_period_ns, units="ns") + await cocotb.start(clock.start()) + + # setup inputs + dut.rx.value = 0 # I2S idle high + + # reset + dut.rst_n.value = 0 + await ClockCycles(signal=dut.mclk, num_cycles=2, rising=True) + dut.rst_n.value = 1 + # await ClockCycles(signal=dut.mclk, num_cycles=5, rising=True) + + await ClockCycles(signal=dut.rx_lrclk, num_cycles=1, rising=False) + await ClockCycles( + signal=dut.bclk, num_cycles=1, rising=False + ) # I2S typically starts shifting out on the second falling edge of bclk + + for sample in range(0, 4): + # receive bits + read_data = random.randint(0, 2**bit_depth - 1) + for index in range(0, bit_depth): + dut.rx.value = (read_data >> (bit_depth - index - 1)) & 0b1 + await ClockCycles(signal=dut.bclk, num_cycles=1, rising=False) + + # pad rest of lrclk frame, assert lrclk + assert dut.rx_lrclk.value == sample % 2 + await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) + + # assert receive data, receive valid, and lrclk + assert dut.rx_data.value == read_data + assert dut.rx_valid.value == 1 + + +# @cocotb.test() +# @repeat(num_repeats=10) +# async def uart_random_write(dut): +# """ +# Test random writes with a UART main. +# """ +# # setup module parameters and variables +# buffer_width = 8 +# write_data = random.randint(0, 2**buffer_width - 1) +# clk_cycles_till_sample = int(dut.CLK_CYCLES_PER_BIT.value / 2) + +# # setup clock +# clock_period_ns = int(1e9 / dut.CLK_FREQ.value) +# clock = Clock(signal=dut.clk, period=clock_period_ns, units="ns") +# await cocotb.start(clock.start()) + +# # reset +# dut.rst_n.value = 0 +# await ClockCycles(signal=dut.clk, num_cycles=2, rising=True) +# dut.rst_n.value = 1 +# await ClockCycles(signal=dut.clk, num_cycles=2, rising=True) + +# # await for write_ready, continue if already high +# if not dut.write_ready.value: +# await RisingEdge(signal=dut.write_ready) +# dut.write_data.value = write_data +# dut.write_valid.value = 1 + +# # start bit +# await FallingEdge(signal=dut.tx) +# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) +# assert dut.tx.value == 0 + +# # write bits +# for index in range(0, 8): +# await ClockCycles(signal=dut.clk, num_cycles=dut.CLK_CYCLES_PER_BIT.value) +# assert dut.tx.value == (write_data >> index) & 0b1 +# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) + +# # stop transmit +# dut.write_valid.value = 0 + +# # stop bit +# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) +# assert dut.tx.value == 0b1 + +# # idle and cooldown +# await ClockCycles(signal=dut.clk, num_cycles=5) + + +# @cocotb.test() +# @repeat(num_repeats=10) +# async def uart_random_full_duplex(dut): +# """ +# Test random UART receive and transmit concurrently. +# """ +# # setup module parameters and variables +# buffer_width = 8 +# write_data = random.randint(0, 2**buffer_width - 1) +# clk_cycles_till_sample = int(dut.CLK_CYCLES_PER_BIT.value / 2) + +# # setup clock +# clock_period_ns = int(1e9 / dut.CLK_FREQ.value) +# clock = Clock(signal=dut.clk, period=clock_period_ns, units="ns") +# await cocotb.start(clock.start()) + +# # setup inputs +# dut.rx.value = 1 # UART idle high + +# # reset +# dut.rst_n.value = 0 +# await ClockCycles(signal=dut.clk, num_cycles=2, rising=True) +# dut.rst_n.value = 1 +# await ClockCycles(signal=dut.clk, num_cycles=2, rising=True) + +# # await for write_ready, continue if already high +# if not dut.write_ready.value: +# await RisingEdge(signal=dut.write_ready) +# dut.write_data.value = write_data +# dut.write_valid.value = 1 + +# # start bit +# dut.rx.value = 0 +# await FallingEdge(signal=dut.tx) +# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) +# assert dut.tx.value == 0 + +# # read and write bits +# read_data = random.randint(0, 2**buffer_width - 1) +# for index in range(0, 8): +# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) +# dut.rx.value = (read_data >> index) & 0b1 +# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) +# assert dut.tx.value == (write_data >> index) & 0b1 +# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) + +# # stop transmit and assert read data +# dut.write_valid.value = 0 +# assert dut.read_data.value == read_data + +# # stop bit +# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) +# assert dut.tx.value == 0b1 + +# # idle and cooldown +# dut.rx.value = 1 +# await ClockCycles(signal=dut.clk, num_cycles=5) + + +def test_i2s(): + hardware.verif.py.cocotb_runner.run_cocotb(top="i2s", deps=[]) diff --git a/hardware/verif/py/interfaces/test_uart.py b/hardware/verif/py/interfaces/test_uart.py index c0f8eaf..4d102ee 100644 --- a/hardware/verif/py/interfaces/test_uart.py +++ b/hardware/verif/py/interfaces/test_uart.py @@ -1,5 +1,5 @@ """ -Test for UART module. +Tests for UART module. """ import random @@ -14,7 +14,7 @@ @cocotb.test() @repeat(num_repeats=10) -async def uart_random_read(dut, buffer_width: int = None): +async def uart_random_receive(dut, buffer_width: int = None): """ Test random reads with a UART main. """ @@ -65,7 +65,7 @@ async def uart_random_read(dut, buffer_width: int = None): @cocotb.test() @repeat(num_repeats=10) -async def uart_random_write(dut): +async def uart_random_transmit(dut): """ Test random writes with a UART main. """ From 0e87e28ccb71b430734bc3c470331a83a4bf3097 Mon Sep 17 00:00:00 2001 From: Drew Date: Thu, 1 May 2025 15:13:14 -0400 Subject: [PATCH 04/10] add i2s waves --- hardware/waves/interfaces/i2s.ron | 562 ++++++++++++++++++++++++++++++ 1 file changed, 562 insertions(+) create mode 100644 hardware/waves/interfaces/i2s.ron diff --git a/hardware/waves/interfaces/i2s.ron b/hardware/waves/interfaces/i2s.ron new file mode 100644 index 0000000..f7f79bf --- /dev/null +++ b/hardware/waves/interfaces/i2s.ron @@ -0,0 +1,562 @@ +( + show_hierarchy: None, + show_menu: None, + show_ticks: None, + show_toolbar: None, + show_tooltip: None, + show_scope_tooltip: None, + show_default_timeline: None, + show_overview: None, + show_statusbar: None, + align_names_right: None, + show_variable_indices: None, + show_variable_direction: None, + show_empty_scopes: None, + show_parameters_in_scopes: None, + highlight_focused: None, + waves: Some(( + source: File("../sim_build/i2s/i2s.fst"), + format: Fst, + active_scope: Some(WaveScope(( + strs: [ + "i2s", + ], + ))), + items_tree: ( + items: [ + ( + item_ref: (5), + level: 0, + unfolded: true, + selected: false, + ), + ( + item_ref: (2), + level: 0, + unfolded: true, + selected: false, + ), + ( + item_ref: (1), + level: 0, + unfolded: true, + selected: false, + ), + ( + item_ref: (3), + level: 0, + unfolded: true, + selected: false, + ), + ( + item_ref: (4), + level: 0, + unfolded: true, + selected: false, + ), + ( + item_ref: (21), + level: 0, + unfolded: true, + selected: false, + ), + ( + item_ref: (11), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (14), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (6), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (12), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (15), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (10), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (8), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (7), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (13), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (9), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (22), + level: 0, + unfolded: true, + selected: false, + ), + ( + item_ref: (16), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (19), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (20), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (18), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (17), + level: 1, + unfolded: true, + selected: false, + ), + ], + ), + displayed_items: { + (9): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_data", + ), + color: None, + background_color: None, + display_name: "rx_data [23:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (15): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_valid", + ), + color: None, + background_color: None, + display_name: "rx_valid", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (4): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "mute", + ), + color: None, + background_color: None, + display_name: "mute", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (8): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_bit_counter_rst_n", + ), + color: None, + background_color: None, + display_name: "rx_bit_counter_rst_n", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (11): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_next_state", + ), + color: None, + background_color: None, + display_name: "rx_next_state [3:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (12): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_ready", + ), + color: None, + background_color: None, + display_name: "rx_ready", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (6): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx", + ), + color: None, + background_color: None, + display_name: "rx", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (18): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "tx_lr_clk", + ), + color: None, + background_color: None, + display_name: "tx_lr_clk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (19): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "tx_ready", + ), + color: None, + background_color: None, + display_name: "tx_ready", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (1): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "blck", + ), + color: None, + background_color: None, + display_name: "blck", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (20): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "tx_valid", + ), + color: None, + background_color: None, + display_name: "tx_valid", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (22): Group(( + name: "transmit", + color: Some("Gray"), + background_color: Some("Gray"), + content: [], + is_open: false, + )), + (5): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rst_n", + ), + color: None, + background_color: None, + display_name: "rst_n", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (16): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "tx", + ), + color: None, + background_color: None, + display_name: "tx", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (21): Group(( + name: "receive", + color: Some("Gray"), + background_color: Some("Gray"), + content: [], + is_open: false, + )), + (17): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "tx_data", + ), + color: None, + background_color: None, + display_name: "tx_data [23:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (13): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_shift_en", + ), + color: None, + background_color: None, + display_name: "rx_shift_en", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (7): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_bit_counter", + ), + color: None, + background_color: None, + display_name: "rx_bit_counter [4:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (2): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "clk", + ), + color: None, + background_color: None, + display_name: "clk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (14): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_state", + ), + color: None, + background_color: None, + display_name: "rx_state [3:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (3): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "mclk", + ), + color: None, + background_color: None, + display_name: "mclk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (10): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_lr_clk", + ), + color: None, + background_color: None, + display_name: "rx_lr_clk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + }, + display_item_ref_counter: 22, + viewports: [ + ( + curr_left: (0.0), + curr_right: (1.3999999999999997), + target_left: (0.0), + target_right: (1.0), + move_start_left: (0.0), + move_start_right: (1.0), + move_duration: None, + move_strategy: Instant, + ), + ], + cursor: None, + markers: {}, + focused_item: None, + focused_transaction: (None, None), + default_variable_name_type: Unique, + scroll_offset: 0.0, + display_variable_indices: true, + graphics: {}, + )), + drag_started: false, + drag_source_idx: None, + drag_target_idx: None, + previous_waves: None, + count: None, + blacklisted_translators: [], + show_about: false, + show_keys: false, + show_gestures: false, + show_quick_start: false, + show_license: false, + show_performance: false, + show_logs: false, + show_cursor_window: false, + wanted_timeunit: PicoSeconds, + time_string_format: None, + show_url_entry: false, + variable_name_filter_focused: false, + variable_name_filter_type: Fuzzy, + variable_name_filter_case_insensitive: true, + rename_target: None, + sidepanel_width: Some(100.0), + ui_zoom_factor: None, +) \ No newline at end of file From fbb1896fd4ec8d1fd547552baf579e401e9d662f Mon Sep 17 00:00:00 2001 From: Drew Date: Thu, 1 May 2025 16:18:14 -0400 Subject: [PATCH 05/10] add i2s transmit test, i2s transmit hw --- hardware/hdl/interfaces/i2s.sv | 156 ++++++++++++- hardware/hdl/interfaces/uart.sv | 2 +- hardware/verif/py/interfaces/test_i2s.py | 160 +++++-------- hardware/waves/interfaces/i2s.ron | 271 ++++++++++++++--------- 4 files changed, 373 insertions(+), 216 deletions(-) diff --git a/hardware/hdl/interfaces/i2s.sv b/hardware/hdl/interfaces/i2s.sv index 937d591..e5284a5 100644 --- a/hardware/hdl/interfaces/i2s.sv +++ b/hardware/hdl/interfaces/i2s.sv @@ -30,10 +30,10 @@ module i2s output logic rx_valid, // i2s tx - input wire tx, + output logic tx, output logic tx_lrclk, input logic [BIT_DEPTH-1:0] tx_data, - input wire tx_ready, + output logic tx_ready, input wire tx_valid, // device specific //TODO: move to higher level module @@ -98,6 +98,7 @@ always_comb begin : _bclk_clk_divider bclk = 1; end +// TODO: synthesis difference between this and the block above // always_ff @( posedge mclk ) begin : _bclk_clk_divider // if (!rst_n) // bclk <= 0; @@ -118,7 +119,6 @@ end i2s_state_t rx_state, rx_next_state; logic [BUFFER_COUNTER_BITS-1:0] rx_bit_counter; logic rx_shift_en, rx_bit_counter_rst_n; - logic [BIT_DEPTH-1:0] input_buffer; // rx current state logic always_ff @( posedge mclk ) begin : _rx_current_state_logic @@ -136,7 +136,7 @@ end IDLE: rx_next_state = LEFT_START; LEFT_START: - if (bclk_counter == '0) + if (bclk_counter == '0) // bclk falling edge rx_next_state = LEFT; LEFT: if (rx_bit_counter == '0) @@ -145,7 +145,7 @@ end if (rx_lrclk == 1) // unsure if this will work with 32 bit words rx_next_state = RIGHT_START; RIGHT_START: - if (bclk_counter == '0) + if (bclk_counter == '0) // bclk falling edge rx_next_state = RIGHT; RIGHT: if (rx_bit_counter == '0) @@ -254,6 +254,152 @@ end rx_lrclk = 1; end + /* + * ============================================================================= + * transmit + * ============================================================================= + */ + + // internal tx variables + i2s_state_t tx_state, tx_next_state; + logic [BUFFER_COUNTER_BITS-1:0] tx_bit_counter; + logic tx_shift_en, tx_bit_counter_rst_n; + + // tx current state logic + always_ff @( posedge mclk ) begin : _tx_current_state_logic + if (!rst_n) + tx_state <= RESET; + else + tx_state <= tx_next_state; + end + + // rx next state logic + always_comb begin : _tx_next_state_logic + unique case (tx_state) + RESET: + tx_next_state = LEFT_START; + IDLE: + if (tx_valid) + tx_next_state = LEFT_START; + LEFT_START: + if (bclk_counter == '0) // bclk falling edge + tx_next_state = LEFT; + LEFT: + if (tx_bit_counter == '0) + tx_next_state = LEFT_IDLE; + LEFT_IDLE: + if (tx_lrclk == 1) // unsure if this will work with 32 bit words + tx_next_state = RIGHT_START; + RIGHT_START: + if (bclk_counter == '0) // bclk falling edge + tx_next_state = RIGHT; + RIGHT: + if (tx_bit_counter == '0) + tx_next_state = RIGHT_IDLE; + RIGHT_IDLE: + if (tx_lrclk == 0) // unsure if this will work with 32 bit words + tx_next_state = LEFT_START; + ERROR: + tx_next_state = ERROR; + default: + tx_next_state = ERROR; // catch glitches + endcase + end + + // tx fsm outputs + always_comb begin : _tx_fsm_outputs + unique case (rx_state) + RESET, ERROR: begin + {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; + {tx_lrclk_rst_n} = 1'b0; + {tx_ready} = 1'b0; + end + IDLE: begin + {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; + {tx_lrclk_rst_n} = 1'b0; + {tx_ready} = 1'b1; + end + LEFT_START: begin + {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; + {tx_lrclk_rst_n} = 1'b1; + {tx_ready} = 1'b0; + end + LEFT: begin + {tx_shift_en, tx_bit_counter_rst_n} = 2'b11; + {tx_lrclk_rst_n} = 1'b1; + {tx_ready} = 1'b0; + end + LEFT_IDLE: begin + {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; + {tx_lrclk_rst_n} = 1'b1; + {tx_ready} = 1'b0; + end + RIGHT_START: begin + {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; + {tx_lrclk_rst_n} = 1'b1; + {tx_ready} = 1'b0; + end + RIGHT: begin + {tx_shift_en, tx_bit_counter_rst_n} = 2'b11; + {tx_lrclk_rst_n} = 1'b1; + {tx_ready} = 1'b0; + end + RIGHT_IDLE: begin + {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; + {tx_lrclk_rst_n} = 1'b1; + {tx_ready} = 1'b0; + end + default: begin + {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; + {tx_lrclk_rst_n} = 1'b0; + {tx_ready} = 1'b0; + end + endcase + end + + // receive shift register + always_ff @( posedge bclk ) begin : _tx_shift_register + if (!rst_n) + tx <= 0; + else if (tx_shift_en) + tx <= tx_data[tx_bit_counter]; // msb first + else + tx <= tx; + end + + // tx bit counter + always_ff @( posedge bclk ) begin : _tx_bit_counter + if (!rx_bit_counter_rst_n) + rx_bit_counter <= BIT_DEPTH; + else if (rx_bit_counter == '0) + rx_bit_counter <= BIT_DEPTH - 1; + else + rx_bit_counter <= rx_bit_counter - 1; + end + + logic tx_lrclk_rst_n; + logic [LRCLK_COUNTER_BITS-1:0] tx_lrclk_counter; + + // tx lrclk counter + always_ff @( posedge mclk ) begin : _tx_lrclk_clk_counter + if (!tx_lrclk_rst_n) + tx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 1); + else if (tx_lrclk_counter == '0) + tx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 1); + else + tx_lrclk_counter <= tx_lrclk_counter - 1; + end + + // tx lrclk output + always_comb begin : _tx_lrclk_clk_div + if (!tx_lrclk_rst_n) + tx_lrclk = 1; + else if (tx_lrclk_counter[LRCLK_COUNTER_BITS-1:0] >= (LRCLK_COUNTER_BITS)'(LRCLK_DIV / 2)) + tx_lrclk = 0; + else + tx_lrclk = 1; + end + endmodule : i2s `default_nettype wire diff --git a/hardware/hdl/interfaces/uart.sv b/hardware/hdl/interfaces/uart.sv index 1ed3bdf..17ac30d 100644 --- a/hardware/hdl/interfaces/uart.sv +++ b/hardware/hdl/interfaces/uart.sv @@ -311,7 +311,7 @@ module uart else if (tx_next_state == TX_IDLE) // Potentially sketchy. Cycle steal to prevent glitches on tx tx <= '1; - else if (tx_state == TX_START) + else if (tx_state == TX_START) // TODO: should be able to put this in the fsm output block tx <= '0; else if (tx_shift_en) tx <= write_data[BUFFER_WIDTH - tx_bit_counter]; // lsb first diff --git a/hardware/verif/py/interfaces/test_i2s.py b/hardware/verif/py/interfaces/test_i2s.py index dc2bc3e..1937c86 100644 --- a/hardware/verif/py/interfaces/test_i2s.py +++ b/hardware/verif/py/interfaces/test_i2s.py @@ -14,9 +14,9 @@ @cocotb.test() @repeat(num_repeats=3) -async def i2s_random_read(dut, bit_depth: int = None): +async def i2s_random_receive(dut, bit_depth: int = None): """ - Test random reads with a I2S main. + Test random receives with a I2S main. """ # setup module parameters and variables bit_depth = 24 @@ -33,8 +33,8 @@ async def i2s_random_read(dut, bit_depth: int = None): dut.rst_n.value = 0 await ClockCycles(signal=dut.mclk, num_cycles=2, rising=True) dut.rst_n.value = 1 - # await ClockCycles(signal=dut.mclk, num_cycles=5, rising=True) + # await start of lrclk frame await ClockCycles(signal=dut.rx_lrclk, num_cycles=1, rising=False) await ClockCycles( signal=dut.bclk, num_cycles=1, rising=False @@ -42,9 +42,9 @@ async def i2s_random_read(dut, bit_depth: int = None): for sample in range(0, 4): # receive bits - read_data = random.randint(0, 2**bit_depth - 1) + receive_data = random.randint(0, 2**bit_depth - 1) for index in range(0, bit_depth): - dut.rx.value = (read_data >> (bit_depth - index - 1)) & 0b1 + dut.rx.value = (receive_data >> (bit_depth - index - 1)) & 0b1 await ClockCycles(signal=dut.bclk, num_cycles=1, rising=False) # pad rest of lrclk frame, assert lrclk @@ -52,117 +52,57 @@ async def i2s_random_read(dut, bit_depth: int = None): await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) # assert receive data, receive valid, and lrclk - assert dut.rx_data.value == read_data + assert dut.rx_data.value == receive_data assert dut.rx_valid.value == 1 -# @cocotb.test() -# @repeat(num_repeats=10) -# async def uart_random_write(dut): -# """ -# Test random writes with a UART main. -# """ -# # setup module parameters and variables -# buffer_width = 8 -# write_data = random.randint(0, 2**buffer_width - 1) -# clk_cycles_till_sample = int(dut.CLK_CYCLES_PER_BIT.value / 2) - -# # setup clock -# clock_period_ns = int(1e9 / dut.CLK_FREQ.value) -# clock = Clock(signal=dut.clk, period=clock_period_ns, units="ns") -# await cocotb.start(clock.start()) - -# # reset -# dut.rst_n.value = 0 -# await ClockCycles(signal=dut.clk, num_cycles=2, rising=True) -# dut.rst_n.value = 1 -# await ClockCycles(signal=dut.clk, num_cycles=2, rising=True) - -# # await for write_ready, continue if already high -# if not dut.write_ready.value: -# await RisingEdge(signal=dut.write_ready) -# dut.write_data.value = write_data -# dut.write_valid.value = 1 - -# # start bit -# await FallingEdge(signal=dut.tx) -# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) -# assert dut.tx.value == 0 - -# # write bits -# for index in range(0, 8): -# await ClockCycles(signal=dut.clk, num_cycles=dut.CLK_CYCLES_PER_BIT.value) -# assert dut.tx.value == (write_data >> index) & 0b1 -# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) - -# # stop transmit -# dut.write_valid.value = 0 - -# # stop bit -# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) -# assert dut.tx.value == 0b1 - -# # idle and cooldown -# await ClockCycles(signal=dut.clk, num_cycles=5) +@cocotb.test() +@repeat(num_repeats=1) +async def i2s_random_transmit(dut, bit_depth: int = None): + """ + Test random transmits with a I2S main. + """ + # setup module parameters and variables + bit_depth = 24 + + # setup clock + clock_period_ns = int(1e9 / 12e6) + clock = Clock(signal=dut.mclk, period=clock_period_ns, units="ns") + await cocotb.start(clock.start()) + + # reset + dut.rst_n.value = 0 + await ClockCycles(signal=dut.mclk, num_cycles=2, rising=True) + dut.rst_n.value = 1 + + # await for transmit_ready, continue if already high + if not dut.tx_ready.value: + await RisingEdge(signal=dut.tx_ready) + dut.rx_valid.value = 1 + + # await start of lrclk frame + await ClockCycles(signal=dut.rx_lrclk, num_cycles=1, rising=False) + await ClockCycles( + signal=dut.bclk, num_cycles=1, rising=False + ) # I2S typically starts shifting out on the second falling edge of bclk + + for sample in range(0, 1): + # receive bits + transmit_data = random.randint(0, 2**bit_depth - 1) + dut.tx_data.value = transmit_data + for index in range(0, bit_depth): + await ClockCycles(signal=dut.bclk, num_cycles=1, rising=True) + assert dut.tx.value == (transmit_data >> (bit_depth - index)) & 0b1 + + # pad rest of lrclk frame, assert lrclk + assert dut.rx_lrclk.value == sample % 2 + await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) # @cocotb.test() -# @repeat(num_repeats=10) -# async def uart_random_full_duplex(dut): -# """ -# Test random UART receive and transmit concurrently. -# """ -# # setup module parameters and variables -# buffer_width = 8 -# write_data = random.randint(0, 2**buffer_width - 1) -# clk_cycles_till_sample = int(dut.CLK_CYCLES_PER_BIT.value / 2) - -# # setup clock -# clock_period_ns = int(1e9 / dut.CLK_FREQ.value) -# clock = Clock(signal=dut.clk, period=clock_period_ns, units="ns") -# await cocotb.start(clock.start()) - -# # setup inputs -# dut.rx.value = 1 # UART idle high - -# # reset -# dut.rst_n.value = 0 -# await ClockCycles(signal=dut.clk, num_cycles=2, rising=True) -# dut.rst_n.value = 1 -# await ClockCycles(signal=dut.clk, num_cycles=2, rising=True) - -# # await for write_ready, continue if already high -# if not dut.write_ready.value: -# await RisingEdge(signal=dut.write_ready) -# dut.write_data.value = write_data -# dut.write_valid.value = 1 - -# # start bit -# dut.rx.value = 0 -# await FallingEdge(signal=dut.tx) -# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) -# assert dut.tx.value == 0 - -# # read and write bits -# read_data = random.randint(0, 2**buffer_width - 1) -# for index in range(0, 8): -# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) -# dut.rx.value = (read_data >> index) & 0b1 -# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) -# assert dut.tx.value == (write_data >> index) & 0b1 -# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) - -# # stop transmit and assert read data -# dut.write_valid.value = 0 -# assert dut.read_data.value == read_data - -# # stop bit -# await ClockCycles(signal=dut.clk, num_cycles=clk_cycles_till_sample) -# assert dut.tx.value == 0b1 - -# # idle and cooldown -# dut.rx.value = 1 -# await ClockCycles(signal=dut.clk, num_cycles=5) +# @repeat(num_repeats=1) +# async def i2s_random_full_duplex(dut, bit_depth: int = None): +# pass def test_i2s(): diff --git a/hardware/waves/interfaces/i2s.ron b/hardware/waves/interfaces/i2s.ron index f7f79bf..fa2d417 100644 --- a/hardware/waves/interfaces/i2s.ron +++ b/hardware/waves/interfaces/i2s.ron @@ -25,31 +25,31 @@ items_tree: ( items: [ ( - item_ref: (5), + item_ref: (28), level: 0, unfolded: true, selected: false, ), ( - item_ref: (2), + item_ref: (27), level: 0, unfolded: true, selected: false, ), ( - item_ref: (1), + item_ref: (26), level: 0, unfolded: true, selected: false, ), ( - item_ref: (3), + item_ref: (23), level: 0, unfolded: true, selected: false, ), ( - item_ref: (4), + item_ref: (24), level: 0, unfolded: true, selected: false, @@ -61,61 +61,79 @@ selected: false, ), ( - item_ref: (11), + item_ref: (32), level: 1, unfolded: true, selected: false, ), ( - item_ref: (14), + item_ref: (29), level: 1, unfolded: true, selected: false, ), ( - item_ref: (6), + item_ref: (37), level: 1, unfolded: true, selected: false, ), ( - item_ref: (12), + item_ref: (40), level: 1, unfolded: true, selected: false, ), ( - item_ref: (15), + item_ref: (69), level: 1, unfolded: true, selected: false, ), ( - item_ref: (10), + item_ref: (39), level: 1, unfolded: true, selected: false, ), ( - item_ref: (8), + item_ref: (36), level: 1, unfolded: true, selected: false, ), ( - item_ref: (7), + item_ref: (38), level: 1, unfolded: true, selected: false, ), ( - item_ref: (13), + item_ref: (33), level: 1, unfolded: true, selected: false, ), ( - item_ref: (9), + item_ref: (31), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (30), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (35), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (34), level: 1, unfolded: true, selected: false, @@ -127,31 +145,31 @@ selected: false, ), ( - item_ref: (16), + item_ref: (41), level: 1, unfolded: true, selected: false, ), ( - item_ref: (19), + item_ref: (42), level: 1, unfolded: true, selected: false, ), ( - item_ref: (20), + item_ref: (43), level: 1, unfolded: true, selected: false, ), ( - item_ref: (18), + item_ref: (44), level: 1, unfolded: true, selected: false, ), ( - item_ref: (17), + item_ref: (45), level: 1, unfolded: true, selected: false, @@ -159,276 +177,262 @@ ], ), displayed_items: { - (9): Variable(( + (45): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_data", + name: "tx_valid", ), color: None, background_color: None, - display_name: "rx_data [23:0]", + display_name: "tx_valid", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (15): Variable(( + (38): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_valid", + name: "rx_shift_en", ), color: None, background_color: None, - display_name: "rx_valid", + display_name: "rx_shift_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (4): Variable(( + (34): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "mute", + name: "rx_lrclk_counter", ), color: None, background_color: None, - display_name: "mute", + display_name: "rx_lrclk_counter [7:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (8): Variable(( + (42): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_bit_counter_rst_n", + name: "tx_data", ), color: None, background_color: None, - display_name: "rx_bit_counter_rst_n", + display_name: "tx_data [23:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (11): Variable(( + (28): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_next_state", + name: "rst_n", ), color: None, background_color: None, - display_name: "rx_next_state [3:0]", + display_name: "rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (12): Variable(( + (24): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_ready", + name: "bclk_counter", ), color: None, background_color: None, - display_name: "rx_ready", + display_name: "bclk_counter [1:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (6): Variable(( + (69): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx", + name: "bclk", ), color: None, background_color: None, - display_name: "rx", + display_name: "bclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (18): Variable(( + (44): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_lr_clk", + name: "tx_ready", ), color: None, background_color: None, - display_name: "tx_lr_clk", + display_name: "tx_ready", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (19): Variable(( + (35): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_ready", + name: "rx_lrclk_rst_n", ), color: None, background_color: None, - display_name: "tx_ready", + display_name: "rx_lrclk_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (1): Variable(( + (32): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "blck", + name: "rx_data", ), color: None, background_color: None, - display_name: "blck", + display_name: "rx_data [23:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (20): Variable(( + (43): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_valid", + name: "tx_lrclk", ), color: None, background_color: None, - display_name: "tx_valid", + display_name: "tx_lrclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (22): Group(( - name: "transmit", - color: Some("Gray"), - background_color: Some("Gray"), - content: [], - is_open: false, - )), - (5): Variable(( + (31): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rst_n", + name: "rx_bit_counter_rst_n", ), color: None, background_color: None, - display_name: "rst_n", + display_name: "rx_bit_counter_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (16): Variable(( + (26): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx", + name: "mclk", ), color: None, background_color: None, - display_name: "tx", + display_name: "mclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (21): Group(( - name: "receive", - color: Some("Gray"), - background_color: Some("Gray"), - content: [], - is_open: false, - )), - (17): Variable(( + (27): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_data", + name: "mute", ), color: None, background_color: None, - display_name: "tx_data [23:0]", + display_name: "mute", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (13): Variable(( + (36): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_shift_en", + name: "rx_next_state", ), color: None, background_color: None, - display_name: "rx_shift_en", + display_name: "rx_next_state [7:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (7): Variable(( + (30): Variable(( variable_ref: ( path: ( strs: [ @@ -445,24 +449,48 @@ format: None, field_formats: [], )), - (2): Variable(( + (29): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "clk", + name: "rx", ), color: None, background_color: None, - display_name: "clk", + display_name: "rx", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (14): Variable(( + (23): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "bclk", + ), + color: None, + background_color: None, + display_name: "bclk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (22): Group(( + name: "transmit", + color: Some("Gray"), + background_color: Some("Gray"), + content: [], + is_open: false, + )), + (39): Variable(( variable_ref: ( path: ( strs: [ @@ -473,63 +501,106 @@ ), color: None, background_color: None, - display_name: "rx_state [3:0]", + display_name: "rx_state [7:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (3): Variable(( + (40): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "mclk", + name: "rx_valid", ), color: None, background_color: None, - display_name: "mclk", + display_name: "rx_valid", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (10): Variable(( + (37): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lr_clk", + name: "rx_ready", ), color: None, background_color: None, - display_name: "rx_lr_clk", + display_name: "rx_ready", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (21): Group(( + name: "receive", + color: Some("Gray"), + background_color: Some("Gray"), + content: [], + is_open: false, + )), + (33): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_lrclk", + ), + color: None, + background_color: None, + display_name: "rx_lrclk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (41): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "tx", + ), + color: None, + background_color: None, + display_name: "tx", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), }, - display_item_ref_counter: 22, + display_item_ref_counter: 72, viewports: [ ( curr_left: (0.0), - curr_right: (1.3999999999999997), - target_left: (0.0), - target_right: (1.0), - move_start_left: (0.0), - move_start_right: (1.0), + curr_right: (1.4), + target_left: (-0.2), + target_right: (1.2), + move_start_left: (-0.2), + move_start_right: (1.2), move_duration: None, move_strategy: Instant, ), ], - cursor: None, + cursor: Some((1, [ + 337902, + ])), markers: {}, - focused_item: None, + focused_item: Some((20)), focused_transaction: (None, None), default_variable_name_type: Unique, scroll_offset: 0.0, @@ -557,6 +628,6 @@ variable_name_filter_type: Fuzzy, variable_name_filter_case_insensitive: true, rename_target: None, - sidepanel_width: Some(100.0), + sidepanel_width: Some(217.5625), ui_zoom_factor: None, ) \ No newline at end of file From 5b3f386b6ae173ca26f2eed015cae81da9d799a8 Mon Sep 17 00:00:00 2001 From: Drew Date: Fri, 2 May 2025 11:55:16 -0400 Subject: [PATCH 06/10] add i2s progress --- hardware/hdl/interfaces/i2s.sv | 42 +-- hardware/verif/py/interfaces/test_i2s.py | 119 ++++---- hardware/waves/interfaces/i2s.ron | 355 +++++++++++++++++------ 3 files changed, 354 insertions(+), 162 deletions(-) diff --git a/hardware/hdl/interfaces/i2s.sv b/hardware/hdl/interfaces/i2s.sv index e5284a5..d5757c9 100644 --- a/hardware/hdl/interfaces/i2s.sv +++ b/hardware/hdl/interfaces/i2s.sv @@ -51,7 +51,8 @@ module i2s // clk dividers localparam BCLK_COUNTER_BITS = $clog2(BCLK_DIV); - localparam LRCLK_COUNTER_BITS = $clog2(LRCLK_DIV); + localparam LRCLK_BCLK_DIV = LRCLK_DIV/BCLK_DIV; + localparam LRCLK_COUNTER_BITS = $clog2(LRCLK_BCLK_DIV); /* @@ -81,10 +82,11 @@ module i2s logic [BCLK_COUNTER_BITS-1:0] bclk_counter; // bclk counter +initial bclk_counter = '0; always_ff @( posedge mclk ) begin : _bclk_clk_counter - if (!rst_n) - bclk_counter <= '0; - else if (bclk_counter == '0) + // if (!rst_n) + // bclk_counter <= '0; + if (bclk_counter == '0) bclk_counter <= (BCLK_COUNTER_BITS)'(LRCLK_DIV - 1); else bclk_counter <= bclk_counter - 1; @@ -248,7 +250,7 @@ end always_comb begin : _rx_lrclk_clk_div if (!rx_lrclk_rst_n) rx_lrclk = 1; - else if (rx_lrclk_counter[LRCLK_COUNTER_BITS-1:0] >= (LRCLK_COUNTER_BITS)'(LRCLK_DIV / 2)) + else if (rx_lrclk_counter[LRCLK_COUNTER_BITS-1:0] >= (LRCLK_COUNTER_BITS)'(LRCLK_BCLK_DIV / 2)) rx_lrclk = 0; else rx_lrclk = 1; @@ -273,11 +275,11 @@ end tx_state <= tx_next_state; end - // rx next state logic + // tx next state logic always_comb begin : _tx_next_state_logic unique case (tx_state) RESET: - tx_next_state = LEFT_START; + tx_next_state = IDLE; IDLE: if (tx_valid) tx_next_state = LEFT_START; @@ -308,7 +310,7 @@ end // tx fsm outputs always_comb begin : _tx_fsm_outputs - unique case (rx_state) + unique case (tx_state) RESET, ERROR: begin {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; {tx_lrclk_rst_n} = 1'b0; @@ -358,35 +360,37 @@ end end // receive shift register - always_ff @( posedge bclk ) begin : _tx_shift_register + always_ff @( posedge mclk ) begin : _tx_shift_register if (!rst_n) tx <= 0; else if (tx_shift_en) - tx <= tx_data[tx_bit_counter]; // msb first + tx <= tx_data[tx_bit_counter - 1]; // msb first else tx <= tx; end // tx bit counter always_ff @( posedge bclk ) begin : _tx_bit_counter - if (!rx_bit_counter_rst_n) - rx_bit_counter <= BIT_DEPTH; - else if (rx_bit_counter == '0) - rx_bit_counter <= BIT_DEPTH - 1; + if (!tx_bit_counter_rst_n) + tx_bit_counter <= BIT_DEPTH; + else if (tx_bit_counter == '0) + tx_bit_counter <= BIT_DEPTH - 1; else - rx_bit_counter <= rx_bit_counter - 1; + tx_bit_counter <= tx_bit_counter - 1; end logic tx_lrclk_rst_n; logic [LRCLK_COUNTER_BITS-1:0] tx_lrclk_counter; + initial tx_lrclk_counter = '0; // tx lrclk counter - always_ff @( posedge mclk ) begin : _tx_lrclk_clk_counter + always_ff @( posedge bclk ) begin : _tx_lrclk_counter if (!tx_lrclk_rst_n) - tx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 1); + tx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_BCLK_DIV - 1); else if (tx_lrclk_counter == '0) - tx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 1); + tx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_BCLK_DIV - 1); else + // tx_lrclk_counter <= '0; tx_lrclk_counter <= tx_lrclk_counter - 1; end @@ -394,7 +398,7 @@ end always_comb begin : _tx_lrclk_clk_div if (!tx_lrclk_rst_n) tx_lrclk = 1; - else if (tx_lrclk_counter[LRCLK_COUNTER_BITS-1:0] >= (LRCLK_COUNTER_BITS)'(LRCLK_DIV / 2)) + else if (tx_lrclk_counter >= (LRCLK_COUNTER_BITS)'(LRCLK_BCLK_DIV / 2)) tx_lrclk = 0; else tx_lrclk = 1; diff --git a/hardware/verif/py/interfaces/test_i2s.py b/hardware/verif/py/interfaces/test_i2s.py index 1937c86..2ee21d4 100644 --- a/hardware/verif/py/interfaces/test_i2s.py +++ b/hardware/verif/py/interfaces/test_i2s.py @@ -12,48 +12,48 @@ from hardware.util.verif import repeat, parameterize -@cocotb.test() -@repeat(num_repeats=3) -async def i2s_random_receive(dut, bit_depth: int = None): - """ - Test random receives with a I2S main. - """ - # setup module parameters and variables - bit_depth = 24 - - # setup clock - clock_period_ns = int(1e9 / 12e6) - clock = Clock(signal=dut.mclk, period=clock_period_ns, units="ns") - await cocotb.start(clock.start()) - - # setup inputs - dut.rx.value = 0 # I2S idle high - - # reset - dut.rst_n.value = 0 - await ClockCycles(signal=dut.mclk, num_cycles=2, rising=True) - dut.rst_n.value = 1 - - # await start of lrclk frame - await ClockCycles(signal=dut.rx_lrclk, num_cycles=1, rising=False) - await ClockCycles( - signal=dut.bclk, num_cycles=1, rising=False - ) # I2S typically starts shifting out on the second falling edge of bclk - - for sample in range(0, 4): - # receive bits - receive_data = random.randint(0, 2**bit_depth - 1) - for index in range(0, bit_depth): - dut.rx.value = (receive_data >> (bit_depth - index - 1)) & 0b1 - await ClockCycles(signal=dut.bclk, num_cycles=1, rising=False) - - # pad rest of lrclk frame, assert lrclk - assert dut.rx_lrclk.value == sample % 2 - await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) - - # assert receive data, receive valid, and lrclk - assert dut.rx_data.value == receive_data - assert dut.rx_valid.value == 1 +# @cocotb.test() +# @repeat(num_repeats=3) +# async def i2s_random_receive(dut, bit_depth: int = None): +# """ +# Test random receives with a I2S main. +# """ +# # setup module parameters and variables +# bit_depth = 24 + +# # setup clock +# clock_period_ns = int(1e9 / 12e6) +# clock = Clock(signal=dut.mclk, period=clock_period_ns, units="ns") +# await cocotb.start(clock.start()) + +# # setup inputs +# dut.rx.value = 0 # I2S idle high + +# # reset +# dut.rst_n.value = 0 +# await ClockCycles(signal=dut.mclk, num_cycles=2, rising=True) +# dut.rst_n.value = 1 + +# # await start of lrclk frame +# await ClockCycles(signal=dut.rx_lrclk, num_cycles=1, rising=False) +# await ClockCycles( +# signal=dut.bclk, num_cycles=1, rising=False +# ) # I2S typically starts shifting out on the second falling edge of bclk + +# for sample in range(0, 4): +# # receive bits +# receive_data = random.randint(0, 2**bit_depth - 1) +# for index in range(0, bit_depth): +# dut.rx.value = (receive_data >> (bit_depth - index - 1)) & 0b1 +# await ClockCycles(signal=dut.bclk, num_cycles=1, rising=False) + +# # pad rest of lrclk frame, assert lrclk +# assert dut.rx_lrclk.value == sample % 2 +# await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) + +# # assert receive data, receive valid, and lrclk +# assert dut.rx_data.value == receive_data +# assert dut.rx_valid.value == 1 @cocotb.test() @@ -78,25 +78,26 @@ async def i2s_random_transmit(dut, bit_depth: int = None): # await for transmit_ready, continue if already high if not dut.tx_ready.value: await RisingEdge(signal=dut.tx_ready) - dut.rx_valid.value = 1 + transmit_data = 0b101011110000111100001010 # random.randint(0, 2**bit_depth - 1) + dut.tx_data.value = transmit_data + dut.tx_valid.value = 1 # await start of lrclk frame - await ClockCycles(signal=dut.rx_lrclk, num_cycles=1, rising=False) - await ClockCycles( - signal=dut.bclk, num_cycles=1, rising=False - ) # I2S typically starts shifting out on the second falling edge of bclk - - for sample in range(0, 1): - # receive bits - transmit_data = random.randint(0, 2**bit_depth - 1) - dut.tx_data.value = transmit_data - for index in range(0, bit_depth): - await ClockCycles(signal=dut.bclk, num_cycles=1, rising=True) - assert dut.tx.value == (transmit_data >> (bit_depth - index)) & 0b1 - - # pad rest of lrclk frame, assert lrclk - assert dut.rx_lrclk.value == sample % 2 - await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) + await ClockCycles(signal=dut.mclk, num_cycles=10, rising=False) + # await ClockCycles(signal=dut.tx_lrclk, num_cycles=1, rising=False) + # await ClockCycles( + # signal=dut.bclk, num_cycles=2, rising=False + # ) # I2S typically starts shifting out on the second falling edge of bclk + + # for sample in range(0, 1): + # # receive bits + # for index in range(0, bit_depth): + # await ClockCycles(signal=dut.bclk, num_cycles=1, rising=True) + # assert dut.tx.value == (transmit_data >> (bit_depth - index - 1)) & 0b1 + + # # pad rest of lrclk frame, assert lrclk + # assert dut.tx_lrclk.value == sample % 2 + # await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) # @cocotb.test() diff --git a/hardware/waves/interfaces/i2s.ron b/hardware/waves/interfaces/i2s.ron index fa2d417..f74b935 100644 --- a/hardware/waves/interfaces/i2s.ron +++ b/hardware/waves/interfaces/i2s.ron @@ -145,31 +145,79 @@ selected: false, ), ( - item_ref: (41), + item_ref: (86), level: 1, unfolded: true, selected: false, ), ( - item_ref: (42), + item_ref: (73), level: 1, unfolded: true, selected: false, ), ( - item_ref: (43), + item_ref: (81), level: 1, unfolded: true, selected: false, ), ( - item_ref: (44), + item_ref: (87), level: 1, unfolded: true, selected: false, ), ( - item_ref: (45), + item_ref: (85), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (88), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (80), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (82), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (77), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (75), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (74), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (79), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (78), level: 1, unfolded: true, selected: false, @@ -177,261 +225,292 @@ ], ), displayed_items: { - (45): Variable(( + (31): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_valid", + name: "rx_bit_counter_rst_n", ), color: None, background_color: None, - display_name: "tx_valid", + display_name: "rx_bit_counter_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (38): Variable(( + (34): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_shift_en", + name: "rx_lrclk_counter", ), color: None, background_color: None, - display_name: "rx_shift_en", + display_name: "rx_lrclk_counter [7:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (34): Variable(( + (82): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lrclk_counter", + name: "tx_shift_en", ), color: None, background_color: None, - display_name: "rx_lrclk_counter [7:0]", + display_name: "tx_shift_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (42): Variable(( + (69): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_data", + name: "bclk", ), color: None, background_color: None, - display_name: "tx_data [23:0]", + display_name: "bclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (28): Variable(( + (74): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rst_n", + name: "tx_bit_counter", ), color: None, background_color: None, - display_name: "rst_n", + display_name: "tx_bit_counter [4:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (24): Variable(( + (80): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk_counter", + name: "tx_next_state", ), color: None, background_color: None, - display_name: "bclk_counter [1:0]", + display_name: "tx_next_state [7:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (69): Variable(( + (73): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk", + name: "tx", ), color: None, background_color: None, - display_name: "bclk", + display_name: "tx", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (22): Group(( + name: "transmit", + color: Some("Gray"), + background_color: Some("Gray"), + content: [], + is_open: false, + )), + (40): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_valid", + ), + color: None, + background_color: None, + display_name: "rx_valid", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (44): Variable(( + (39): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_ready", + name: "rx_state", ), color: None, background_color: None, - display_name: "tx_ready", + display_name: "rx_state [7:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (35): Variable(( + (38): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lrclk_rst_n", + name: "rx_shift_en", ), color: None, background_color: None, - display_name: "rx_lrclk_rst_n", + display_name: "rx_shift_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (32): Variable(( + (79): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_data", + name: "tx_lrclk_rst_n", ), color: None, background_color: None, - display_name: "rx_data [23:0]", + display_name: "tx_lrclk_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (43): Variable(( + (33): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_lrclk", + name: "rx_lrclk", ), color: None, background_color: None, - display_name: "tx_lrclk", + display_name: "rx_lrclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (31): Variable(( + (81): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_bit_counter_rst_n", + name: "tx_ready", ), color: None, background_color: None, - display_name: "rx_bit_counter_rst_n", + display_name: "tx_ready", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (26): Variable(( + (32): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "mclk", + name: "rx_data", ), color: None, background_color: None, - display_name: "mclk", + display_name: "rx_data [23:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (27): Variable(( + (88): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "mute", + name: "tx_state", ), color: None, background_color: None, - display_name: "mute", + display_name: "tx_state [7:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (36): Variable(( + (87): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_next_state", + name: "tx_valid", ), color: None, background_color: None, - display_name: "rx_next_state [7:0]", + display_name: "tx_valid", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), + (21): Group(( + name: "receive", + color: Some("Gray"), + background_color: Some("Gray"), + content: [], + is_open: false, + )), (30): Variable(( variable_ref: ( path: ( @@ -449,18 +528,18 @@ format: None, field_formats: [], )), - (29): Variable(( + (27): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx", + name: "mute", ), color: None, background_color: None, - display_name: "rx", + display_name: "mute", display_name_type: Unique, manual_name: None, format: None, @@ -483,107 +562,212 @@ format: None, field_formats: [], )), - (22): Group(( - name: "transmit", - color: Some("Gray"), - background_color: Some("Gray"), - content: [], - is_open: false, + (35): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_lrclk_rst_n", + ), + color: None, + background_color: None, + display_name: "rx_lrclk_rst_n", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], )), - (39): Variable(( + (37): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_state", + name: "rx_ready", ), color: None, background_color: None, - display_name: "rx_state [7:0]", + display_name: "rx_ready", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (40): Variable(( + (28): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_valid", + name: "rst_n", ), color: None, background_color: None, - display_name: "rx_valid", + display_name: "rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (37): Variable(( + (86): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_ready", + name: "tx_data", ), color: None, background_color: None, - display_name: "rx_ready", + display_name: "tx_data [23:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (21): Group(( - name: "receive", - color: Some("Gray"), - background_color: Some("Gray"), - content: [], - is_open: false, + (26): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "mclk", + ), + color: None, + background_color: None, + display_name: "mclk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], )), - (33): Variable(( + (24): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lrclk", + name: "bclk_counter", ), color: None, background_color: None, - display_name: "rx_lrclk", + display_name: "bclk_counter [1:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (41): Variable(( + (85): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx", + name: "bclk", ), color: None, background_color: None, - display_name: "tx", + display_name: "bclk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (36): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx_next_state", + ), + color: None, + background_color: None, + display_name: "rx_next_state [7:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (29): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "rx", + ), + color: None, + background_color: None, + display_name: "rx", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (75): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "tx_bit_counter_rst_n", + ), + color: None, + background_color: None, + display_name: "tx_bit_counter_rst_n", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (78): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "tx_lrclk_counter", + ), + color: None, + background_color: None, + display_name: "tx_lrclk_counter [7:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (77): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "tx_lrclk", + ), + color: None, + background_color: None, + display_name: "tx_lrclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), }, - display_item_ref_counter: 72, + display_item_ref_counter: 88, viewports: [ ( curr_left: (0.0), @@ -597,10 +781,10 @@ ), ], cursor: Some((1, [ - 337902, + 2299, ])), markers: {}, - focused_item: Some((20)), + focused_item: Some((32)), focused_transaction: (None, None), default_variable_name_type: Unique, scroll_offset: 0.0, @@ -609,7 +793,10 @@ )), drag_started: false, drag_source_idx: None, - drag_target_idx: None, + drag_target_idx: Some(( + before: (32), + level: 1, + )), previous_waves: None, count: None, blacklisted_translators: [], From 8b7271ef2dfbbebe7f2b831080d0df515fca5ad0 Mon Sep 17 00:00:00 2001 From: Drew Date: Thu, 8 May 2025 20:56:20 -0400 Subject: [PATCH 07/10] resolve bugs in i2s receive --- hardware/hdl/interfaces/i2s.sv | 52 ++--- hardware/makefile | 6 +- hardware/verif/py/interfaces/test_i2s.py | 129 ++++++----- hardware/waves/interfaces/i2s.ron | 259 +++++++++++------------ 4 files changed, 222 insertions(+), 224 deletions(-) diff --git a/hardware/hdl/interfaces/i2s.sv b/hardware/hdl/interfaces/i2s.sv index d5757c9..21a1afd 100644 --- a/hardware/hdl/interfaces/i2s.sv +++ b/hardware/hdl/interfaces/i2s.sv @@ -1,7 +1,12 @@ /* -I2S Codec interface +I2S Codec interface. + +Specifically written for the Analog Devices SSM2603. @param BIT_DEPTH: The bit depth of the codec. +@param MCLK_FREQ: The MCLK frequency used for the codec and interface. +@param BCLK_DIV: The number of MCLK cycles per BCLK cycle. +@param LRCLK_DIV: The number of BCLK cycles per LRCLK cycle. */ `begin_keywords "1800-2017" // Use SystemVerilog 2017 keywords @@ -10,10 +15,9 @@ I2S Codec interface module i2s #( parameter BIT_DEPTH = 24, - parameter WORD_LENGTH = 32, - parameter MCLK_FREQ = 125_000_000, + parameter MCLK_FREQ = 12_288_000, parameter BCLK_DIV = 4, - parameter LRCLK_DIV = 256 + parameter LRCLK_DIV = 64 ) ( input wire rst_n, @@ -48,11 +52,11 @@ module i2s */ // general localparam BUFFER_COUNTER_BITS = $clog2(BIT_DEPTH); + localparam WORD_LENGTH = LRCLK_DIV / 2; // clk dividers localparam BCLK_COUNTER_BITS = $clog2(BCLK_DIV); - localparam LRCLK_BCLK_DIV = LRCLK_DIV/BCLK_DIV; - localparam LRCLK_COUNTER_BITS = $clog2(LRCLK_BCLK_DIV); + localparam LRCLK_COUNTER_BITS = $clog2(LRCLK_DIV); /* @@ -84,8 +88,6 @@ logic [BCLK_COUNTER_BITS-1:0] bclk_counter; // bclk counter initial bclk_counter = '0; always_ff @( posedge mclk ) begin : _bclk_clk_counter - // if (!rst_n) - // bclk_counter <= '0; if (bclk_counter == '0) bclk_counter <= (BCLK_COUNTER_BITS)'(LRCLK_DIV - 1); else @@ -100,11 +102,11 @@ always_comb begin : _bclk_clk_divider bclk = 1; end -// TODO: synthesis difference between this and the block above +// // TODO: synthesis difference between this and the block above // always_ff @( posedge mclk ) begin : _bclk_clk_divider // if (!rst_n) // bclk <= 0; -// else if (clk_counter[BCLK_COUNTER_BITS-1:0] >= (BCLK_COUNTER_BITS)'(BCLK_DIV / 2)) +// else if (bclk_counter[BCLK_COUNTER_BITS-1:0] >= (BCLK_COUNTER_BITS)'(BCLK_DIV / 2)) // bclk <= 0; // else // bclk <= 1; @@ -123,7 +125,8 @@ end logic rx_shift_en, rx_bit_counter_rst_n; // rx current state logic - always_ff @( posedge mclk ) begin : _rx_current_state_logic + initial rx_state = RESET; + always_ff @( posedge bclk ) begin : _rx_current_state_logic if (!rst_n) rx_state <= RESET; else @@ -138,22 +141,21 @@ end IDLE: rx_next_state = LEFT_START; LEFT_START: - if (bclk_counter == '0) // bclk falling edge + if (rx_lrclk_counter == (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 2)) rx_next_state = LEFT; LEFT: if (rx_bit_counter == '0) rx_next_state = LEFT_IDLE; LEFT_IDLE: - if (rx_lrclk == 1) // unsure if this will work with 32 bit words + if (rx_lrclk_counter == (LRCLK_COUNTER_BITS)'((LRCLK_DIV/2) - 1)) rx_next_state = RIGHT_START; RIGHT_START: - if (bclk_counter == '0) // bclk falling edge - rx_next_state = RIGHT; + rx_next_state = RIGHT; RIGHT: - if (rx_bit_counter == '0) - rx_next_state = RIGHT_IDLE; + if (rx_bit_counter == '0) + rx_next_state = RIGHT_IDLE; RIGHT_IDLE: - if (rx_lrclk == 0) // unsure if this will work with 32 bit words + if (rx_lrclk_counter == 0) rx_next_state = LEFT_START; ERROR: rx_next_state = ERROR; @@ -226,7 +228,7 @@ end // rx bit counter always_ff @( posedge bclk ) begin : _rx_bit_counter if (!rx_bit_counter_rst_n) - rx_bit_counter <= BIT_DEPTH; + rx_bit_counter <= BIT_DEPTH - 1; else if (rx_bit_counter == '0) rx_bit_counter <= BIT_DEPTH - 1; else @@ -237,9 +239,9 @@ end logic [LRCLK_COUNTER_BITS-1:0] rx_lrclk_counter; // rx lrclk counter - always_ff @( posedge mclk ) begin : _rx_lrclk_clk_counter + always_ff @( posedge bclk ) begin : _rx_lrclk_clk_counter if (!rx_lrclk_rst_n) - rx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 1); + rx_lrclk_counter <= 0; else if (rx_lrclk_counter == '0) rx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 1); else @@ -250,7 +252,7 @@ end always_comb begin : _rx_lrclk_clk_div if (!rx_lrclk_rst_n) rx_lrclk = 1; - else if (rx_lrclk_counter[LRCLK_COUNTER_BITS-1:0] >= (LRCLK_COUNTER_BITS)'(LRCLK_BCLK_DIV / 2)) + else if (rx_lrclk_counter[LRCLK_COUNTER_BITS-1:0] >= (LRCLK_COUNTER_BITS)'(LRCLK_DIV / 2)) rx_lrclk = 0; else rx_lrclk = 1; @@ -386,9 +388,9 @@ end // tx lrclk counter always_ff @( posedge bclk ) begin : _tx_lrclk_counter if (!tx_lrclk_rst_n) - tx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_BCLK_DIV - 1); + tx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 1); else if (tx_lrclk_counter == '0) - tx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_BCLK_DIV - 1); + tx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 1); else // tx_lrclk_counter <= '0; tx_lrclk_counter <= tx_lrclk_counter - 1; @@ -398,7 +400,7 @@ end always_comb begin : _tx_lrclk_clk_div if (!tx_lrclk_rst_n) tx_lrclk = 1; - else if (tx_lrclk_counter >= (LRCLK_COUNTER_BITS)'(LRCLK_BCLK_DIV / 2)) + else if (tx_lrclk_counter >= (LRCLK_COUNTER_BITS)'(LRCLK_DIV / 2)) tx_lrclk = 0; else tx_lrclk = 1; diff --git a/hardware/makefile b/hardware/makefile index 2b5d3de..ffe3c68 100644 --- a/hardware/makefile +++ b/hardware/makefile @@ -37,12 +37,12 @@ include hdl/interfaces.mk # Test a module %.test: - ${PYTHON} -m pytest -v -o log_cli=True hardware/verif/py/$* + ${PYTHON} -m pytest -v -o log_cli=True verif/py/interfaces/test_$*.py # Test and display waveforms for a module #TODO: Add config directory for waveforms %.waves: - ${PYTHON} -m pytest -v -o log_cli=True hardware/verif/py/$* - ${SURFER} waves/$*.fst + ${PYTHON} -m pytest -v -o log_cli=True verif/py/interfaces/test_$*.py + ${SURFER} ../sim_build/$*/$*.fst -s waves/interfaces/$*.ron & # Generate a bitstream %.bit: ../scripts/synthesis_place_route.tcl $${%_TOP} $${_XDC} $${%_SRCS} $${%_DEPS} diff --git a/hardware/verif/py/interfaces/test_i2s.py b/hardware/verif/py/interfaces/test_i2s.py index 2ee21d4..e6d240d 100644 --- a/hardware/verif/py/interfaces/test_i2s.py +++ b/hardware/verif/py/interfaces/test_i2s.py @@ -12,11 +12,55 @@ from hardware.util.verif import repeat, parameterize +@cocotb.test() +@repeat(num_repeats=1) +async def i2s_random_receive(dut, bit_depth: int = None): + """ + Test random receives with a I2S main. + """ + # setup module parameters and variables + bit_depth = 24 + + # setup clock + clock_period_ns = int(1e9 / 12e6) + clock = Clock(signal=dut.mclk, period=clock_period_ns, units="ns") + await cocotb.start(clock.start()) + + # setup inputs + dut.rx.value = 0 # I2S idle high + + # reset + dut.rst_n.value = 0 + await ClockCycles(signal=dut.mclk, num_cycles=2, rising=True) + dut.rst_n.value = 1 + + # await start of lrclk frame + await ClockCycles(signal=dut.rx_lrclk, num_cycles=1, rising=False) + # I2S typically starts shifting out on the second falling edge of bclk + # after falling edge of lrclk + await ClockCycles(signal=dut.bclk, num_cycles=3, rising=False) + + for sample in range(0, 4): + # receive bits + receive_data = random.randint(0, 2**bit_depth - 1) + for index in range(0, bit_depth): + dut.rx.value = (receive_data >> (bit_depth - index - 1)) & 0b1 + await ClockCycles(signal=dut.bclk, num_cycles=1, rising=False) + + # assert receive data, receive valid, and lrclk + assert dut.rx_data.value == receive_data + assert dut.rx_valid.value == 1 + + # pad rest of lrclk frame, assert lrclk + assert dut.rx_lrclk.value == sample % 2 + await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) + + # @cocotb.test() -# @repeat(num_repeats=3) -# async def i2s_random_receive(dut, bit_depth: int = None): +# @repeat(num_repeats=1) +# async def i2s_random_transmit(dut, bit_depth: int = None): # """ -# Test random receives with a I2S main. +# Test random transmits with a I2S main. # """ # # setup module parameters and variables # bit_depth = 24 @@ -26,78 +70,33 @@ # clock = Clock(signal=dut.mclk, period=clock_period_ns, units="ns") # await cocotb.start(clock.start()) -# # setup inputs -# dut.rx.value = 0 # I2S idle high - # # reset # dut.rst_n.value = 0 # await ClockCycles(signal=dut.mclk, num_cycles=2, rising=True) # dut.rst_n.value = 1 +# # await for transmit_ready, continue if already high +# if not dut.tx_ready.value: +# await RisingEdge(signal=dut.tx_ready) +# transmit_data = 0b101011110000111100001010 # random.randint(0, 2**bit_depth - 1) +# dut.tx_data.value = transmit_data +# dut.tx_valid.value = 1 + # # await start of lrclk frame -# await ClockCycles(signal=dut.rx_lrclk, num_cycles=1, rising=False) -# await ClockCycles( -# signal=dut.bclk, num_cycles=1, rising=False -# ) # I2S typically starts shifting out on the second falling edge of bclk +# await ClockCycles(signal=dut.tx_lrclk, num_cycles=1, rising=False) +# # I2S typically starts shifting out on the second falling edge of bclk +# # after falling edge of lrclk +# await ClockCycles(signal=dut.bclk, num_cycles=3, rising=False) -# for sample in range(0, 4): +# for sample in range(0, 1): # # receive bits -# receive_data = random.randint(0, 2**bit_depth - 1) # for index in range(0, bit_depth): -# dut.rx.value = (receive_data >> (bit_depth - index - 1)) & 0b1 -# await ClockCycles(signal=dut.bclk, num_cycles=1, rising=False) - -# # pad rest of lrclk frame, assert lrclk -# assert dut.rx_lrclk.value == sample % 2 -# await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) - -# # assert receive data, receive valid, and lrclk -# assert dut.rx_data.value == receive_data -# assert dut.rx_valid.value == 1 - - -@cocotb.test() -@repeat(num_repeats=1) -async def i2s_random_transmit(dut, bit_depth: int = None): - """ - Test random transmits with a I2S main. - """ - # setup module parameters and variables - bit_depth = 24 +# await ClockCycles(signal=dut.bclk, num_cycles=1, rising=True) +# # assert dut.tx.value == (transmit_data >> (bit_depth - index - 1)) & 0b1 - # setup clock - clock_period_ns = int(1e9 / 12e6) - clock = Clock(signal=dut.mclk, period=clock_period_ns, units="ns") - await cocotb.start(clock.start()) - - # reset - dut.rst_n.value = 0 - await ClockCycles(signal=dut.mclk, num_cycles=2, rising=True) - dut.rst_n.value = 1 - - # await for transmit_ready, continue if already high - if not dut.tx_ready.value: - await RisingEdge(signal=dut.tx_ready) - transmit_data = 0b101011110000111100001010 # random.randint(0, 2**bit_depth - 1) - dut.tx_data.value = transmit_data - dut.tx_valid.value = 1 - - # await start of lrclk frame - await ClockCycles(signal=dut.mclk, num_cycles=10, rising=False) - # await ClockCycles(signal=dut.tx_lrclk, num_cycles=1, rising=False) - # await ClockCycles( - # signal=dut.bclk, num_cycles=2, rising=False - # ) # I2S typically starts shifting out on the second falling edge of bclk - - # for sample in range(0, 1): - # # receive bits - # for index in range(0, bit_depth): - # await ClockCycles(signal=dut.bclk, num_cycles=1, rising=True) - # assert dut.tx.value == (transmit_data >> (bit_depth - index - 1)) & 0b1 - - # # pad rest of lrclk frame, assert lrclk - # assert dut.tx_lrclk.value == sample % 2 - # await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) +# # # pad rest of lrclk frame, assert lrclk +# # assert dut.tx_lrclk.value == sample % 2 +# # await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) # @cocotb.test() diff --git a/hardware/waves/interfaces/i2s.ron b/hardware/waves/interfaces/i2s.ron index f74b935..e8df536 100644 --- a/hardware/waves/interfaces/i2s.ron +++ b/hardware/waves/interfaces/i2s.ron @@ -85,55 +85,55 @@ selected: false, ), ( - item_ref: (69), + item_ref: (33), level: 1, unfolded: true, selected: false, ), ( - item_ref: (39), + item_ref: (69), level: 1, unfolded: true, selected: false, ), ( - item_ref: (36), + item_ref: (34), level: 1, unfolded: true, selected: false, ), ( - item_ref: (38), + item_ref: (39), level: 1, unfolded: true, selected: false, ), ( - item_ref: (33), + item_ref: (36), level: 1, unfolded: true, selected: false, ), ( - item_ref: (31), + item_ref: (38), level: 1, unfolded: true, selected: false, ), ( - item_ref: (30), + item_ref: (31), level: 1, unfolded: true, selected: false, ), ( - item_ref: (35), + item_ref: (30), level: 1, unfolded: true, selected: false, ), ( - item_ref: (34), + item_ref: (35), level: 1, unfolded: true, selected: false, @@ -225,542 +225,542 @@ ], ), displayed_items: { - (31): Variable(( + (75): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_bit_counter_rst_n", + name: "tx_bit_counter_rst_n", ), color: None, background_color: None, - display_name: "rx_bit_counter_rst_n", + display_name: "tx_bit_counter_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (34): Variable(( + (87): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lrclk_counter", + name: "tx_valid", ), color: None, background_color: None, - display_name: "rx_lrclk_counter [7:0]", + display_name: "tx_valid", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (82): Variable(( + (31): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_shift_en", + name: "rx_bit_counter_rst_n", ), color: None, background_color: None, - display_name: "tx_shift_en", + display_name: "rx_bit_counter_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (69): Variable(( + (22): Group(( + name: "transmit", + color: Some("Gray"), + background_color: Some("Gray"), + content: [], + is_open: false, + )), + (30): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk", + name: "rx_bit_counter", ), color: None, background_color: None, - display_name: "bclk", + display_name: "rx_bit_counter [4:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), - (74): Variable(( + (36): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_bit_counter", + name: "rx_next_state", ), color: None, background_color: None, - display_name: "tx_bit_counter [4:0]", + display_name: "rx_next_state [7:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Binary"), field_formats: [], )), - (80): Variable(( + (81): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_next_state", + name: "tx_ready", ), color: None, background_color: None, - display_name: "tx_next_state [7:0]", + display_name: "tx_ready", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (73): Variable(( + (37): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx", + name: "rx_ready", ), color: None, background_color: None, - display_name: "tx", + display_name: "rx_ready", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (22): Group(( - name: "transmit", - color: Some("Gray"), - background_color: Some("Gray"), - content: [], - is_open: false, - )), - (40): Variable(( + (32): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_valid", + name: "rx_data", ), color: None, background_color: None, - display_name: "rx_valid", + display_name: "rx_data [23:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Binary"), field_formats: [], )), - (39): Variable(( + (34): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_state", + name: "rx_lrclk_counter", ), color: None, background_color: None, - display_name: "rx_state [7:0]", + display_name: "rx_lrclk_counter [7:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), - (38): Variable(( + (77): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_shift_en", + name: "tx_lrclk", ), color: None, background_color: None, - display_name: "rx_shift_en", + display_name: "tx_lrclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (79): Variable(( + (29): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_lrclk_rst_n", + name: "rx", ), color: None, background_color: None, - display_name: "tx_lrclk_rst_n", + display_name: "rx", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (33): Variable(( + (26): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lrclk", + name: "mclk", ), color: None, background_color: None, - display_name: "rx_lrclk", + display_name: "mclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (81): Variable(( + (78): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_ready", + name: "tx_lrclk_counter", ), color: None, background_color: None, - display_name: "tx_ready", + display_name: "tx_lrclk_counter [7:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), - (32): Variable(( + (39): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_data", + name: "rx_state", ), color: None, background_color: None, - display_name: "rx_data [23:0]", + display_name: "rx_state [7:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Binary"), field_formats: [], )), - (88): Variable(( + (40): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_state", + name: "rx_valid", ), color: None, background_color: None, - display_name: "tx_state [7:0]", + display_name: "rx_valid", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (87): Variable(( + (35): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_valid", + name: "rx_lrclk_rst_n", ), color: None, background_color: None, - display_name: "tx_valid", + display_name: "rx_lrclk_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (21): Group(( - name: "receive", - color: Some("Gray"), - background_color: Some("Gray"), - content: [], - is_open: false, - )), - (30): Variable(( + (28): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_bit_counter", + name: "rst_n", ), color: None, background_color: None, - display_name: "rx_bit_counter [4:0]", + display_name: "rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (27): Variable(( + (88): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "mute", + name: "tx_state", ), color: None, background_color: None, - display_name: "mute", + display_name: "tx_state [7:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (23): Variable(( + (80): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk", + name: "tx_next_state", ), color: None, background_color: None, - display_name: "bclk", + display_name: "tx_next_state [7:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (35): Variable(( + (24): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lrclk_rst_n", + name: "bclk_counter", ), color: None, background_color: None, - display_name: "rx_lrclk_rst_n", + display_name: "bclk_counter [1:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (37): Variable(( + (23): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_ready", + name: "bclk", ), color: None, background_color: None, - display_name: "rx_ready", + display_name: "bclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (28): Variable(( + (74): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rst_n", + name: "tx_bit_counter", ), color: None, background_color: None, - display_name: "rst_n", + display_name: "tx_bit_counter [4:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (86): Variable(( + (38): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_data", + name: "rx_shift_en", ), color: None, background_color: None, - display_name: "tx_data [23:0]", + display_name: "rx_shift_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (26): Variable(( + (79): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "mclk", + name: "tx_lrclk_rst_n", ), color: None, background_color: None, - display_name: "mclk", + display_name: "tx_lrclk_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (24): Variable(( + (33): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk_counter", + name: "rx_lrclk", ), color: None, background_color: None, - display_name: "bclk_counter [1:0]", + display_name: "rx_lrclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (85): Variable(( + (27): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk", + name: "mute", ), color: None, background_color: None, - display_name: "bclk", + display_name: "mute", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (36): Variable(( + (82): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_next_state", + name: "tx_shift_en", ), color: None, background_color: None, - display_name: "rx_next_state [7:0]", + display_name: "tx_shift_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (29): Variable(( + (85): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx", + name: "bclk", ), color: None, background_color: None, - display_name: "rx", + display_name: "bclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (75): Variable(( + (86): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_bit_counter_rst_n", + name: "tx_data", ), color: None, background_color: None, - display_name: "tx_bit_counter_rst_n", + display_name: "tx_data [23:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (78): Variable(( + (21): Group(( + name: "receive", + color: Some("Gray"), + background_color: Some("Gray"), + content: [], + is_open: false, + )), + (73): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_lrclk_counter", + name: "tx", ), color: None, background_color: None, - display_name: "tx_lrclk_counter [7:0]", + display_name: "tx", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (77): Variable(( + (69): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_lrclk", + name: "bclk", ), color: None, background_color: None, - display_name: "tx_lrclk", + display_name: "bclk", display_name_type: Unique, manual_name: None, format: None, @@ -770,8 +770,8 @@ display_item_ref_counter: 88, viewports: [ ( - curr_left: (0.0), - curr_right: (1.4), + curr_left: (-0.2239999909140302), + curr_right: (1.1759999781149202), target_left: (-0.2), target_right: (1.2), move_start_left: (-0.2), @@ -781,10 +781,10 @@ ), ], cursor: Some((1, [ - 2299, + 107900, ])), markers: {}, - focused_item: Some((32)), + focused_item: Some((14)), focused_transaction: (None, None), default_variable_name_type: Unique, scroll_offset: 0.0, @@ -793,10 +793,7 @@ )), drag_started: false, drag_source_idx: None, - drag_target_idx: Some(( - before: (32), - level: 1, - )), + drag_target_idx: None, previous_waves: None, count: None, blacklisted_translators: [], @@ -815,6 +812,6 @@ variable_name_filter_type: Fuzzy, variable_name_filter_case_insensitive: true, rename_target: None, - sidepanel_width: Some(217.5625), + sidepanel_width: Some(100.0), ui_zoom_factor: None, ) \ No newline at end of file From 06210f549c6ceb3e05bf10d7bc12fed0e0f11a98 Mon Sep 17 00:00:00 2001 From: Drew Date: Thu, 8 May 2025 22:37:00 -0400 Subject: [PATCH 08/10] complete i2s transmit, tested --- hardware/hdl/interfaces/i2s.sv | 55 +++-- hardware/verif/py/interfaces/test_i2s.py | 85 +++---- hardware/waves/interfaces/i2s.ron | 268 +++++++++++++---------- 3 files changed, 221 insertions(+), 187 deletions(-) diff --git a/hardware/hdl/interfaces/i2s.sv b/hardware/hdl/interfaces/i2s.sv index 21a1afd..9d72f4f 100644 --- a/hardware/hdl/interfaces/i2s.sv +++ b/hardware/hdl/interfaces/i2s.sv @@ -112,6 +112,14 @@ end // bclk <= 1; // end +// inverted bclk output +logic bclk_inv; +always_comb begin : _bclk_inv_clk_divider + if (bclk_counter[BCLK_COUNTER_BITS-1:0] >= (BCLK_COUNTER_BITS)'(BCLK_DIV / 2)) + bclk_inv = 1; + else + bclk_inv = 0; +end /* * ============================================================================= @@ -215,7 +223,7 @@ end endcase end - // receive shift register + // rx shift register always_ff @( posedge bclk ) begin : _rx_shift_register if (!rst_n) rx_data <= '0; @@ -258,6 +266,7 @@ end rx_lrclk = 1; end + /* * ============================================================================= * transmit @@ -270,7 +279,8 @@ end logic tx_shift_en, tx_bit_counter_rst_n; // tx current state logic - always_ff @( posedge mclk ) begin : _tx_current_state_logic + initial tx_state = RESET; + always_ff @( posedge bclk_inv ) begin : _tx_current_state_logic if (!rst_n) tx_state <= RESET; else @@ -283,25 +293,24 @@ end RESET: tx_next_state = IDLE; IDLE: - if (tx_valid) + if (tx_valid) // TODO: may prevent state transition tx_next_state = LEFT_START; LEFT_START: - if (bclk_counter == '0) // bclk falling edge + if (tx_lrclk_counter == (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 2)) tx_next_state = LEFT; LEFT: if (tx_bit_counter == '0) tx_next_state = LEFT_IDLE; LEFT_IDLE: - if (tx_lrclk == 1) // unsure if this will work with 32 bit words + if ((tx_lrclk_counter == (LRCLK_COUNTER_BITS)'((LRCLK_DIV/2) - 1)) && tx_valid) // TODO: may prevent state transition tx_next_state = RIGHT_START; RIGHT_START: - if (bclk_counter == '0) // bclk falling edge - tx_next_state = RIGHT; + tx_next_state = RIGHT; RIGHT: - if (tx_bit_counter == '0) - tx_next_state = RIGHT_IDLE; + if (tx_bit_counter == '0) + tx_next_state = RIGHT_IDLE; RIGHT_IDLE: - if (tx_lrclk == 0) // unsure if this will work with 32 bit words + if ((tx_lrclk_counter == 0) && tx_ready) // TODO: may prevent state transition tx_next_state = LEFT_START; ERROR: tx_next_state = ERROR; @@ -326,7 +335,7 @@ end LEFT_START: begin {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; {tx_lrclk_rst_n} = 1'b1; - {tx_ready} = 1'b0; + {tx_ready} = 1'b0; end LEFT: begin {tx_shift_en, tx_bit_counter_rst_n} = 2'b11; @@ -336,7 +345,7 @@ end LEFT_IDLE: begin {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; {tx_lrclk_rst_n} = 1'b1; - {tx_ready} = 1'b0; + {tx_ready} = 1'b1; end RIGHT_START: begin {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; @@ -351,7 +360,7 @@ end RIGHT_IDLE: begin {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; {tx_lrclk_rst_n} = 1'b1; - {tx_ready} = 1'b0; + {tx_ready} = 1'b1; end default: begin {tx_shift_en, tx_bit_counter_rst_n} = 2'b00; @@ -361,20 +370,20 @@ end endcase end - // receive shift register - always_ff @( posedge mclk ) begin : _tx_shift_register + // tx shift register + always_ff @( posedge bclk_inv ) begin : _tx_shift_register if (!rst_n) - tx <= 0; + tx <= '0; else if (tx_shift_en) - tx <= tx_data[tx_bit_counter - 1]; // msb first + tx <= tx_data[tx_bit_counter]; // msb first else tx <= tx; end // tx bit counter - always_ff @( posedge bclk ) begin : _tx_bit_counter + always_ff @( posedge bclk_inv ) begin : _tx_bit_counter if (!tx_bit_counter_rst_n) - tx_bit_counter <= BIT_DEPTH; + tx_bit_counter <= BIT_DEPTH - 1; else if (tx_bit_counter == '0) tx_bit_counter <= BIT_DEPTH - 1; else @@ -383,16 +392,14 @@ end logic tx_lrclk_rst_n; logic [LRCLK_COUNTER_BITS-1:0] tx_lrclk_counter; - initial tx_lrclk_counter = '0; // tx lrclk counter - always_ff @( posedge bclk ) begin : _tx_lrclk_counter + always_ff @( posedge bclk ) begin : _tx_lrclk_clk_counter if (!tx_lrclk_rst_n) - tx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 1); + tx_lrclk_counter <= 0; else if (tx_lrclk_counter == '0) tx_lrclk_counter <= (LRCLK_COUNTER_BITS)'(LRCLK_DIV - 1); else - // tx_lrclk_counter <= '0; tx_lrclk_counter <= tx_lrclk_counter - 1; end @@ -400,7 +407,7 @@ end always_comb begin : _tx_lrclk_clk_div if (!tx_lrclk_rst_n) tx_lrclk = 1; - else if (tx_lrclk_counter >= (LRCLK_COUNTER_BITS)'(LRCLK_DIV / 2)) + else if (tx_lrclk_counter[LRCLK_COUNTER_BITS-1:0] >= (LRCLK_COUNTER_BITS)'(LRCLK_DIV / 2)) tx_lrclk = 0; else tx_lrclk = 1; diff --git a/hardware/verif/py/interfaces/test_i2s.py b/hardware/verif/py/interfaces/test_i2s.py index e6d240d..034b714 100644 --- a/hardware/verif/py/interfaces/test_i2s.py +++ b/hardware/verif/py/interfaces/test_i2s.py @@ -13,7 +13,7 @@ @cocotb.test() -@repeat(num_repeats=1) +@repeat(num_repeats=3) async def i2s_random_receive(dut, bit_depth: int = None): """ Test random receives with a I2S main. @@ -56,47 +56,48 @@ async def i2s_random_receive(dut, bit_depth: int = None): await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) -# @cocotb.test() -# @repeat(num_repeats=1) -# async def i2s_random_transmit(dut, bit_depth: int = None): -# """ -# Test random transmits with a I2S main. -# """ -# # setup module parameters and variables -# bit_depth = 24 - -# # setup clock -# clock_period_ns = int(1e9 / 12e6) -# clock = Clock(signal=dut.mclk, period=clock_period_ns, units="ns") -# await cocotb.start(clock.start()) - -# # reset -# dut.rst_n.value = 0 -# await ClockCycles(signal=dut.mclk, num_cycles=2, rising=True) -# dut.rst_n.value = 1 - -# # await for transmit_ready, continue if already high -# if not dut.tx_ready.value: -# await RisingEdge(signal=dut.tx_ready) -# transmit_data = 0b101011110000111100001010 # random.randint(0, 2**bit_depth - 1) -# dut.tx_data.value = transmit_data -# dut.tx_valid.value = 1 - -# # await start of lrclk frame -# await ClockCycles(signal=dut.tx_lrclk, num_cycles=1, rising=False) -# # I2S typically starts shifting out on the second falling edge of bclk -# # after falling edge of lrclk -# await ClockCycles(signal=dut.bclk, num_cycles=3, rising=False) - -# for sample in range(0, 1): -# # receive bits -# for index in range(0, bit_depth): -# await ClockCycles(signal=dut.bclk, num_cycles=1, rising=True) -# # assert dut.tx.value == (transmit_data >> (bit_depth - index - 1)) & 0b1 - -# # # pad rest of lrclk frame, assert lrclk -# # assert dut.tx_lrclk.value == sample % 2 -# # await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) +@cocotb.test() +@repeat(num_repeats=3) +async def i2s_random_transmit(dut, bit_depth: int = None): + """ + Test random transmits with a I2S main. + """ + # setup module parameters and variables + bit_depth = 24 + + # setup clock + clock_period_ns = int(1e9 / 12e6) + clock = Clock(signal=dut.mclk, period=clock_period_ns, units="ns") + await cocotb.start(clock.start()) + + # reset + dut.rst_n.value = 0 + dut.tx_valid.value = 0 + await ClockCycles(signal=dut.bclk, num_cycles=2, rising=True) + dut.rst_n.value = 1 + + # await for transmit_ready, continue if already high + if not dut.tx_ready.value: + await RisingEdge(signal=dut.tx_ready) + transmit_data = 0b101011110000111100001010 # random.randint(0, 2**bit_depth - 1) + dut.tx_data.value = transmit_data + dut.tx_valid.value = 1 + + # await start of lrclk frame + await ClockCycles(signal=dut.tx_lrclk, num_cycles=1, rising=False) + # I2S typically starts shifting out on the second falling edge of bclk + # after falling edge of lrclk + await ClockCycles(signal=dut.bclk, num_cycles=2, rising=True) + + for sample in range(0, 4): + # transmit bits + for index in range(0, bit_depth): + await ClockCycles(signal=dut.bclk, num_cycles=1, rising=True) + assert dut.tx.value == (transmit_data >> (bit_depth - index - 1)) & 0b1 + + # pad rest of lrclk frame, assert lrclk + assert dut.tx_lrclk.value == sample % 2 + await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=True) # @cocotb.test() diff --git a/hardware/waves/interfaces/i2s.ron b/hardware/waves/interfaces/i2s.ron index e8df536..aa90b14 100644 --- a/hardware/waves/interfaces/i2s.ron +++ b/hardware/waves/interfaces/i2s.ron @@ -169,31 +169,37 @@ selected: false, ), ( - item_ref: (85), + item_ref: (88), level: 1, unfolded: true, selected: false, ), ( - item_ref: (88), + item_ref: (80), level: 1, unfolded: true, selected: false, ), ( - item_ref: (80), + item_ref: (82), level: 1, unfolded: true, selected: false, ), ( - item_ref: (82), + item_ref: (77), level: 1, unfolded: true, selected: false, ), ( - item_ref: (77), + item_ref: (85), + level: 1, + unfolded: true, + selected: false, + ), + ( + item_ref: (89), level: 1, unfolded: true, selected: false, @@ -225,6 +231,23 @@ ], ), displayed_items: { + (89): Variable(( + variable_ref: ( + path: ( + strs: [ + "i2s", + ], + ), + name: "bclk_inv", + ), + color: None, + background_color: None, + display_name: "bclk_inv", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), (75): Variable(( variable_ref: ( path: ( @@ -242,456 +265,456 @@ format: None, field_formats: [], )), - (87): Variable(( + (78): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_valid", + name: "tx_lrclk_counter", ), color: None, background_color: None, - display_name: "tx_valid", + display_name: "tx_lrclk_counter [5:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), - (31): Variable(( + (88): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_bit_counter_rst_n", + name: "tx_state", ), color: None, background_color: None, - display_name: "rx_bit_counter_rst_n", + display_name: "tx_state [7:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Binary"), field_formats: [], )), - (22): Group(( - name: "transmit", - color: Some("Gray"), - background_color: Some("Gray"), - content: [], - is_open: false, - )), - (30): Variable(( + (38): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_bit_counter", + name: "rx_shift_en", ), color: None, background_color: None, - display_name: "rx_bit_counter [4:0]", + display_name: "rx_shift_en", display_name_type: Unique, manual_name: None, - format: Some("Unsigned"), + format: None, field_formats: [], )), - (36): Variable(( + (79): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_next_state", + name: "tx_lrclk_rst_n", ), color: None, background_color: None, - display_name: "rx_next_state [7:0]", + display_name: "tx_lrclk_rst_n", display_name_type: Unique, manual_name: None, - format: Some("Binary"), + format: None, field_formats: [], )), - (81): Variable(( + (85): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_ready", + name: "bclk", ), color: None, background_color: None, - display_name: "tx_ready", + display_name: "bclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (37): Variable(( + (35): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_ready", + name: "rx_lrclk_rst_n", ), color: None, background_color: None, - display_name: "rx_ready", + display_name: "rx_lrclk_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (32): Variable(( + (26): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_data", + name: "mclk", ), color: None, background_color: None, - display_name: "rx_data [23:0]", + display_name: "mclk", display_name_type: Unique, manual_name: None, - format: Some("Binary"), + format: None, field_formats: [], )), - (34): Variable(( + (86): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lrclk_counter", + name: "tx_data", ), color: None, background_color: None, - display_name: "rx_lrclk_counter [7:0]", + display_name: "tx_data [23:0]", display_name_type: Unique, manual_name: None, - format: Some("Unsigned"), + format: None, field_formats: [], )), - (77): Variable(( + (27): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_lrclk", + name: "mute", ), color: None, background_color: None, - display_name: "tx_lrclk", + display_name: "mute", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (29): Variable(( + (77): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx", + name: "tx_lrclk", ), color: None, background_color: None, - display_name: "rx", + display_name: "tx_lrclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (26): Variable(( + (31): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "mclk", + name: "rx_bit_counter_rst_n", ), color: None, background_color: None, - display_name: "mclk", + display_name: "rx_bit_counter_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (78): Variable(( + (81): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_lrclk_counter", + name: "tx_ready", ), color: None, background_color: None, - display_name: "tx_lrclk_counter [7:0]", + display_name: "tx_ready", display_name_type: Unique, manual_name: None, - format: Some("Unsigned"), + format: None, field_formats: [], )), - (39): Variable(( + (36): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_state", + name: "rx_next_state", ), color: None, background_color: None, - display_name: "rx_state [7:0]", + display_name: "rx_next_state [7:0]", display_name_type: Unique, manual_name: None, format: Some("Binary"), field_formats: [], )), - (40): Variable(( + (33): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_valid", + name: "rx_lrclk", ), color: None, background_color: None, - display_name: "rx_valid", + display_name: "rx_lrclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (35): Variable(( + (39): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lrclk_rst_n", + name: "rx_state", ), color: None, background_color: None, - display_name: "rx_lrclk_rst_n", + display_name: "rx_state [7:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Binary"), field_formats: [], )), - (28): Variable(( + (30): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rst_n", + name: "rx_bit_counter", ), color: None, background_color: None, - display_name: "rst_n", + display_name: "rx_bit_counter [4:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), - (88): Variable(( + (28): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_state", + name: "rst_n", ), color: None, background_color: None, - display_name: "tx_state [7:0]", + display_name: "rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (80): Variable(( + (32): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_next_state", + name: "rx_data", ), color: None, background_color: None, - display_name: "tx_next_state [7:0]", + display_name: "rx_data [23:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Binary"), field_formats: [], )), - (24): Variable(( + (40): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk_counter", + name: "rx_valid", ), color: None, background_color: None, - display_name: "bclk_counter [1:0]", + display_name: "rx_valid", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (23): Variable(( + (34): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk", + name: "rx_lrclk_counter", ), color: None, background_color: None, - display_name: "bclk", + display_name: "rx_lrclk_counter [5:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), - (74): Variable(( + (24): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_bit_counter", + name: "bclk_counter", ), color: None, background_color: None, - display_name: "tx_bit_counter [4:0]", + display_name: "bclk_counter [1:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (38): Variable(( + (74): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_shift_en", + name: "tx_bit_counter", ), color: None, background_color: None, - display_name: "rx_shift_en", + display_name: "tx_bit_counter [4:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), - (79): Variable(( + (87): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_lrclk_rst_n", + name: "tx_valid", ), color: None, background_color: None, - display_name: "tx_lrclk_rst_n", + display_name: "tx_valid", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (33): Variable(( + (29): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lrclk", + name: "rx", ), color: None, background_color: None, - display_name: "rx_lrclk", + display_name: "rx", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (27): Variable(( + (73): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "mute", + name: "tx", ), color: None, background_color: None, - display_name: "mute", + display_name: "tx", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (82): Variable(( + (80): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_shift_en", + name: "tx_next_state", ), color: None, background_color: None, - display_name: "tx_shift_en", + display_name: "tx_next_state [7:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Binary"), field_formats: [], )), - (85): Variable(( + (21): Group(( + name: "receive", + color: Some("Gray"), + background_color: Some("Gray"), + content: [], + is_open: false, + )), + (23): Variable(( variable_ref: ( path: ( strs: [ @@ -708,70 +731,70 @@ format: None, field_formats: [], )), - (86): Variable(( + (37): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_data", + name: "rx_ready", ), color: None, background_color: None, - display_name: "tx_data [23:0]", + display_name: "rx_ready", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (21): Group(( - name: "receive", + (22): Group(( + name: "transmit", color: Some("Gray"), background_color: Some("Gray"), content: [], is_open: false, )), - (73): Variable(( + (69): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx", + name: "bclk", ), color: None, background_color: None, - display_name: "tx", + display_name: "bclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (69): Variable(( + (82): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk", + name: "tx_shift_en", ), color: None, background_color: None, - display_name: "bclk", + display_name: "tx_shift_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), }, - display_item_ref_counter: 88, + display_item_ref_counter: 89, viewports: [ ( - curr_left: (-0.2239999909140302), - curr_right: (1.1759999781149202), + curr_left: (-0.19431991150975228), + curr_right: (1.2056800884902474), target_left: (-0.2), target_right: (1.2), move_start_left: (-0.2), @@ -781,10 +804,10 @@ ), ], cursor: Some((1, [ - 107900, + 111220, ])), markers: {}, - focused_item: Some((14)), + focused_item: Some((28)), focused_transaction: (None, None), default_variable_name_type: Unique, scroll_offset: 0.0, @@ -793,7 +816,10 @@ )), drag_started: false, drag_source_idx: None, - drag_target_idx: None, + drag_target_idx: Some(( + before: (28), + level: 1, + )), previous_waves: None, count: None, blacklisted_translators: [], From 5f6ada24ae1c3f2e5b065cb312c4f8c53971aaec Mon Sep 17 00:00:00 2001 From: Drew Date: Thu, 8 May 2025 23:05:05 -0400 Subject: [PATCH 09/10] complete i2s full duplex test --- hardware/verif/py/interfaces/test_i2s.py | 75 ++++++- hardware/waves/interfaces/i2s.ron | 250 +++++++++++------------ 2 files changed, 190 insertions(+), 135 deletions(-) diff --git a/hardware/verif/py/interfaces/test_i2s.py b/hardware/verif/py/interfaces/test_i2s.py index 034b714..209f0f5 100644 --- a/hardware/verif/py/interfaces/test_i2s.py +++ b/hardware/verif/py/interfaces/test_i2s.py @@ -16,7 +16,7 @@ @repeat(num_repeats=3) async def i2s_random_receive(dut, bit_depth: int = None): """ - Test random receives with a I2S main. + Test random receives with a I2S peripheral. """ # setup module parameters and variables bit_depth = 24 @@ -27,11 +27,11 @@ async def i2s_random_receive(dut, bit_depth: int = None): await cocotb.start(clock.start()) # setup inputs - dut.rx.value = 0 # I2S idle high + dut.rx.value = 0 # I2S idle low # reset dut.rst_n.value = 0 - await ClockCycles(signal=dut.mclk, num_cycles=2, rising=True) + await ClockCycles(signal=dut.bclk, num_cycles=2, rising=True) dut.rst_n.value = 1 # await start of lrclk frame @@ -60,7 +60,7 @@ async def i2s_random_receive(dut, bit_depth: int = None): @repeat(num_repeats=3) async def i2s_random_transmit(dut, bit_depth: int = None): """ - Test random transmits with a I2S main. + Test random transmits with a I2S peripheral. """ # setup module parameters and variables bit_depth = 24 @@ -70,16 +70,18 @@ async def i2s_random_transmit(dut, bit_depth: int = None): clock = Clock(signal=dut.mclk, period=clock_period_ns, units="ns") await cocotb.start(clock.start()) + # setup inputs + dut.tx_valid.value = 0 + # reset dut.rst_n.value = 0 - dut.tx_valid.value = 0 await ClockCycles(signal=dut.bclk, num_cycles=2, rising=True) dut.rst_n.value = 1 # await for transmit_ready, continue if already high if not dut.tx_ready.value: await RisingEdge(signal=dut.tx_ready) - transmit_data = 0b101011110000111100001010 # random.randint(0, 2**bit_depth - 1) + transmit_data = random.randint(0, 2**bit_depth - 1) dut.tx_data.value = transmit_data dut.tx_valid.value = 1 @@ -100,10 +102,63 @@ async def i2s_random_transmit(dut, bit_depth: int = None): await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=True) -# @cocotb.test() -# @repeat(num_repeats=1) -# async def i2s_random_full_duplex(dut, bit_depth: int = None): -# pass +@cocotb.test() +@repeat(num_repeats=3) +async def i2s_random_full_duplex(dut, bit_depth: int = None): + """ + Test random transmit and receives with a I2S main. + """ + # setup module parameters and variables + bit_depth = 24 + + # setup clock + clock_period_ns = int(1e9 / 12e6) + clock = Clock(signal=dut.mclk, period=clock_period_ns, units="ns") + await cocotb.start(clock.start()) + + # setup inputs + dut.rx.value = 0 # I2S idle low + dut.tx_valid.value = 0 + + # reset + dut.rst_n.value = 0 + await ClockCycles(signal=dut.bclk, num_cycles=2, rising=True) + dut.rst_n.value = 1 + + # await for transmit_ready, continue if already high + if not dut.tx_ready.value: + await RisingEdge(signal=dut.tx_ready) + transmit_data = random.randint(0, 2**bit_depth - 1) + dut.tx_data.value = transmit_data + dut.tx_valid.value = 1 + + # await start of lrclk frame + await ClockCycles(signal=dut.rx_lrclk, num_cycles=1, rising=False) + # I2S typically starts shifting out on the second falling edge of bclk + # after falling edge of lrclk + await ClockCycles(signal=dut.bclk, num_cycles=3, rising=False) # 3.0 + + for sample in range(0, 4): + # transmit and receive bits + receive_data = random.randint(0, 2**bit_depth - 1) + for index in range(0, bit_depth): + # apply rx value on falling edge + dut.rx.value = (receive_data >> (bit_depth - index - 1)) & 0b1 + + # assert tx value on rising edge + await ClockCycles(signal=dut.bclk, num_cycles=1, rising=True) + assert dut.tx.value == (transmit_data >> (bit_depth - index - 1)) & 0b1 + + # complete cycle + await ClockCycles(signal=dut.bclk, num_cycles=1, rising=False) + + # assert receive data, receive valid, and lrclk + assert dut.rx_data.value == receive_data + assert dut.rx_valid.value == 1 + + # pad rest of lrclk frame, assert lrclk + assert dut.rx_lrclk.value == sample % 2 + await ClockCycles(signal=dut.bclk, num_cycles=32 - bit_depth, rising=False) def test_i2s(): diff --git a/hardware/waves/interfaces/i2s.ron b/hardware/waves/interfaces/i2s.ron index aa90b14..66846b7 100644 --- a/hardware/waves/interfaces/i2s.ron +++ b/hardware/waves/interfaces/i2s.ron @@ -231,222 +231,236 @@ ], ), displayed_items: { - (89): Variable(( + (38): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk_inv", + name: "rx_shift_en", ), color: None, background_color: None, - display_name: "bclk_inv", + display_name: "rx_shift_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (75): Variable(( + (87): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_bit_counter_rst_n", + name: "tx_valid", ), color: None, background_color: None, - display_name: "tx_bit_counter_rst_n", + display_name: "tx_valid", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (78): Variable(( + (69): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_lrclk_counter", + name: "bclk", ), color: None, background_color: None, - display_name: "tx_lrclk_counter [5:0]", + display_name: "bclk", display_name_type: Unique, manual_name: None, - format: Some("Unsigned"), + format: None, field_formats: [], )), - (88): Variable(( + (39): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_state", + name: "rx_state", ), color: None, background_color: None, - display_name: "tx_state [7:0]", + display_name: "rx_state [7:0]", display_name_type: Unique, manual_name: None, format: Some("Binary"), field_formats: [], )), - (38): Variable(( + (30): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_shift_en", + name: "rx_bit_counter", ), color: None, background_color: None, - display_name: "rx_shift_en", + display_name: "rx_bit_counter [4:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), - (79): Variable(( + (28): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_lrclk_rst_n", + name: "rst_n", ), color: None, background_color: None, - display_name: "tx_lrclk_rst_n", + display_name: "rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (85): Variable(( + (22): Group(( + name: "transmit", + color: Some("Gray"), + background_color: Some("Gray"), + content: [], + is_open: false, + )), + (37): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk", + name: "rx_ready", ), color: None, background_color: None, - display_name: "bclk", + display_name: "rx_ready", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (35): Variable(( + (85): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lrclk_rst_n", + name: "bclk", ), color: None, background_color: None, - display_name: "rx_lrclk_rst_n", + display_name: "bclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (26): Variable(( + (21): Group(( + name: "receive", + color: Some("Gray"), + background_color: Some("Gray"), + content: [], + is_open: false, + )), + (79): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "mclk", + name: "tx_lrclk_rst_n", ), color: None, background_color: None, - display_name: "mclk", + display_name: "tx_lrclk_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (86): Variable(( + (40): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_data", + name: "rx_valid", ), color: None, background_color: None, - display_name: "tx_data [23:0]", + display_name: "rx_valid", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (27): Variable(( + (35): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "mute", + name: "rx_lrclk_rst_n", ), color: None, background_color: None, - display_name: "mute", + display_name: "rx_lrclk_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (77): Variable(( + (34): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_lrclk", + name: "rx_lrclk_counter", ), color: None, background_color: None, - display_name: "tx_lrclk", + display_name: "rx_lrclk_counter [5:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), - (31): Variable(( + (89): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_bit_counter_rst_n", + name: "bclk_inv", ), color: None, background_color: None, - display_name: "rx_bit_counter_rst_n", + display_name: "bclk_inv", display_name_type: Unique, manual_name: None, format: None, @@ -469,332 +483,318 @@ format: None, field_formats: [], )), - (36): Variable(( + (26): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_next_state", + name: "mclk", ), color: None, background_color: None, - display_name: "rx_next_state [7:0]", + display_name: "mclk", display_name_type: Unique, manual_name: None, - format: Some("Binary"), + format: None, field_formats: [], )), - (33): Variable(( + (29): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lrclk", + name: "rx", ), color: None, background_color: None, - display_name: "rx_lrclk", + display_name: "rx", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (39): Variable(( + (86): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_state", + name: "tx_data", ), color: None, background_color: None, - display_name: "rx_state [7:0]", + display_name: "tx_data [23:0]", display_name_type: Unique, manual_name: None, - format: Some("Binary"), + format: None, field_formats: [], )), - (30): Variable(( + (24): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_bit_counter", + name: "bclk_counter", ), color: None, background_color: None, - display_name: "rx_bit_counter [4:0]", + display_name: "bclk_counter [1:0]", display_name_type: Unique, manual_name: None, - format: Some("Unsigned"), + format: None, field_formats: [], )), - (28): Variable(( + (36): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rst_n", + name: "rx_next_state", ), color: None, background_color: None, - display_name: "rst_n", + display_name: "rx_next_state [7:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Binary"), field_formats: [], )), - (32): Variable(( + (23): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_data", + name: "bclk", ), color: None, background_color: None, - display_name: "rx_data [23:0]", + display_name: "bclk", display_name_type: Unique, manual_name: None, - format: Some("Binary"), + format: None, field_formats: [], )), - (40): Variable(( + (73): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_valid", + name: "tx", ), color: None, background_color: None, - display_name: "rx_valid", + display_name: "tx", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (34): Variable(( + (32): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_lrclk_counter", + name: "rx_data", ), color: None, background_color: None, - display_name: "rx_lrclk_counter [5:0]", + display_name: "rx_data [23:0]", display_name_type: Unique, manual_name: None, - format: Some("Unsigned"), + format: Some("Binary"), field_formats: [], )), - (24): Variable(( + (82): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk_counter", + name: "tx_shift_en", ), color: None, background_color: None, - display_name: "bclk_counter [1:0]", + display_name: "tx_shift_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (74): Variable(( + (31): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_bit_counter", + name: "rx_bit_counter_rst_n", ), color: None, background_color: None, - display_name: "tx_bit_counter [4:0]", + display_name: "rx_bit_counter_rst_n", display_name_type: Unique, manual_name: None, - format: Some("Unsigned"), + format: None, field_formats: [], )), - (87): Variable(( + (80): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_valid", + name: "tx_next_state", ), color: None, background_color: None, - display_name: "tx_valid", + display_name: "tx_next_state [7:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Binary"), field_formats: [], )), - (29): Variable(( + (88): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx", + name: "tx_state", ), color: None, background_color: None, - display_name: "rx", + display_name: "tx_state [7:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Binary"), field_formats: [], )), - (73): Variable(( + (27): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx", + name: "mute", ), color: None, background_color: None, - display_name: "tx", + display_name: "mute", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (80): Variable(( + (77): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_next_state", + name: "tx_lrclk", ), color: None, background_color: None, - display_name: "tx_next_state [7:0]", + display_name: "tx_lrclk", display_name_type: Unique, manual_name: None, - format: Some("Binary"), + format: None, field_formats: [], )), - (21): Group(( - name: "receive", - color: Some("Gray"), - background_color: Some("Gray"), - content: [], - is_open: false, - )), - (23): Variable(( + (75): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk", + name: "tx_bit_counter_rst_n", ), color: None, background_color: None, - display_name: "bclk", + display_name: "tx_bit_counter_rst_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (37): Variable(( + (33): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "rx_ready", + name: "rx_lrclk", ), color: None, background_color: None, - display_name: "rx_ready", + display_name: "rx_lrclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (22): Group(( - name: "transmit", - color: Some("Gray"), - background_color: Some("Gray"), - content: [], - is_open: false, - )), - (69): Variable(( + (74): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "bclk", + name: "tx_bit_counter", ), color: None, background_color: None, - display_name: "bclk", + display_name: "tx_bit_counter [4:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), - (82): Variable(( + (78): Variable(( variable_ref: ( path: ( strs: [ "i2s", ], ), - name: "tx_shift_en", + name: "tx_lrclk_counter", ), color: None, background_color: None, - display_name: "tx_shift_en", + display_name: "tx_lrclk_counter [5:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), }, display_item_ref_counter: 89, viewports: [ ( - curr_left: (-0.19431991150975228), - curr_right: (1.2056800884902474), + curr_left: (-0.2), + curr_right: (1.2), target_left: (-0.2), target_right: (1.2), move_start_left: (-0.2), @@ -804,7 +804,7 @@ ), ], cursor: Some((1, [ - 111220, + 8393, ])), markers: {}, focused_item: Some((28)), From af90a63e193cb805d2d08d7c26e88073790f786b Mon Sep 17 00:00:00 2001 From: Drew Date: Fri, 9 May 2025 01:10:57 -0400 Subject: [PATCH 10/10] fix header indents --- hardware/hdl/interfaces/i2s.sv | 76 +++++++++++++++++----------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/hardware/hdl/interfaces/i2s.sv b/hardware/hdl/interfaces/i2s.sv index 9d72f4f..31d3685 100644 --- a/hardware/hdl/interfaces/i2s.sv +++ b/hardware/hdl/interfaces/i2s.sv @@ -83,43 +83,43 @@ module i2s * bclk clk divider * ============================================================================= */ -logic [BCLK_COUNTER_BITS-1:0] bclk_counter; - -// bclk counter -initial bclk_counter = '0; -always_ff @( posedge mclk ) begin : _bclk_clk_counter - if (bclk_counter == '0) - bclk_counter <= (BCLK_COUNTER_BITS)'(LRCLK_DIV - 1); - else - bclk_counter <= bclk_counter - 1; -end - -// bclk_output -always_comb begin : _bclk_clk_divider - if (bclk_counter[BCLK_COUNTER_BITS-1:0] >= (BCLK_COUNTER_BITS)'(BCLK_DIV / 2)) - bclk = 0; - else - bclk = 1; -end - -// // TODO: synthesis difference between this and the block above -// always_ff @( posedge mclk ) begin : _bclk_clk_divider -// if (!rst_n) -// bclk <= 0; -// else if (bclk_counter[BCLK_COUNTER_BITS-1:0] >= (BCLK_COUNTER_BITS)'(BCLK_DIV / 2)) -// bclk <= 0; -// else -// bclk <= 1; -// end - -// inverted bclk output -logic bclk_inv; -always_comb begin : _bclk_inv_clk_divider - if (bclk_counter[BCLK_COUNTER_BITS-1:0] >= (BCLK_COUNTER_BITS)'(BCLK_DIV / 2)) - bclk_inv = 1; - else - bclk_inv = 0; -end + logic [BCLK_COUNTER_BITS-1:0] bclk_counter; + + // bclk counter + initial bclk_counter = '0; + always_ff @( posedge mclk ) begin : _bclk_clk_counter + if (bclk_counter == '0) + bclk_counter <= (BCLK_COUNTER_BITS)'(LRCLK_DIV - 1); + else + bclk_counter <= bclk_counter - 1; + end + + // bclk_output + always_comb begin : _bclk_clk_divider + if (bclk_counter[BCLK_COUNTER_BITS-1:0] >= (BCLK_COUNTER_BITS)'(BCLK_DIV / 2)) + bclk = 0; + else + bclk = 1; + end + + // // TODO: synthesis difference between this and the block above + // always_ff @( posedge mclk ) begin : _bclk_clk_divider + // if (!rst_n) + // bclk <= 0; + // else if (bclk_counter[BCLK_COUNTER_BITS-1:0] >= (BCLK_COUNTER_BITS)'(BCLK_DIV / 2)) + // bclk <= 0; + // else + // bclk <= 1; + // end + + // inverted bclk output + logic bclk_inv; + always_comb begin : _bclk_inv_clk_divider + if (bclk_counter[BCLK_COUNTER_BITS-1:0] >= (BCLK_COUNTER_BITS)'(BCLK_DIV / 2)) + bclk_inv = 1; + else + bclk_inv = 0; + end /* * ============================================================================= @@ -267,7 +267,7 @@ end end - /* +/* * ============================================================================= * transmit * =============================================================================