diff --git a/Artix-7-HDMI-processing.xpr b/Artix-7-HDMI-processing.xpr
index 316c7a1..6c0ad59 100644
--- a/Artix-7-HDMI-processing.xpr
+++ b/Artix-7-HDMI-processing.xpr
@@ -42,7 +42,7 @@
-
+
@@ -237,6 +237,14 @@
+
+
+
+
+
+
+
+
@@ -258,8 +266,16 @@
+
+
+
+
+
+
+
+
@@ -352,9 +368,14 @@
+
+
+
+
+
-
+
@@ -368,6 +389,7 @@
+
diff --git a/spi_core_tb_behav.wcfg b/spi_core_tb_behav.wcfg
new file mode 100644
index 0000000..96cc0a0
--- /dev/null
+++ b/spi_core_tb_behav.wcfg
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clk
+ clk
+
+
+ rst
+ rst
+
+
+ ncs
+ ncs
+
+
+ sck
+ sck
+ #FFFF00
+ true
+
+
+ sdi
+ sdi
+ #FFFF00
+ true
+
+
+ sdo
+ sdo
+ #FFFF00
+ true
+
+
+ cs_rising
+ cs_rising
+
+
+ cs_falling
+ cs_falling
+
+
+ data_out[15:0]
+ data_out[15:0]
+
+
+ data_out_valid
+ data_out_valid
+
+
+ data_in[15:0]
+ data_in[15:0]
+
+
+ data_in_valid
+ data_in_valid
+
+
+ sim_txbuf[15:0]
+ sim_txbuf[15:0]
+ #FAAFBE
+ true
+
+
+ last_cs
+ last_cs
+
+
+ last_sck[1:0]
+ last_sck[1:0]
+ BINARYRADIX
+
+
+ rx_buf[15:0]
+ rx_buf[15:0]
+
+
+ tx_buf[15:0]
+ tx_buf[15:0]
+
+
+ tx_buf_next[15:0]
+ tx_buf_next[15:0]
+
+
+ sck_rising
+ sck_rising
+
+
+ sck_falling
+ sck_falling
+
+
+ i[31:0]
+ i[31:0]
+
+
+ sim_rxdata[1:4][15:0]
+ sim_rxdata[1:4][15:0]
+
+
+ sim_txdata[1:4][15:0]
+ sim_txdata[1:4][15:0]
+
+
+ testcase[31:0]
+ testcase[31:0]
+
+
diff --git a/src/spi_core.v b/src/spi_core.v
index 1f4b9a1..bf828ab 100644
--- a/src/spi_core.v
+++ b/src/spi_core.v
@@ -2,124 +2,87 @@
module spi_core(
input clk, rst,
- input sck, sdi, sdo, ncs,
+ input sck, sdi, ncs,
+ output reg sdo,
output reg cs_rising,
output reg cs_falling,
- output reg data[15:0],
- output reg data_valid
+ output reg [WORDSIZE-1:0] data_out,
+ output reg data_out_valid,
+ input [WORDSIZE-1:0] data_in,
+ input data_in_valid
);
-reg data_release_flag_sysclk;
+parameter WORDSIZE = 16;
+parameter SPI_CPOL = 0;
+parameter SPI_CPHA = 0;
-reg [15:0] rxbuf_sck;
-reg [15:0] data_reg_sck;
-reg data_good_flag_sck;
-always @(posedge sck or posedge ncs) begin
- if (ncs) begin /* asynchronous reset */
- data_reg_sck <= 16'h0001;
- data_good_flag_sck <= 0;
-
- end else begin
- if (data_reg_sck[15]) begin
- rxbuf_sck <= {data_reg_sck[14:0], sdi};
- data_reg_sck <= 16'h0001;
- data_good_flag_sck <= 1;
-
- end else begin
- data_reg_sck <= {data_reg_sck[14:0], sdi};
- end
- end
-end
+/* Receiver */
+
+reg last_cs;
+reg [1:0] last_sck;
+reg [WORDSIZE-1:0] rx_buf;
+reg [WORDSIZE-1:0] tx_buf;
+reg [WORDSIZE-1:0] tx_buf_next;
+
+wire sck_rising = !last_sck[1] && last_sck[0];
+wire sck_falling = last_sck[1] && !last_sck[0];
-reg cs_rising_sysclk;
-reg cs_falling_sysclk;
-reg last_cs_sysclk;
-reg [1:0] data_good_flag_sysclk;
always @(posedge clk) begin
+ last_cs <= ncs;
+ last_sck = {last_sck[0], sck};
+ data_out_valid <= 0;
+
if (rst) begin
- last_cs_sysclk <= cs;
- cs_rising <= 0;
- cs_falling <= 0;
- data_valid <= 0;
- data <= 0;
- data_release_flag_sysclk <= 0;
- data_good_flag_sysclk <= 0;
-
- end else begin
- data_good_flag_sysclk <= {data-good_flag_sysclk[0], data_good_flag_sck};
+ rx_buf[WORDSIZE-1:1] <= 0;
+ rx_buf[0] <= 1;
+ tx_buf <= 0;
+ tx_buf_next <= 0;
+ sdo <= 0;
+ data_out <= 0;
+ data_out_valid <= 0;
- if (last_cs_sysclk = 0 && cs == 1) begin
- cs_rising <= 1;
- cs_falling <= 0;
- end else begin if (last_cs_sysclk = 1 && cs == 0) begin
- cs_rising <= 0;
+ end else begin
+ if (last_cs && !ncs) begin /* cs falling, device asserted */
cs_falling <= 1;
+ cs_rising <= 0;
+ sdo <= tx_buf_next[WORDSIZE-1];
+ tx_buf <= {tx_buf_next[WORDSIZE-2:0], 1'b0};
+ tx_buf_next <= 0;
+
+ end else if (!last_cs && ncs) begin /* cs rising, device de-asserted */
+ cs_falling <= 0;
+ cs_rising <= 1;
+
+ end else begin /* cs unchanged */
+ cs_falling <= 0;
+ cs_rising <= 0;
end
- if (!last_cs_sysclk && data_good_flag_sysclk[0] && data_good_flag_sysclk[1]) begin
- data <= rxbuf_sck;
- data_release_flag_sysclk <= 1;
+ if(!ncs) begin
+ if (((SPI_CPOL == SPI_CPHA) && sck_rising) || ((SPI_CPOL != SPI_CPHA) && sck_falling)) begin /* sampling edge */
+ if (rx_buf[WORDSIZE-1]) begin
+ data_out <= {rx_buf[WORDSIZE-2:0], sdi};
+ data_out_valid <= 1;
+ rx_buf[WORDSIZE-1:1] <= 0;
+ rx_buf[0] <= 1;
+ tx_buf <= tx_buf_next;
+ tx_buf_next <= 0;
+
+ end else begin
+ rx_buf <= {rx_buf[WORDSIZE-2:0], sdi};
+ end
+
+ end else if (((SPI_CPOL == SPI_CPHA) && sck_falling) || ((SPI_CPOL != SPI_CPHA) && sck_rising)) begin /* driving edge */
+ sdo <= tx_buf[WORDSIZE-1];
+ tx_buf <= {tx_buf[WORDSIZE-2:0], 1'b0};
+ end
+ end
+
+ if (data_in_valid) begin
+ tx_buf_next <= data_in;
end
end
end
endmodule
-
-module cdc_reg (
- input in_clk, in_rst,
- input [WORDSIZE-1:0] in_data,
- input in_data_valid,
-
- input out_clk, out_rst,
- output reg [WORDSIZE-1:0] out_data,
- output reg out_data_valid,
-);
-
-parameter WORDSIZE = 16;
-
-reg [2:0] wr_flags_in;
-reg [WORDSIZE-1:0] reg_in [0:2];
-always @(posedge in_clk, posedge in_rst) begin
- if (in_rst) begin
- wr_flags_in <= 3'b000;
- regs_in[0] <= 0;
- regs_in[1] <= 0;
- regs_in[2] <= 0;
-
- end else begin
- case (regs_in)
- 3'b001: begin regs_in[1] <= in_data; wr_flags_in <= 3'b010; end
- 3'b010: begin regs_in[2] <= in_data; wr_flags_in <= 3'b100; end
- 3'b100, 3'b000: begin regs_in[0] <= in_data; wr_flags_in <= 3'b001; end
- endcase
- end
-end
-
-reg [2:0] wr_flags_out [0:1];
-always @(posedge out_clk) begin
- if (out_rst) begin
- wr_flags_out[0] <= 3'b000;
- wr_flags_out[1] <= 3'b000;
-
- end else begin
- wr_flags_out[0] <= wr_flags_in;
- wr_flags_out[1] <= wr_flags_out[0];
- out_data_valid <= 0;
-
- if (wr_flags_out[0][0] && !wr_flags_out[1][0]) begin
- out_data <= regs_in[0];
- out_data_valid <= 1;
-
- end else if (wr_flags_out[0][1] && !wr_flags_out[1][1]) begin
- out_data <= regs_in[1];
- out_data_valid <= 1;
-
- end else if (wr_flags_out[0][2] && !wr_flags_out[1][2]) begin
- out_data <= regs_in[2];
- out_data_valid <= 1;
- end
- end
-end
-
-endmodule
\ No newline at end of file
diff --git a/test_bench/spi_core_tb.v b/test_bench/spi_core_tb.v
index e69de29..fff7fa1 100644
--- a/test_bench/spi_core_tb.v
+++ b/test_bench/spi_core_tb.v
@@ -0,0 +1,145 @@
+
+module spi_core_tb();
+
+localparam period = 10;
+parameter WORDSIZE = 16;
+reg clk, rst;
+
+reg sck, sdi, ncs;
+wire sdo;
+
+wire cs_rising, cs_falling;
+
+wire [WORDSIZE-1:0] data_out;
+wire data_out_valid;
+
+reg [WORDSIZE-1:0] data_in;
+reg data_in_valid;
+
+initial begin
+ clk = 0;
+ /* rst set below */
+ sck = 0;
+ sdi = 0;
+ ncs = 1;
+ data_in = 0;
+ data_in_valid = 0;
+ forever #period clk = ~clk;
+end
+
+integer i;
+integer j;
+integer k;
+integer testcase;
+reg [WORDSIZE-1:0] sim_rxdata [1:4];
+reg [WORDSIZE-1:0] sim_txdata [1:4];
+reg [WORDSIZE-1:0] sim_txbuf;
+initial begin
+ sim_rxdata[1] = 16'h523a;
+ sim_rxdata[2] = 16'hbeef;
+ sim_rxdata[3] = 16'h7721;
+ sim_rxdata[4] = 16'h0108;
+
+ sim_txdata[1] = 16'h1234;
+ sim_txdata[2] = 16'h5678;
+ sim_txdata[3] = 16'h9abc;
+ sim_txdata[4] = 16'hdef9;
+
+ for (j=1; j<=4; j=j+1) begin
+ $display("TC-SIMPLE-%d: rx/tx %d word", j, j);
+ testcase = j;
+
+ rst = 1;
+ repeat(2) @(posedge clk);
+ rst = 0;
+ @(posedge clk);
+
+ data_in = sim_txdata[1];
+ data_in_valid = 1;
+ @(posedge clk);
+
+ data_in_valid = 0;
+ ncs = 0;
+ @(posedge clk);
+ if (cs_rising || !cs_falling || data_out_valid) $finish;
+
+ for (k=0; k