`timescale 10ns/10ns module top(); reg clk = 0; reg rstn = 1; reg adc_so = 1; wire adc_si; wire adc_sck; wire adc_ss; reg sck_old = 1; reg ss_old = 1; wire [1:0] channel; wire [11:0] adc_val; wire vld; reg ack = 0; adc_driver dut( .clk(clk), .rstn(rstn), .so(adc_so), .si(adc_si), .ss(adc_ss), .sck(adc_sck), .channel(channel), .val(adc_val), .vld(vld), .ack(ack) ); reg configured; reg [15:0] out; initial begin clk = 0; rstn = 1; adc_so = 1; sck_old = 1; configured = 0; out = 0; $dumpfile("adc_driver_tb.vcd"); $dumpvars; end always #2 clk = !clk; reg enabled; integer bit_pos; integer channel_num; integer tosend; integer configdata; integer adc_pos; integer adc_out[3:0]; integer expected[3:0]; integer i; initial begin bit_pos = 0; channel_num = 0; tosend = 0; enabled = 0; configdata = 0; adc_pos = 0; adc_so = 1; for (i = 0; i < 4; i++) begin #1 adc_pos = i; #1 expected[i] = out; end adc_pos = 0; for (i = 0; i < 4; i++) adc_out[i] = 0; end always @* begin case (adc_pos[1:0]) 2'b00: out = 16'h01ff; 2'b01: out = 16'h1fff; 2'b10: out = 16'h2dea; 2'b11: out = 16'h3caf; endcase end always @(posedge clk) begin if (~adc_ss & ss_old) begin enabled <= 1; //bit_pos <= 0; end if (enabled) begin if (!configured) begin // load into configdata if it hasn't // been configured yet if (~sck_old & adc_sck) begin configdata <= (configdata << 1) | adc_si; if (bit_pos >= 15) begin configured <= 1; bit_pos <= 0; end else bit_pos <= bit_pos + 1; end end else begin if (~sck_old & adc_sck) begin // TODO make sure the input is zero end if (sck_old & ~adc_sck) begin // otherwise start loading in adc data if (bit_pos >= 15) begin bit_pos <= 0; end else bit_pos <= bit_pos + 1; adc_so <= out[15-bit_pos]; end end end if (vld & configured & ~ack) begin adc_pos <= adc_pos + 1; adc_out[channel] = adc_val; ack <= 1; if (channel == 3) begin // TODO check configdata i = { 1'b0, // ADC Mode Control 4'b0100, // Standard_Ext 4'b0011, // Up to AIN3 2'b01, // reset FIFO 2'b00, // normal PM mode 1'b1, // include channel number in output 1'b0, // SWCNV enable, not used in external clock mode 1'b0 // reserved }; if (configdata != i) $display("config %d != %d", configdata, i); for (i = 0; i < 4; i++) begin if (adc_out[i] != (12'hfff & expected[i]) ) $display("adc %x %x != %x", i, adc_out[i], expected[i]); end $finish; end end else ack <= 0; ss_old <= adc_ss; sck_old <= adc_sck; end initial begin #50000 $finish; end endmodule