Skip to content

Commit

Permalink
Add system level integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
vk2seb committed Sep 19, 2023
1 parent b033f23 commit 45e6bcc
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 88 deletions.
8 changes: 8 additions & 0 deletions gateware/boards/icebreaker/sysmgr.v
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module sysmgr (
assign clk_fs = clkdiv[7];

// PLL instance
`ifndef COCOTB_SIM
`ifndef VERILATOR_LINT_ONLY
SB_PLL40_2F_PAD #(
.DIVR(4'b0000),
Expand Down Expand Up @@ -57,6 +58,9 @@ module sysmgr (
.SCLK(1'b0)
);
`endif
`else
assign clk_1x_i = clk_in;
`endif

// Logic reset generation
always @(posedge clk_1x_i or negedge pll_lock)
Expand All @@ -72,11 +76,15 @@ module sysmgr (
clkdiv <= clkdiv + 1;


`ifndef COCOTB_SIM
`ifndef VERILATOR_LINT_ONLY
SB_GB rst_gbuf_I (
.USER_SIGNAL_TO_GLOBAL_BUFFER(rst_i),
.GLOBAL_BUFFER_OUTPUT(rst_out)
);
`endif
`else
assign rst_out = rst_i;
`endif

endmodule // sysmgr
136 changes: 77 additions & 59 deletions gateware/cal/cal.sv
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module cal #(
parameter W = 16, // sample width
parameter CAL_MEM_FILE = "cal/cal_mem.hex"
)(
input rst,
input clk_256fs,
input clk_fs,
input [7:0] jack,
Expand Down Expand Up @@ -57,80 +58,97 @@ localparam int signed CLAMPH = 32'sd32000;

logic signed [W-1:0] cal_mem [0:(2*N_CHANNELS)-1];
logic signed [(2*W)-1:0] out [N_CHANNELS];
logic [2:0] ch = 0;
logic [2:0] state = CAL_ST_ZERO;
logic l_clk_fs = 1'd0;
logic [2:0] ch;
logic [2:0] state;
logic l_clk_fs;

// Calibration memory for 8 channels stored as
// 2 bytes shift, 2 bytes multiply * 8 channels.
initial $readmemh(CAL_MEM_FILE, cal_mem);

always_ff @(posedge clk_256fs) begin

// On rising clk_fs.
if (clk_fs && (l_clk_fs != clk_fs)) begin
state <= CAL_ST_LATCH;
if (rst) begin
l_clk_fs <= 0;
ch <= 0;
state <= CAL_ST_LATCH;
out[0] <= 0;
out[1] <= 0;
out[2] <= 0;
out[3] <= 0;
out[4] <= 0;
out[5] <= 0;
out[6] <= 0;
out[7] <= 0;
end else begin
ch <= ch + 1;
end

case (state)
CAL_ST_LATCH: begin
case (ch)
0: out[0] <= 32'(in0);
1: out[1] <= 32'(in1);
2: out[2] <= 32'(in2);
3: out[3] <= 32'(in3);
4: out[4] <= 32'(in4);
5: out[5] <= 32'(in5);
6: out[6] <= 32'(in6);
7: out[7] <= 32'(in7);
endcase
if (ch == LAST_CH_IX) state <= CAL_ST_ZERO;
end
CAL_ST_ZERO: begin
out[ch] <= (out[ch] - 32'(cal_mem[{ch, 1'b0}]));
if (ch == LAST_CH_IX) state <= CAL_ST_MULTIPLY;
end
CAL_ST_MULTIPLY: begin
out[ch] <= (out[ch] * cal_mem[{ch, 1'b1}]) >>> 10;
if (ch == LAST_CH_IX) state <= CAL_ST_CLAMPL;
end
CAL_ST_CLAMPL: begin
out[ch] <= ((out[ch] < CLAMPL) ? CLAMPL : out[ch]);
if (ch == LAST_CH_IX) state <= CAL_ST_CLAMPH;
end
CAL_ST_CLAMPH: begin
out[ch] <= ((out[ch] > CLAMPH) ? CLAMPH : out[ch]);
if (ch == LAST_CH_IX) state <= CAL_ST_OUT;
end
CAL_ST_OUT: begin
// Calibrated input samples are zeroed if jack disconnected.
out0 <= jack[0] ? out[0][W-1:0] : 0;
out1 <= jack[1] ? out[1][W-1:0] : 0;
out2 <= jack[2] ? out[2][W-1:0] : 0;
out3 <= jack[3] ? out[3][W-1:0] : 0;
out4 <= out[4][W-1:0];
out5 <= out[5][W-1:0];
out6 <= out[6][W-1:0];
out7 <= out[7][W-1:0];
state <= CAL_ST_HALT;
end
default: begin
// Halt and do nothing.
l_clk_fs <= clk_fs;

// On rising clk_fs.
if (clk_fs && (l_clk_fs != clk_fs)) begin
state <= CAL_ST_LATCH;
ch <= 0;
end else begin
ch <= ch + 1;
end
endcase

l_clk_fs <= clk_fs;
case (state)
CAL_ST_LATCH: begin
case (ch)
0: out[0] <= 32'(in0);
1: out[1] <= 32'(in1);
2: out[2] <= 32'(in2);
3: out[3] <= 32'(in3);
4: out[4] <= 32'(in4);
5: out[5] <= 32'(in5);
6: out[6] <= 32'(in6);
7: out[7] <= 32'(in7);
endcase
if (ch == LAST_CH_IX) state <= CAL_ST_ZERO;
end
CAL_ST_ZERO: begin
out[ch] <= (out[ch] - 32'(cal_mem[{ch, 1'b0}]));
if (ch == LAST_CH_IX) state <= CAL_ST_MULTIPLY;
end
CAL_ST_MULTIPLY: begin
out[ch] <= (out[ch] * cal_mem[{ch, 1'b1}]) >>> 10;
if (ch == LAST_CH_IX) state <= CAL_ST_CLAMPL;
end
CAL_ST_CLAMPL: begin
out[ch] <= ((out[ch] < CLAMPL) ? CLAMPL : out[ch]);
if (ch == LAST_CH_IX) state <= CAL_ST_CLAMPH;
end
CAL_ST_CLAMPH: begin
out[ch] <= ((out[ch] > CLAMPH) ? CLAMPH : out[ch]);
if (ch == LAST_CH_IX) state <= CAL_ST_OUT;
end
CAL_ST_OUT: begin
// Calibrated input samples are zeroed if jack disconnected.
out0 <= out[0][W-1:0];
out1 <= out[1][W-1:0];
out2 <= out[2][W-1:0];
out3 <= out[3][W-1:0];
out4 <= out[4][W-1:0];
out5 <= out[5][W-1:0];
out6 <= out[6][W-1:0];
out7 <= out[7][W-1:0];
state <= CAL_ST_HALT;
end
default: begin
// Halt and do nothing.
end
endcase
end
end

`ifdef COCOTB_SIM
initial begin
$dumpfile ("cal.vcd");
$dumpvars;
#1;
end
generate
genvar idx;
for(idx = 0; idx < 8; idx = idx+1) begin: register
wire [31:0] tmp;
assign tmp = out[idx];
end
endgenerate
`endif

endmodule
29 changes: 13 additions & 16 deletions gateware/drivers/ak4619.sv
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,24 @@ assign lrck = clkdiv[7];
assign channel = clkdiv[7:6]; // 0, 1, 2, 3 == L, R, L, R
assign bit_counter = clkdiv[5:1];

always_ff @(negedge clk_fs) begin
dac_words = {sample_in3, sample_in2,
sample_in1, sample_in0};
sample_out0 <= adc_words[0];
sample_out1 <= adc_words[1];
sample_out2 <= adc_words[2];
sample_out3 <= adc_words[3];
end

always_ff @(posedge clk_256fs) begin
clkdiv <= clkdiv + 1;
if (rst) begin
clkdiv <= 8'h0;
sample_out0 <= 0;
sample_out1 <= 0;
sample_out2 <= 0;
sample_out3 <= 0;
end else if (bick) begin // HI -> LO
if (channel == (N_CHANNELS-1) && bit_counter == (2*W-1)) begin
dac_words = {sample_in3, sample_in2,
sample_in1, sample_in0};
sample_out0 <= adc_words[0];
sample_out1 <= adc_words[1];
sample_out2 <= adc_words[2];
sample_out3 <= adc_words[3];
end

// Clock in W bits
if (bit_counter == 0) begin
adc_words[channel] <= 0;
Expand All @@ -92,12 +96,5 @@ always_ff @(posedge clk_256fs) begin
end
end

`ifdef COCOTB_SIM
initial begin
$dumpfile ("ak4619.vcd");
$dumpvars;
#1;
end
`endif

endmodule
15 changes: 6 additions & 9 deletions gateware/drivers/pmod_i2c_master.sv
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ localparam I2C_DELAY1 = 0,
I2C_JACK2 = 8, // >>--/
I2C_IDLE = 9;

`ifdef COCOTB_SIM
localparam STARTUP_DELAY_BIT = 4;
`else
localparam STARTUP_DELAY_BIT = 17;
`endif

logic [3:0] i2c_state = I2C_DELAY1;

Expand Down Expand Up @@ -109,7 +114,7 @@ always_ff @(posedge clk) begin
if (ready && ~stb) begin
case (i2c_state)
I2C_DELAY1: begin
if(delay_cnt[17])
if(delay_cnt[STARTUP_DELAY_BIT])
i2c_state <= I2C_EEPROM1;
end
I2C_EEPROM1: begin
Expand Down Expand Up @@ -297,12 +302,4 @@ i2c_master #(.DW(4)) i2c_master_inst(
.rst(rst)
);

`ifdef COCOTB_SIM
initial begin
$dumpfile ("pmod_i2c_master.vcd");
$dumpvars;
#1;
end
`endif

endmodule
10 changes: 6 additions & 4 deletions gateware/eurorack_pmod.sv
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ cal #(
.W(W),
.CAL_MEM_FILE(CAL_MEM_FILE)
)cal_instance (
.rst(rst),
.clk_256fs (clk_256fs),
.clk_fs (clk_fs),
// Calibrated inputs are zeroed if jack is unplugged.
Expand Down Expand Up @@ -115,12 +116,13 @@ ak4619 ak4619_instance (
.sample_out1 (sample_adc1),
.sample_out2 (sample_adc2),
.sample_out3 (sample_adc3),
.sample_in0 (force_dac_output == 0 ? sample_dac0 : force_dac_output),
.sample_in1 (force_dac_output == 0 ? sample_dac1 : force_dac_output),
.sample_in2 (force_dac_output == 0 ? sample_dac2 : force_dac_output),
.sample_in3 (force_dac_output == 0 ? sample_dac3 : force_dac_output)
.sample_in0 (sample_dac0),
.sample_in1 (sample_dac1),
.sample_in2 (sample_dac2),
.sample_in3 (sample_dac3)
);


// I2C transceiver and driver for all connected slaves.
pmod_i2c_master #(
.CODEC_CFG(CODEC_CFG_FILE),
Expand Down
18 changes: 18 additions & 0 deletions gateware/sim/integration/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
SIM ?= icarus
TOPLEVEL_LANG ?= verilog
TOPLEVEL = top
VERILOG_SOURCES = ../../top.sv \
../../eurorack_pmod.sv \
../../drivers/ak4619.sv \
../../cal/cal.sv \
../../boards/icebreaker/sysmgr.v \
../../drivers/pmod_i2c_master.sv \
../../external/no2misc/rtl/i2c_master.v \
../../cal/debug_uart.sv \
../../external/no2misc/rtl/uart_tx.v \
../../cores/mirror.sv

MODULE = tb_integration
COMPILE_ARGS += -DSELECTED_DSP_CORE=mirror

include $(shell cocotb-config --makefiles)/Makefile.sim
1 change: 1 addition & 0 deletions gateware/sim/integration/cal/cal_mem.hex
1 change: 1 addition & 0 deletions gateware/sim/integration/drivers/ak4619-cfg.hex
1 change: 1 addition & 0 deletions gateware/sim/integration/drivers/pca9635-cfg.hex
62 changes: 62 additions & 0 deletions gateware/sim/integration/tb_integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import math
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import Timer, FallingEdge, RisingEdge, ClockCycles
from cocotb.handle import Force, Release


async def clock_out_word(dut, word):
await FallingEdge(dut.bick)
for i in range(32):
await RisingEdge(dut.bick)
dut.sdout1.value = (word >> (0x1F-i)) & 1

async def clock_in_word(dut):
word = 0x00000000
await RisingEdge(dut.bick)
for i in range(32):
await FallingEdge(dut.bick)
word |= dut.sdin1.value << (0x1F-i)
return word

def bit_not(n, numbits=16):
return (1 << numbits) - 1 - n

def signed_to_twos_comp(n, numbits=16):
return n if n >= 0 else bit_not(-n, numbits) + 1

@cocotb.test()
async def test_integration_00(dut):

clk_256fs = Clock(dut.CLK, 83, units='ns')
cocotb.start_soon(clk_256fs.start())

dut.eurorack_pmod1.ak4619_instance.sdout1.value = 0

dut.sysmgr_instance.pll_lock.value = 0
await RisingEdge(dut.clk_256fs)
await RisingEdge(dut.clk_256fs)
dut.sysmgr_instance.pll_lock.value = 1

dut = dut.eurorack_pmod1.ak4619_instance

N = 20

await FallingEdge(dut.lrck)

for i in range(N):

v = signed_to_twos_comp(int(16000*math.sin((2*math.pi*i)/N)))

await clock_out_word(dut, v << 16)
await clock_out_word(dut, v << 16)
await clock_out_word(dut, v << 16)
await clock_out_word(dut, v << 16)

# Note: this edge is also where dac_words <= sample_in (sample.sv)

print("Data clocked from sdout1 present at sample_outX:")
print(hex(dut.sample_out0.value))
print(hex(dut.sample_out1.value))
print(hex(dut.sample_out2.value))
print(hex(dut.sample_out3.value))
Loading

0 comments on commit 45e6bcc

Please sign in to comment.