From 38df761877d1f1abc582a0503af40202faaed2b8 Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Tue, 24 May 2016 17:01:21 +0200 Subject: [PATCH 01/18] spi: Connect nreset of oh_rise2pulse Solves issue with master STATUS[0] always high. Signed-off-by: Ola Jeppsson --- src/spi/hdl/spi_master_io.v | 5 +++-- src/spi/hdl/spi_slave_io.v | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/spi/hdl/spi_master_io.v b/src/spi/hdl/spi_master_io.v index 1dad7d6c..0daa1270 100644 --- a/src/spi/hdl/spi_master_io.v +++ b/src/spi/hdl/spi_master_io.v @@ -146,10 +146,11 @@ 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)); - + oh_ser2par #(.PW(64), .SW(1)) ser2par (//output diff --git a/src/spi/hdl/spi_slave_io.v b/src/spi/hdl/spi_slave_io.v index a85876a7..7feb51b4 100644 --- a/src/spi/hdl/spi_slave_io.v +++ b/src/spi/hdl/spi_slave_io.v @@ -165,9 +165,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); From 20fe7c235f7ebf4a924dd22c65d9427965450f07 Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Tue, 24 May 2016 17:05:28 +0200 Subject: [PATCH 02/18] spi: fpga: Add constraint for master slave clock out Signed-off-by: Ola Jeppsson --- src/spi/fpga/axi_spi_timing.xdc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/spi/fpga/axi_spi_timing.xdc b/src/spi/fpga/axi_spi_timing.xdc index 90770f54..fce0ff68 100644 --- a/src/spi/fpga/axi_spi_timing.xdc +++ b/src/spi/fpga/axi_spi_timing.xdc @@ -1,3 +1,4 @@ # SPI slave clock create_clock -name spi_s_sclk -period 10 [get_ports spi_s_sclk] - +# SPI master clock +create_clock -name spi_m_sclk -period 10 [get_ports spi_m_sclk] From 210d2e1f47cd275957cd7dc08db24f5882f2b513 Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Thu, 26 May 2016 13:38:46 +0200 Subject: [PATCH 03/18] oh_fifo_async: Error on invalid TARGET/PARAMETERS Make sure neither synthesis or simulation can go through with an empty block. Signed-off-by: Ola Jeppsson --- src/common/hdl/oh_fifo_async.v | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 From a434697503327f81c7420bba23d30c1c915e6c11 Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Thu, 26 May 2016 13:44:11 +0200 Subject: [PATCH 04/18] spi: fpga: Add fifo_async_104x32 ip Signed-off-by: Ola Jeppsson --- src/spi/fpga/ip_params.tcl | 4 +++- src/spi/fpga/system_params.tcl | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/spi/fpga/ip_params.tcl b/src/spi/fpga/ip_params.tcl index 77a4bf9a..6e52fe42 100644 --- a/src/spi/fpga/ip_params.tcl +++ b/src/spi/fpga/ip_params.tcl @@ -17,7 +17,9 @@ set hdl_files [list \ $root/parallella/hdl \ ] -set ip_files [] +set ip_files [list \ + $root/xilibs/ip/fifo_async_104x32.xci \ + ] set constraints_files [] diff --git a/src/spi/fpga/system_params.tcl b/src/spi/fpga/system_params.tcl index 3f042e9f..77686c34 100644 --- a/src/spi/fpga/system_params.tcl +++ b/src/spi/fpga/system_params.tcl @@ -20,7 +20,9 @@ set hdl_files [list \ $root/parallella/hdl \ ] -set ip_files [] +set ip_files [list \ + $root/xilibs/ip/fifo_async_104x32.xci \ + ] set constraints_files [list \ ../../parallella/fpga/parallella_io.xdc \ From 5678a4866c240d8651aecc301c05973b3518b605 Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Thu, 26 May 2016 14:24:08 +0200 Subject: [PATCH 05/18] common: oh_par2ser: Reset shiftreg to zero on nreset Stabilizes output in simulation. Signed-off-by: Ola Jeppsson --- src/common/hdl/oh_par2ser.v | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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]}; From e7a97e3d3239dc8e39102a6a0cba75815167bc4c Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Thu, 26 May 2016 14:28:48 +0200 Subject: [PATCH 06/18] common: oh_ser2par: Add dout_reg Fixes iverilog warning. Signed-off-by: Ola Jeppsson --- src/common/hdl/oh_ser2par.v | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 From 417ad3478c15e796280f93db205cadfa4f2b1f29 Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Thu, 26 May 2016 14:39:57 +0200 Subject: [PATCH 07/18] spi: spi_master_io: Sample MISO on rising edge of SCLK In CPOL=0 CPHA=0 (MODE=0) the master outputs M0SI on the falling edge of SCLK, and samples MISO on the rising edge of SCLK. Signed-off-by: Ola Jeppsson --- src/spi/hdl/spi_master_io.v | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/spi/hdl/spi_master_io.v b/src/spi/hdl/spi_master_io.v index 0daa1270..299822f5 100644 --- a/src/spi/hdl/spi_master_io.v +++ b/src/spi/hdl/spi_master_io.v @@ -100,8 +100,10 @@ module spi_master_io //data done whne assign data_done = fifo_empty & ~spi_wait & phase_match; + // In CPOL=0 CPHA=0 (MODE=0) MOSI is output on negative egde. //shift on every clock cycle while in datamode - assign shift = phase_match & (spi_state[1:0]==`SPI_DATA);//period_match + wire tx_shift; + assign tx_shift = phase_match & (spi_state[1:0]==`SPI_DATA); //load is the result of the fifo_read always @ (posedge clk) @@ -133,7 +135,7 @@ module spi_master_io .clk (clk), .nreset (nreset), // async active low reset .din (fifo_dout[7:0]), // 8 bit data from fifo - .shift (shift), // shift on neg edge + .shift (tx_shift), // shift data .datasize (8'd7), // 8 bits at a time (0..7-->8) .load (load_byte), // load data from fifo .lsbfirst (lsbfirst), // serializer direction @@ -151,6 +153,9 @@ module spi_master_io .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[1:0] == `SPI_DATA) & period_match & ~ss; oh_ser2par #(.PW(64), .SW(1)) ser2par (//output @@ -159,7 +164,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: From 86274da2c371cdab8594410188ab3629c32f342b Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Thu, 26 May 2016 14:51:53 +0200 Subject: [PATCH 08/18] spi: spi_master_regs: Connect nreset to e2pulse Signed-off-by: Ola Jeppsson --- src/spi/hdl/spi_master_regs.v | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/spi/hdl/spi_master_regs.v b/src/spi/hdl/spi_master_regs.v index fbd092ce..65dd1ac9 100644 --- a/src/spi/hdl/spi_master_regs.v +++ b/src/spi/hdl/spi_master_regs.v @@ -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; From 71fd0347c3ac171eeb5640b6b582422ce83b02c9 Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Thu, 26 May 2016 15:30:47 +0200 Subject: [PATCH 09/18] spi: Rewrite slave to be CPOL=0 CPHA=0 compliant. CPOL=0 CPHA=0 mode: RX data is sampled on rising edge. TX data is outputted on falling edge. Between the first byte is received and the second byte should start transmitting, we have a half clock cycle so we need to bypass the deserializer for the last MOSI bit and grab it directly from the pin. Signed-off-by: Ola Jeppsson --- src/spi/hdl/spi_slave_io.v | 59 ++++++++++++++++++++++++------------ src/spi/hdl/spi_slave_regs.v | 14 ++++++--- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/spi/hdl/spi_slave_io.v b/src/spi/hdl/spi_slave_io.v index 7feb51b4..8a647a23 100644 --- a/src/spi/hdl/spi_slave_io.v +++ b/src/spi/hdl/spi_slave_io.v @@ -59,7 +59,7 @@ module spi_slave_io #( parameter PW = 104 // packet width 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; + `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]) @@ -69,33 +69,50 @@ module spi_slave_io #( parameter PW = 104 // packet width 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 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) From 0064c0f33041ab15869971f26890ad985b4c0077 Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Thu, 26 May 2016 16:32:15 +0200 Subject: [PATCH 10/18] [HACK] spi: spi_master_fifo: Use oh_fifo_cdc for XILINX Use oh_fifo_cdc for XILINX target. oh_fifo_sync does work in simulation but it does not work when synthesizing in Vivado (see #84). This also includes a hack that forces the FIFO depth/width to 32/104 when TARGET is set to "XILINX" (only available FIFO IP atm.). Signed-off-by: Ola Jeppsson --- src/spi/hdl/axi_spi.v | 3 +- src/spi/hdl/parallella_spi.v | 3 +- src/spi/hdl/spi.v | 6 ++- src/spi/hdl/spi_master.v | 6 ++- src/spi/hdl/spi_master_fifo.v | 70 ++++++++++++++++++++++++++--------- 5 files changed, 65 insertions(+), 23 deletions(-) diff --git a/src/spi/hdl/axi_spi.v b/src/spi/hdl/axi_spi.v index 2122cfba..b9bdb0ae 100644 --- a/src/spi/hdl/axi_spi.v +++ b/src/spi/hdl/axi_spi.v @@ -29,6 +29,7 @@ module axi_spi(/*AUTOARG*/ parameter PW = 2*AW+40; // packet width parameter ID = 12'h810; // addr[31:20] id parameter S_IDW = 12; // ID width for S_AXI + parameter TARGET = "GENERIC"; // XILINX,ALTERA,GENERIC,ASIC //clk, reset input sys_nreset; // active low async reset @@ -122,7 +123,7 @@ module axi_spi(/*AUTOARG*/ wire spi_wait_in; /* spi AUTO_TEMPLATE (.\([sm]_.*\) (spi_\1[]),); */ - spi #(.AW(AW)) + spi #(.AW(AW),.TARGET(TARGET)) spi ( //Outputs .hw_en (1'b1), diff --git a/src/spi/hdl/parallella_spi.v b/src/spi/hdl/parallella_spi.v index 46e14fc1..29b83858 100644 --- a/src/spi/hdl/parallella_spi.v +++ b/src/spi/hdl/parallella_spi.v @@ -32,6 +32,7 @@ module parallella_spi(/*AUTOARG*/ parameter ID = 12'h7fe; // addr[31:20] id parameter S_IDW = 12; // ID width for S_AXI parameter NGPIO = 24; // number of gpio pins + parameter TARGET = "XILINX"; // XILINX,ALTERA,GENERIC,ASIC // constants input constant_zero; // Always 0 @@ -139,7 +140,7 @@ module parallella_spi(/*AUTOARG*/ .gpio_n (gpio_n[NGPIO-1:0])); - axi_spi #(.S_IDW(S_IDW),.AW(AW),.ID(ID)) + axi_spi #(.S_IDW(S_IDW),.AW(AW),.ID(ID),.TARGET(TARGET)) axi_spi (// Outputs .spi_irq (spi_irq), .spi_m_mosi (spi_m_mosi), diff --git a/src/spi/hdl/spi.v b/src/spi/hdl/spi.v index ca6687a0..31d60e4a 100644 --- a/src/spi/hdl/spi.v +++ b/src/spi/hdl/spi.v @@ -7,7 +7,8 @@ module spi #( parameter AW = 32, // address width parameter PW = 104, // packet size - parameter UREGS = 13 // number of user slave regs + parameter UREGS = 13, // number of user slave regs + parameter TARGET = "GENERIC" // XILINX,ALTERA,GENERIC,ASIC ) (//clk, reset, irq input nreset, // asynch active low reset @@ -63,7 +64,8 @@ module spi #( parameter AW = 32, // address width */ spi_master #(.AW(AW), - .PW(PW)) + .PW(PW), + .TARGET(TARGET)) spi_master (/*AUTOINST*/ // Outputs .sclk (m_sclk), // Templated diff --git a/src/spi/hdl/spi_master.v b/src/spi/hdl/spi_master.v index b1d12ada..61d23324 100644 --- a/src/spi/hdl/spi_master.v +++ b/src/spi/hdl/spi_master.v @@ -8,7 +8,8 @@ module spi_master # ( parameter DEPTH = 32, // fifo depth parameter REGS = 16, // total # of regs parameter AW = 32, // addresss width - parameter PW = 104 // packet width + parameter PW = 104, // packet width + parameter TARGET = "GENERIC" // XILINX,ALTERA,GENERIC,ASIC ) ( //clk,reset, cfg @@ -93,7 +94,8 @@ module spi_master # ( parameter DEPTH = 32, // fifo depth spi_master_fifo #(.AW(AW), .PW(PW), - .DEPTH(DEPTH)) + .DEPTH(DEPTH), + .TARGET(TARGET)) spi_master_fifo( /*AUTOINST*/ // Outputs diff --git a/src/spi/hdl/spi_master_fifo.v b/src/spi/hdl/spi_master_fifo.v index 83c588d1..76bfce09 100644 --- a/src/spi/hdl/spi_master_fifo.v +++ b/src/spi/hdl/spi_master_fifo.v @@ -11,7 +11,8 @@ module spi_master_fifo #( parameter DEPTH = 16, // fifo entries parameter PW = 104, // input packet width parameter SW = 8, // io packet width parameter FAW = $clog2(DEPTH), // fifo address width - parameter SRW = $clog2(PW/SW) // serialization factor + parameter SRW = $clog2(PW/SW), // serialization factor + parameter TARGET = "GENERIC" // XILINX,ALTERA,GENERIC,ASIC ) ( //clk,reset, cfg @@ -69,7 +70,8 @@ module spi_master_fifo #( parameter DEPTH = 16, // fifo entries access_in & ~fifo_wait & (dstaddr_in[5:0]==`SPI_TX); - + + wire fifo_wait; assign wait_out = fifo_wait; // & tx_write; //epiphany mode works in msb or lsb mode @@ -79,7 +81,7 @@ module spi_master_fifo #( parameter DEPTH = 16, // fifo entries assign tx_data[PW-1:0] = {{(40){1'b0}}, srcaddr_in[AW-1:0], data_in[AW-1:0]}; - + //################################## //# FIFO PACKET WRITE //################################## @@ -106,20 +108,54 @@ module spi_master_fifo #( parameter DEPTH = 16, // fifo entries //# FIFO //################################### - oh_fifo_sync #(.DEPTH(DEPTH), - .DW(SW)) - fifo(// Outputs - .dout (fifo_dout[7:0]), - .full (fifo_full), - .prog_full (fifo_prog_full), - .empty (fifo_empty), - .rd_count (), - // Inputs - .clk (clk), - .nreset (nreset), - .din (fifo_din[7:0]), - .wr_en (fifo_wr), - .rd_en (fifo_read)); + // HACK: oh_fifo_sync is broken for XILINX target. + generate + if(TARGET=="XILINX") begin : gen_xilinx_fifo + // HACK: Hardcoded DW/DEPTH to please XILINX target + wire [103:0] fifo_dout_full; + assign fifo_dout[SW-1:0] = fifo_dout_full[SW-1:0]; + + wire [103:0] packet_in_full; + assign packet_in_full[103:0] = {{(104-SW){1'b0}},fifo_din[SW-1:0]}; + + // oh_fifo_cdc #(.DW(SW), + // .DEPTH(DEPTH), + // .TARGET(TARGET)) + oh_fifo_cdc #(.DW(104), + .DEPTH(32), + .TARGET(TARGET)) + fifo (// Outputs + .wait_out (), + .access_out (), + .packet_out (fifo_dout_full[103:0]), + .prog_full (fifo_prog_full), + .full (fifo_full), + .empty (fifo_empty), + // Inputs + .nreset (nreset), + .clk_in (clk), + .packet_in (packet_in_full[103:0]), + .clk_out (clk), + .access_in (fifo_wr), + .wait_in (~fifo_read)); + end // TARGET == "XILINX" + else begin : gen_generic_fifo + oh_fifo_sync #(.DEPTH(DEPTH), + .DW(SW)) + fifo(// Outputs + .dout (fifo_dout[7:0]), + .full (fifo_full), + .prog_full (fifo_prog_full), + .empty (fifo_empty), + .rd_count (), + // Inputs + .clk (clk), + .nreset (nreset), + .din (fifo_din[7:0]), + .wr_en (fifo_wr), + .rd_en (fifo_read)); + end // TARGET != "XILINX" + endgenerate endmodule // spi_master_fifo From bd8576f9f937d0a3ad2cf4d865d051c29e614fc8 Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Fri, 27 May 2016 17:04:58 +0200 Subject: [PATCH 11/18] spi: dv: Add 'high bits' test Should output 0x00fedcba98765432 to master receive FIFO register. Signed-off-by: Ola Jeppsson --- src/spi/dv/tests/test_high_bits.emf | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/spi/dv/tests/test_high_bits.emf 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 From a3e89eba8c9c442ad92d39075013f56734fadb7a Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Fri, 27 May 2016 17:08:19 +0200 Subject: [PATCH 12/18] scripts: view.sh: Fix path to presets file Signed-off-by: Ola Jeppsson --- scripts/view.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From c92cac626664d3fe6055ce31ce1e2ee1eab8dfe5 Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Fri, 27 May 2016 17:19:18 +0200 Subject: [PATCH 13/18] spi: spi_slave_io: Add default case to state machine Fixes iverilog warning. Signed-off-by: Ola Jeppsson --- src/spi/hdl/spi_slave_io.v | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spi/hdl/spi_slave_io.v b/src/spi/hdl/spi_slave_io.v index 8a647a23..602005c8 100644 --- a/src/spi/hdl/spi_slave_io.v +++ b/src/spi/hdl/spi_slave_io.v @@ -58,11 +58,11 @@ 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; + 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) From 07fc3b46a7aa5c6acf47e6ba055f51d6471bd94d Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Fri, 27 May 2016 23:35:20 +0200 Subject: [PATCH 14/18] parallella: pgpio: Add parameter for SLEW rate Allow setting SLEW rate in single-ended mode. Signed-off-by: Ola Jeppsson --- src/parallella/hdl/pgpio.v | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) 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] ( From c960cc010d09ad696e5959fd30b42e717d0513f3 Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Fri, 27 May 2016 23:36:52 +0200 Subject: [PATCH 15/18] spi: parallell_spi: Set gpio pin SLEW rate to "FAST" Signed-off-by: Ola Jeppsson --- src/spi/hdl/parallella_spi.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spi/hdl/parallella_spi.v b/src/spi/hdl/parallella_spi.v index 29b83858..bd342453 100644 --- a/src/spi/hdl/parallella_spi.v +++ b/src/spi/hdl/parallella_spi.v @@ -130,7 +130,7 @@ module parallella_spi(/*AUTOARG*/ assign constant_zero = 1'b0; assign constant_one = 1'b1; - pgpio #(.NGPIO(NGPIO),.NPS(NGPIO)) + pgpio #(.NGPIO(NGPIO),.NPS(NGPIO),.SLEW("FAST")) pgpio (.ps_gpio_i (gpio_in[NGPIO-1:0]), .ps_gpio_o (gpio_out[NGPIO-1:0]), .ps_gpio_t (~gpio_dir[NGPIO-1:0]), From 6ee5290662a25ca6fa6fa2c63072039cd5feafde Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Fri, 27 May 2016 23:37:40 +0200 Subject: [PATCH 16/18] spi: fpga: Update timing constraints Estimated values, seems close to HW limits though. TX just barely misses 100 MHz timing. Signed-off-by: Ola Jeppsson --- src/spi/fpga/axi_spi_timing.xdc | 36 +++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/spi/fpga/axi_spi_timing.xdc b/src/spi/fpga/axi_spi_timing.xdc index fce0ff68..1299badf 100644 --- a/src/spi/fpga/axi_spi_timing.xdc +++ b/src/spi/fpga/axi_spi_timing.xdc @@ -1,4 +1,32 @@ -# SPI slave clock -create_clock -name spi_s_sclk -period 10 [get_ports spi_s_sclk] -# SPI master clock -create_clock -name spi_m_sclk -period 10 [get_ports spi_m_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; m Date: Thu, 19 May 2016 18:41:21 +0200 Subject: [PATCH 17/18] spi: parallella_spi: Fix pin directions Signed-off-by: Ola Jeppsson --- src/spi/hdl/parallella_spi.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spi/hdl/parallella_spi.v b/src/spi/hdl/parallella_spi.v index bd342453..20f669ad 100644 --- a/src/spi/hdl/parallella_spi.v +++ b/src/spi/hdl/parallella_spi.v @@ -125,7 +125,7 @@ module parallella_spi(/*AUTOARG*/ assign spi_m_sclk = gpio_out[3]; /* NOTE: 0 = in, 1 = out */ - assign gpio_dir[NGPIO-1:0] = {{(NGPIO-8){1'b0}}, 8'b01001011}; + assign gpio_dir[NGPIO-1:0] = {{(NGPIO-11){1'b0}}, 8'b01001011, 3'b000}; assign constant_zero = 1'b0; assign constant_one = 1'b1; From 838c14929bd69dbb6eceda5e2bf3624377bfebb9 Mon Sep 17 00:00:00 2001 From: Ola Jeppsson Date: Sun, 29 May 2016 20:01:20 +0200 Subject: [PATCH 18/18] spi: spi_master_io: Add 1 cycle grace period between transfers Ensure that SS=1 for at least one SCLK clock cycle between transfers. Fixes race condition where the slave misses the end of transfer signal. Signed-off-by: Ola Jeppsson --- src/spi/hdl/spi_master.v | 6 ++--- src/spi/hdl/spi_master_io.v | 43 +++++++++++++++++++---------------- src/spi/hdl/spi_master_regs.v | 4 ++-- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/spi/hdl/spi_master.v b/src/spi/hdl/spi_master.v index 61d23324..d125ba6a 100644 --- a/src/spi/hdl/spi_master.v +++ b/src/spi/hdl/spi_master.v @@ -51,7 +51,7 @@ module spi_master # ( parameter DEPTH = 32, // fifo depth wire rx_access; // From spi_master_io of spi_master_io.v wire [63:0] rx_data; // From spi_master_io of spi_master_io.v wire spi_en; // From spi_master_regs of spi_master_regs.v - wire [1:0] spi_state; // From spi_master_io of spi_master_io.v + wire [2:0] spi_state; // From spi_master_io of spi_master_io.v // End of automatics //##################################################### @@ -76,7 +76,7 @@ module spi_master # ( parameter DEPTH = 32, // fifo depth .hw_en (hw_en), .rx_data (rx_data[63:0]), .rx_access (rx_access), - .spi_state (spi_state[1:0]), + .spi_state (spi_state[2:0]), .fifo_prog_full (fifo_prog_full), .fifo_wait (fifo_wait), .access_in (access_in), @@ -118,7 +118,7 @@ module spi_master # ( parameter DEPTH = 32, // fifo depth spi_master_io spi_master_io (/*AUTOINST*/ // Outputs - .spi_state (spi_state[1:0]), + .spi_state (spi_state[2:0]), .fifo_read (fifo_read), .rx_data (rx_data[63:0]), .rx_access (rx_access), diff --git a/src/spi/hdl/spi_master_io.v b/src/spi/hdl/spi_master_io.v index 299822f5..56e7f6d9 100644 --- a/src/spi/hdl/spi_master_io.v +++ b/src/spi/hdl/spi_master_io.v @@ -13,7 +13,7 @@ module spi_master_io input cpha, // cpha input lsbfirst, // send lsbfirst input [7:0] clkdiv_reg, // baudrate - output [1:0] spi_state, // current spi tx state + output [2:0] spi_state, // current spi tx state // data to transmit input [7:0] fifo_dout, // data payload input fifo_empty, // @@ -31,7 +31,7 @@ module spi_master_io //############### //# LOCAL WIRES //############### - reg [1:0] spi_state; + reg [2:0] spi_state; reg fifo_empty_reg; reg load_byte; wire [7:0] data_out; @@ -74,25 +74,28 @@ module spi_master_io //# STATE MACHINE //################################# -`define SPI_IDLE 2'b00 // set ss to 1 -`define SPI_SETUP 2'b01 // setup time -`define SPI_DATA 2'b10 // send data -`define SPI_HOLD 2'b11 // hold time +`define SPI_IDLE 3'b000 // set ss to 1 +`define SPI_SETUP 3'b001 // setup time +`define SPI_DATA 3'b010 // send data +`define SPI_HOLD 3'b011 // hold time +`define SPI_GRACE 3'b100 // grace period always @ (posedge clk or negedge nreset) if(!nreset) - spi_state[1:0] <= `SPI_IDLE; + spi_state[2:0] <= `SPI_IDLE; else - case (spi_state[1:0]) - `SPI_IDLE : - spi_state[1:0] <= fifo_read ? `SPI_SETUP : `SPI_IDLE; + case (spi_state[2:0]) + default : /* SPI_IDLE */ + spi_state[2:0] <= fifo_read ? `SPI_SETUP : `SPI_IDLE; `SPI_SETUP : - spi_state[1:0] <= phase_match ? `SPI_DATA : `SPI_SETUP; - `SPI_DATA : - spi_state[1:0] <= data_done ? `SPI_HOLD : `SPI_DATA; - `SPI_HOLD : - spi_state[1:0] <= phase_match ? `SPI_IDLE : `SPI_HOLD; - endcase // case (spi_state[1:0]) + spi_state[2:0] <= phase_match ? `SPI_DATA : `SPI_SETUP; + `SPI_DATA : + spi_state[2:0] <= data_done ? `SPI_HOLD : `SPI_DATA; + `SPI_HOLD : + spi_state[2:0] <= phase_match ? `SPI_GRACE : `SPI_HOLD; + `SPI_GRACE : + spi_state[2:0] <= phase_match ? `SPI_IDLE : `SPI_GRACE; + endcase // case (spi_state[2:0]) //read fifo on phase match (due to one cycle pipeline latency assign fifo_read = ~fifo_empty & ~spi_wait & phase_match; @@ -103,7 +106,7 @@ module spi_master_io // In CPOL=0 CPHA=0 (MODE=0) MOSI is output on negative egde. //shift on every clock cycle while in datamode wire tx_shift; - assign tx_shift = phase_match & (spi_state[1:0]==`SPI_DATA); + assign tx_shift = phase_match & (spi_state[2:0]==`SPI_DATA); //load is the result of the fifo_read always @ (posedge clk) @@ -113,13 +116,13 @@ module spi_master_io //# CHIP SELECT //################################# - assign ss = (spi_state[1:0]==`SPI_IDLE); + assign ss = (spi_state[2:0]==`SPI_IDLE) | (spi_state[2:0]==`SPI_GRACE); //################################# //# DRIVE OUTPUT CLOCK //################################# - assign sclk = clkout & (spi_state[1:0]==`SPI_DATA); + assign sclk = clkout & (spi_state[2:0]==`SPI_DATA); //################################# //# TX SHIFT REGISTER @@ -155,7 +158,7 @@ module spi_master_io // In CPOL=0 CPHA=0 (MODE=0) MISO is sampled on positive egde. wire rx_shift; - assign rx_shift = (spi_state[1:0] == `SPI_DATA) & period_match & ~ss; + assign rx_shift = (spi_state[2:0] == `SPI_DATA) & period_match; oh_ser2par #(.PW(64), .SW(1)) ser2par (//output diff --git a/src/spi/hdl/spi_master_regs.v b/src/spi/hdl/spi_master_regs.v index 65dd1ac9..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 //####################################