diff --git a/scripts/view.sh b/scripts/view.sh index b7fecb2e..b0052006 100755 --- a/scripts/view.sh +++ b/scripts/view.sh @@ -1,4 +1,4 @@ #!/bin/bash -gtkwave -a $OH_HOME/common/dv/oh.gtkw waveform.vcd +gtkwave -a $OH_HOME/src/common/dv/oh.gtkw waveform.vcd diff --git a/src/common/hdl/oh_fifo_async.v b/src/common/hdl/oh_fifo_async.v index 5303bc82..b03bcad9 100644 --- a/src/common/hdl/oh_fifo_async.v +++ b/src/common/hdl/oh_fifo_async.v @@ -67,7 +67,11 @@ module oh_fifo_async # (parameter DW = 104, //FIFO width .din (din[DW-1:0]), .rd_en (rd_en)); end // if ((DW==104) & (DEPTH==32)) - end // block: xilinx + else + _INVALID_PARAMETERS_ invalid_parameters(); + end // block: xilinx + else + _INVALID_TARGET_ invalid_target(); endgenerate endmodule // oh_fifo_async diff --git a/src/common/hdl/oh_par2ser.v b/src/common/hdl/oh_par2ser.v index f66da340..b9b2824f 100644 --- a/src/common/hdl/oh_par2ser.v +++ b/src/common/hdl/oh_par2ser.v @@ -35,7 +35,7 @@ module oh_par2ser #(parameter PW = 64, // parallel packet width //transfer counter always @ (posedge clk or negedge nreset) if(!nreset) - count[CW-1:0] <= 'b0; + count[CW-1:0] <= {(CW){1'b0}}; else if(start_transfer) count[CW-1:0] <= datasize[CW-1:0]; //one "SW sized" transfers else if(shift & busy) @@ -51,8 +51,10 @@ module oh_par2ser #(parameter PW = 64, // parallel packet width assign wait_out = wait_in | busy; // shift register - always @ (posedge clk) - if(start_transfer) + always @ (posedge clk or negedge nreset) + if(!nreset) + shiftreg[PW-1:0] = {(PW){1'b0}}; + else if(start_transfer) shiftreg[PW-1:0] = din[PW-1:0]; else if(shift & lsbfirst) shiftreg[PW-1:0] = {{(SW){fill}}, shiftreg[PW-1:SW]}; diff --git a/src/common/hdl/oh_ser2par.v b/src/common/hdl/oh_ser2par.v index ebad2a6a..58a89a58 100644 --- a/src/common/hdl/oh_ser2par.v +++ b/src/common/hdl/oh_ser2par.v @@ -18,14 +18,16 @@ module oh_ser2par #(parameter PW = 64, // parallel packet width parameter CW = $clog2(PW/SW); // serialization factor (for counter) - reg [PW-1:0] dout; + reg [PW-1:0] dout_reg; reg [CW-1:0] count; wire [PW-1:0] shiftdata; + assign dout = dout_reg; + always @ (posedge clk) if(shift & lsbfirst) - dout[PW-1:0] <= {din[SW-1:0],dout[PW-1:SW]}; + dout_reg[PW-1:0] <= {din[SW-1:0],dout_reg[PW-1:SW]}; else if(shift) - dout[PW-1:0] <= {dout[PW-SW-1:0],din[SW-1:0]}; + dout_reg[PW-1:0] <= {dout_reg[PW-SW-1:0],din[SW-1:0]}; endmodule // oh_ser2par diff --git a/src/parallella/hdl/pgpio.v b/src/parallella/hdl/pgpio.v index 7fb51327..21db4e1b 100644 --- a/src/parallella/hdl/pgpio.v +++ b/src/parallella/hdl/pgpio.v @@ -11,10 +11,12 @@ module pgpio(/*AUTOARG*/ ps_gpio_o, ps_gpio_t ); - parameter NGPIO = 24; // 12 or 24 - parameter NPS = 64; // signals for PS - parameter DIFF = 0; // 0= single ended - // 1= differential + parameter NGPIO = 24; // 12 or 24 + parameter NPS = 64; // signals for PS + parameter DIFF = 0; // 0= single ended + // 1= differential + parameter SLEW = "SLOW"; // "SLOW" or "FAST", only applicable to + // single ended. inout [NGPIO-1:0] gpio_p; inout [NGPIO-1:0] gpio_n; @@ -74,7 +76,7 @@ module pgpio(/*AUTOARG*/ .DRIVE(8), // Specify the output drive strength .IBUF_LOW_PWR("TRUE"), // Low Power - "TRUE", High Performance = "FALSE" .IOSTANDARD("LVCMOS25"), // Specify the I/O standard - .SLEW("SLOW") // Specify the output slew rate + .SLEW(SLEW) // Specify the output slew rate ) i_iocmos_n [NGPIO-1:0] ( @@ -89,7 +91,7 @@ module pgpio(/*AUTOARG*/ .DRIVE(8), // Specify the output drive strength .IBUF_LOW_PWR("TRUE"), // Low Power - "TRUE", High Performance = "FALSE" .IOSTANDARD("LVCMOS25"), // Specify the I/O standard - .SLEW("SLOW") // Specify the output slew rate + .SLEW(SLEW) // Specify the output slew rate ) i_iocmos_p [NGPIO-1:0] ( diff --git a/src/spi/dv/tests/test_high_bits.emf b/src/spi/dv/tests/test_high_bits.emf new file mode 100644 index 00000000..6545fd3e --- /dev/null +++ b/src/spi/dv/tests/test_high_bits.emf @@ -0,0 +1,18 @@ +DEADBEEF_00000003_00000002_01_0020 //CLKDIV (BAUDRATE, DIVIDE by 8) +DEADBEEF_00000020_00000008_01_0000 //TX DATA (command=write addr=spi_user0) +DEADBEEF_000000FE_00000008_01_0000 //TX DATA (data) +DEADBEEF_000000DC_00000008_01_0000 //TX DATA (data) +DEADBEEF_000000BA_00000008_01_0000 //TX DATA (data) +DEADBEEF_00000098_00000008_01_0000 //TX DATA (data) +DEADBEEF_00000076_00000008_01_0000 //TX DATA (data) +DEADBEEF_00000054_00000008_01_0000 //TX DATA (data) +DEADBEEF_00000032_00000008_01_0100 //TX DATA (data) +DEADBEEF_000000A0_00000008_01_0000 //TX DATA (command=read addr=spi_user0) +DEADBEEF_00000000_00000008_01_0000 //TX DATA (read) +DEADBEEF_00000000_00000008_01_0000 //TX DATA (read) +DEADBEEF_00000000_00000008_01_0000 //TX DATA (read) +DEADBEEF_00000000_00000008_01_0000 //TX DATA (read) +DEADBEEF_00000000_00000008_01_0000 //TX DATA (read) +DEADBEEF_00000000_00000008_01_0000 //TX DATA (read) +DEADBEEF_00000000_00000008_01_0400 //TX DATA (read) +DEADBEEF_00000000_00000010_04_0400 // Read local RX0 diff --git a/src/spi/fpga/axi_spi_timing.xdc b/src/spi/fpga/axi_spi_timing.xdc index 90770f54..1299badf 100644 --- a/src/spi/fpga/axi_spi_timing.xdc +++ b/src/spi/fpga/axi_spi_timing.xdc @@ -1,3 +1,32 @@ -# SPI slave clock -create_clock -name spi_s_sclk -period 10 [get_ports spi_s_sclk] +# Use numbers from here: +# https://en.wikipedia.org/wiki/Propagation_delay +# Assume wires are shorter than < 30cm (12") +# slave +create_clock -period 30.000 -name spi_s_sclk -waveform {0.000 15.000} [get_ports {gpio_p[3]}] +# assign spi_s_mosi = gpio_in[8]; +set_input_delay -clock spi_s_sclk -max 2.000 [get_ports {gpio_n[4]}] +# assign spi_s_miso = gpio_out[9]; +set_output_delay -clock spi_s_sclk -max -add_delay 2.000 [get_ports {gpio_n[5]}] +# assign spi_s_ss = gpio_in[10]; +set_input_delay -clock spi_s_sclk -max 2.000 [get_ports {gpio_p[4]}] + +#master +# assign spi_m_sclk = gpio_out[3]; +# just misses timing for 100 MHz +create_clock -period 20.000 -name spi_m_sclk -waveform {0.000 10.000} [get_ports {gpio_p[1]}] +# assign spi_m_mosi = gpio_out[4]; +set_output_delay -clock spi_m_sclk -max -add_delay 2.000 [get_ports {gpio_n[2]}] +# assign spi_m_miso = gpio_in[5]; +set_input_delay -clock spi_m_sclk -max 2.000 [get_ports {gpio_n[3]}] +# assign spi_m_ss = gpio_out[6]; +set_output_delay -clock spi_m_sclk -max -add_delay 2.000 [get_ports {gpio_p[2]}] + +set_false_path -from [get_clocks clk_fpga_0] -to [get_clocks spi_m_sclk] + +# pgpio.v pin mapping +# for(m=0; m8) .load (load_byte), // load data from fifo .lsbfirst (lsbfirst), // serializer direction @@ -146,10 +151,14 @@ module spi_master_io //generate access pulse at rise of ss oh_rise2pulse - pulse (.out (rx_access), + pulse (.nreset(nreset), + .out (rx_access), .clk (clk), .in (ss)); - + + // In CPOL=0 CPHA=0 (MODE=0) MISO is sampled on positive egde. + wire rx_shift; + assign rx_shift = (spi_state[2:0] == `SPI_DATA) & period_match; oh_ser2par #(.PW(64), .SW(1)) ser2par (//output @@ -158,7 +167,7 @@ module spi_master_io .din (miso), // serial data in .clk (clk), // shift clk .lsbfirst (lsbfirst), // shift direction - .shift (shift)); // shift data + .shift (rx_shift)); // shift data endmodule // spi_master_io // Local Variables: diff --git a/src/spi/hdl/spi_master_regs.v b/src/spi/hdl/spi_master_regs.v index fbd092ce..0cf78cde 100644 --- a/src/spi/hdl/spi_master_regs.v +++ b/src/spi/hdl/spi_master_regs.v @@ -24,7 +24,7 @@ module spi_master_regs # (parameter CLKDIV = 1, // default clkdiv output lsbfirst, // send lsbfirst output spi_en, // enable transmitter output [7:0] clkdiv_reg, // baud rate setting - input [1:0] spi_state, // transmit state + input [2:0] spi_state, // transmit state input fifo_prog_full, // fifo reached half/full input fifo_wait, // tx transfer wait //packet to transmit @@ -120,7 +120,7 @@ module spi_master_regs # (parameter CLKDIV = 1, // default clkdiv else status_reg[7:0] <= {5'b0, //7:3 fifo_prog_full, //2 - |spi_state[1:0], //1 + |spi_state[2:0], //1 (rx_access | status_reg[0])};//0 //#################################### @@ -170,11 +170,12 @@ module spi_master_regs # (parameter CLKDIV = 1, // default clkdiv end //create a pulse on register reads - oh_edge2pulse + oh_edge2pulse e2pulse (.out (wait_pulse), .clk (clk), - .in (reg_read)); - + .in (reg_read), + .nreset (nreset)); + //TODO: fix! assign wait_out = fifo_wait; diff --git a/src/spi/hdl/spi_slave_io.v b/src/spi/hdl/spi_slave_io.v index a85876a7..602005c8 100644 --- a/src/spi/hdl/spi_slave_io.v +++ b/src/spi/hdl/spi_slave_io.v @@ -58,44 +58,61 @@ module spi_slave_io #( parameter PW = 104 // packet width spi_state[1:0] <= `SPI_IDLE; else case (spi_state[1:0]) - `SPI_IDLE : spi_state[1:0] <= `SPI_CMD; - `SPI_CMD : spi_state[1:0] <= byte_done ? `SPI_DATA : `SPI_CMD; + default : spi_state[1:0] <= `SPI_CMD; + `SPI_CMD : spi_state[1:0] <= next_byte ? `SPI_DATA : `SPI_CMD; `SPI_DATA : spi_state[1:0] <= `SPI_DATA; endcase // case (spi_state[1:0]) - + //bit counter always @ (posedge sclk or posedge ss) if(ss) bit_count[7:0] <= 'b0; else bit_count[7:0] <= bit_count[7:0] + 1'b1; - - assign byte_done = (spi_state[1:0]!=`SPI_IDLE) & - (bit_count[2:0]==3'b000); - + + assign next_byte = (spi_state[1:0]!=`SPI_IDLE) & + (bit_count[2:0]==3'b000); + + assign byte_done = (spi_state[1:0]!=`SPI_IDLE) & + (bit_count[2:0]==3'b111); + // command/address register // auto increment for every byte - always @ (negedge sclk or negedge nreset) + always @ (posedge sclk or negedge nreset) if(!nreset) command_reg[7:0] <= 'b0; else if((spi_state[1:0]==`SPI_CMD) & byte_done) - command_reg[7:0] <= rx_data[7:0]; + command_reg[7:0] <= spi_wdata[7:0]; else if(byte_done) command_reg[7:0] <= {command_reg[7:6], command_reg[5:0] + 1'b1}; - + + //################################# - //# SPI RX SHIFT REGISTER + //# CPOL=0 CPHA=0 settings //################################# + // RX assign rx_shift = ~ss & spi_en; + assign rx_clk = sclk; + + // TX + assign tx_clk = ~sclk; + assign tx_shift = rx_shift; + assign tx_load = next_byte; + + //################################# + //# SPI RX SHIFT REGISTER + //################################# + oh_ser2par #(.PW(8), .SW(1)) + //.EDGE("RISING")) // CPOL=0 CPHA=0 rx_ser2par (// Outputs .dout (rx_data[7:0]), // Inputs - .clk (sclk), + .clk (rx_clk), .din (mosi), .lsbfirst (lsbfirst), //msb first .shift (rx_shift)); @@ -103,13 +120,13 @@ module spi_slave_io #( parameter PW = 104 // packet width //#################################### //# REMOTE TRANSAXTION SHIFT REGISTER //#################################### - + oh_ser2par #(.PW(PW), .SW(1)) e_ser2par (// Outputs .dout (packet_out[PW-1:0]), // Inputs - .clk (sclk), + .clk (rx_clk), .din (mosi), .lsbfirst (lsbfirst), //msb first .shift (rx_shift));//rx_shift @@ -118,15 +135,12 @@ module spi_slave_io #( parameter PW = 104 // packet width //# TX SHIFT REGISTER //################################# - assign tx_load = byte_done; // & (spi_state[1:0]==`SPI_CMD); - assign tx_shift = ~ss & spi_en; - oh_par2ser #(.PW(8), .SW(1)) tx_par2ser (.dout (miso), .access_out (), .wait_out (tx_wait), - .clk (sclk), // shift out on positive edge + .clk (tx_clk), .nreset (~ss), .din (spi_rdata[7:0]), .shift (tx_shift), @@ -147,10 +161,17 @@ module spi_slave_io #( parameter PW = 104 // packet width assign spi_write = spi_en & byte_done & ~ss & - (command_reg[7:6]==`SPI_WR) & + (command_reg[7:6]==`SPI_WR) & (spi_state[1:0]==`SPI_DATA); - - assign spi_wdata[7:0] = rx_data[7:0]; + + // CPOL=0 CPHA=0: + // Skip pipeline stage in rx_ser2par, and grab last bit directly from pin. + // When first RX byte is received on 8th rising edge we need it immediately + // because transmission of the second TX byte starts on the following + // falling edge. + + assign spi_wdata[7:0] = lsbfirst ? {mosi, rx_data[6:0]} + : {rx_data[6:0], mosi}; //################################### //# REMOTE FETCH LOGIC @@ -165,9 +186,10 @@ module spi_slave_io #( parameter PW = 104 // packet width .din (ss)); //create single cycle pulse - oh_rise2pulse r2p (.out (ss_pulse), - .clk (clk), - .in (ss_sync)); + oh_rise2pulse r2p (.nreset (nreset), + .out (ss_pulse), + .clk (clk), + .in (ss_sync)); assign spi_fetch = ss_pulse & (command_reg[7:6]==`SPI_FETCH); diff --git a/src/spi/hdl/spi_slave_regs.v b/src/spi/hdl/spi_slave_regs.v index f9a9dff6..b9b59335 100644 --- a/src/spi/hdl/spi_slave_regs.v +++ b/src/spi/hdl/spi_slave_regs.v @@ -16,6 +16,7 @@ module spi_slave_regs #( parameter UREGS = 13, // # of user regs (max 48) input clk, // core clock input nreset, // asych active low input hw_en, // block enable pin + // IO // sclk io domain input spi_clk, // slave clock input [7:0] spi_wdata, // slave write data in (for write) @@ -90,7 +91,7 @@ module spi_slave_regs #( parameter UREGS = 13, // # of user regs (max 48) //# CONFIG [0] //##################################### - always @ (negedge spi_clk or negedge nreset) + always @ (posedge spi_clk or negedge nreset) if(!nreset) spi_config[7:0] <= 'b0; else if(spi_config_write) @@ -126,9 +127,14 @@ module spi_slave_regs #( parameter UREGS = 13, // # of user regs (max 48) //# USER SPACE REGISTERS //##################################### - always @ (negedge spi_clk) - if(spi_user_write) - user_regs[spi_addr[4:0]] <= spi_wdata[7:0]; +// always @ (posedge spi_clk or negedge nreset) +// if(!nreset) +// for(i=0;i<32;i=i+1) +// user_regs[i] <= 7'b0; + + always @ (posedge spi_clk) + if (spi_user_write) + user_regs[spi_addr[4:0]] <= spi_wdata[7:0]; //##################################### //# REGISTER VECTOR (FOR FLEXIBILITY)