From cd0c787bcfc89a0a1e14f4404a59cb4697854621 Mon Sep 17 00:00:00 2001 From: Wojciech Kosior Date: Tue, 3 Nov 2020 19:16:12 +0100 Subject: add spi wishbone slave with a simplified flash memory chip model and a test bench --- design/spi_slave.v | 262 ++++++++++++++++++++++++++++++++++++++++ models/flash_memory.v | 206 +++++++++++++++++++++++++++++++ tests/spi_slave/Makefile | 9 ++ tests/spi_slave/operations.memv | 62 ++++++++++ tests/spi_slave/rom.mem | 258 +++++++++++++++++++++++++++++++++++++++ tests/spi_slave/test.v | 141 +++++++++++++++++++++ 6 files changed, 938 insertions(+) create mode 100644 design/spi_slave.v create mode 100644 models/flash_memory.v create mode 100644 tests/spi_slave/Makefile create mode 100644 tests/spi_slave/operations.memv create mode 100644 tests/spi_slave/rom.mem create mode 100644 tests/spi_slave/test.v diff --git a/design/spi_slave.v b/design/spi_slave.v new file mode 100644 index 0000000..a53d9d2 --- /dev/null +++ b/design/spi_slave.v @@ -0,0 +1,262 @@ +`default_nettype none + +`define ADDR_WIDTH ($clog2(MEMORY_BLOCKS + 1) + 8) + +module spi_slave + #( + parameter MEMORY_BLOCKS = 1 /* 1 block stores 256 16-bit words */ + ) + ( + /* Interface to flash memory chip */ + output reg sdo, + input wire sdi, + output wire sck, + output reg ss_n, + + /* Wishbone slave interface */ + output wire ACK_O, + input wire [`ADDR_WIDTH - 1:0] ADR_I, + input wire CLK_I, + input wire [15:0] DAT_I, + output wire [15:0] DAT_O, + input wire RST_I, + input wire STB_I, + input wire WE_I, + output wire STALL_O + ); + + parameter MEMORY_IDX_WIDTH = $clog2(MEMORY_BLOCKS) + 8; + parameter MEMORY_MAX_ADDR = MEMORY_BLOCKS * 256 - 1; + parameter BIT_COUNT_WIDTH = MEMORY_IDX_WIDTH + 4; + + reg [15:0] memory [MEMORY_MAX_ADDR:0]; + + reg [15:0] data_read_from_memory; + reg [15:0] data_read_from_regs; + wire [15:0] data_to_write_to_memory; + + reg [`ADDR_WIDTH - 1:0] ADR_I_latched; + reg [15:0] DAT_I_latched; + reg [1:0] wb_read_memory; + reg wb_write_memory; + reg wb_read_regs; + reg wb_write_regs; + + /* + * The wires below are only relevant if regs are being accessed, i.e. + * ADR_I_latched > MEMORY_MAX_ADDR. + */ + wire reg_bytes_to_output; + wire reg_bytes_to_receive; + wire reg_operating; + + assign reg_bytes_to_output = ADR_I_latched[1:0] == 2'b00; + assign reg_bytes_to_receive = ADR_I_latched[1:0] == 2'b01; + assign reg_operating = ADR_I_latched[1] == 1'b1; + + reg ack; + + reg [2:0] operating; + + wire [1:0] start_operating; + assign start_operating = {operating[2:1] == 2'b01, operating[1:0] == 2'b01}; + + reg [15:0] out_data; // sdo data + reg [15:0] in_data; // sdi data + + reg bytes_to_output_odd; + reg bytes_to_receive_odd; + reg [BIT_COUNT_WIDTH - 1:0] bits_to_output; + reg [BIT_COUNT_WIDTH - 1:0] bits_to_receive; + reg [MEMORY_IDX_WIDTH - 1:0] memory_idx; + + reg [1:0] spi_read_memory; + reg spi_write_memory; + + wire spi_write_1byte; + wire initial_spi_read_memory; + assign spi_write_1byte = bits_to_receive[3] == 0 && bytes_to_receive_odd; + assign initial_spi_read_memory = start_operating[0]; + + wire [MEMORY_IDX_WIDTH - 1:0] memory_read_idx; + wire [MEMORY_IDX_WIDTH - 1:0] memory_write_idx; + + assign memory_read_idx = initial_spi_read_memory ? 0 : + spi_read_memory[0] ? memory_idx : + ADR_I_latched; + + assign memory_write_idx = spi_write_memory ? memory_idx : + ADR_I_latched; + + assign data_to_write_to_memory = spi_write_memory ? + (spi_write_1byte ? + {8'hXX, in_data[7:0]} : + {in_data[7:0], in_data[15:8]}) : + DAT_I_latched; + + wire wb_reg_can_be_written; + assign wb_reg_can_be_written = !operating[0]; + + wire wb_mread_completes; + wire wb_rread_completes; + wire wb_mwrite_completes; + wire wb_rwrite_completes; + + assign wb_mread_completes = !(spi_read_memory[0] || initial_spi_read_memory) && + wb_read_memory[0]; + + assign wb_rread_completes = wb_read_regs; /* can always read immediately */ + + assign wb_mwrite_completes = !spi_write_memory && wb_write_memory; + + assign wb_rwrite_completes = wb_reg_can_be_written && wb_write_regs; + + wire wb_operation_accepted; + wire wb_operation_pending; + wire wb_operation_completes; + + assign wb_operation_accepted = !STALL_O && STB_I; + assign wb_operation_pending = wb_read_memory || wb_read_regs || + wb_write_memory || wb_write_regs; + assign wb_operation_completes = wb_mread_completes || wb_rread_completes || + wb_mwrite_completes || wb_rwrite_completes; + + assign DAT_O = wb_read_memory[1] ? data_read_from_memory : + data_read_from_regs; + assign ACK_O = ack; + assign STALL_O = wb_operation_pending && !wb_operation_completes; + + parameter state_sending = 0; + parameter state_receiving = 1; + reg state; + + assign sck = CLK_I; + + always @ (posedge CLK_I) begin + operating[2:1] <= operating[1:0]; + + data_read_from_memory <= memory[memory_read_idx]; + + if (spi_write_memory || wb_write_memory) + memory[memory_write_idx] <= data_to_write_to_memory; + + spi_read_memory[1] <= spi_read_memory[0] || initial_spi_read_memory; + + if (operating[0]) begin + spi_read_memory[0] <= bits_to_output[BIT_COUNT_WIDTH - 1:4] != 0 && + bits_to_output[3:0] == + (bytes_to_output_odd ? 11 : 3); + + spi_write_memory <= bits_to_receive == 1 || + bits_to_receive[3:0] == + (bytes_to_receive_odd ? 9 : 1); + end else begin + spi_read_memory[0] <= 0; + spi_write_memory <= 0; + end + + out_data <= spi_read_memory[1] ? + {data_read_from_memory[7:0], data_read_from_memory[15:8]} : + {out_data[14:0], 1'bx}; + + in_data <= {in_data[14:0], sdi}; + + wb_read_memory[1] <= wb_read_memory[0]; + + if (reg_bytes_to_output) + data_read_from_regs <= bits_to_output[BIT_COUNT_WIDTH - 1:3]; + else if (reg_bytes_to_receive) + data_read_from_regs <= bits_to_receive[BIT_COUNT_WIDTH - 1:3]; + else if (reg_operating) + data_read_from_regs <= {16{operating[0]}}; + else + data_read_from_regs <= 16'hXXXX; + + if (wb_write_regs && wb_reg_can_be_written) begin + if (reg_bytes_to_output) begin + bits_to_output <= DAT_I_latched << 3; + bytes_to_output_odd <= DAT_I_latched[0]; + end + if (reg_bytes_to_receive) begin + bits_to_receive <= (DAT_I_latched << 3); + bytes_to_receive_odd <= DAT_I_latched[0]; + end + if (reg_operating) + operating[0] <= 1; /* might be overwritten below */ + end + + if (RST_I) begin + wb_read_memory[0] <= 0; + wb_write_memory <= 0; + wb_read_regs <= 0; + wb_write_regs <= 0; + + operating[0] <= 0; + + bits_to_receive <= 16'hXXXX; + bits_to_output <= 16'hXXXX;//{{(BIT_COUNT_WIDTH - 4){1'bx}}, 4'h0}; + bytes_to_output_odd <= 1'bx; + bytes_to_receive_odd <= 1'bx; + + ack <= 0; + end else begin // if (RST_I) + if (wb_operation_accepted) begin + ADR_I_latched <= ADR_I; + DAT_I_latched <= DAT_I; + wb_read_memory[0] <= !WE_I && ADR_I <= MEMORY_MAX_ADDR; + wb_write_memory <= WE_I && ADR_I <= MEMORY_MAX_ADDR; + wb_read_regs <= !WE_I && ADR_I > MEMORY_MAX_ADDR; + wb_write_regs <= WE_I && ADR_I > MEMORY_MAX_ADDR; + end else if (wb_operation_completes) begin + wb_read_memory[0] <= 0; + wb_write_memory <= 0; + wb_read_regs <= 0; + wb_write_regs <= 0; + end + + ack <= wb_operation_completes; + end // else: !if(RST_I) + + if (start_operating[1]) begin + memory_idx <= 1; + state <= state_sending; + end + + if (operating == 3'b111) begin + if (state == state_sending) begin + bits_to_output <= bits_to_output - 1; + + if (spi_read_memory[0]) + memory_idx <= memory_idx + 1; + + if (bits_to_output - 1 == 0) begin + state <= state_receiving; + memory_idx <= 0; + + if (bits_to_receive == 0) + operating[0] <= 0; + end + end else if (state == state_receiving) begin + bits_to_receive <= bits_to_receive - 1; + + if (spi_write_memory) + memory_idx <= memory_idx + 1; + + if (bits_to_receive - 1 == 0) + operating[0] <= 0; + end + end // if (operating[2]) + end // always @ (posedge CLK_I) + + always @ (negedge CLK_I) begin + sdo <= out_data[15]; + ss_n <= !(operating == 3'b111); + end + +`ifdef SIMULATION + initial begin + operating[0] <= 0; + ss_n <= 1; + end +`endif +endmodule // spi_slave diff --git a/models/flash_memory.v b/models/flash_memory.v new file mode 100644 index 0000000..3b6c659 --- /dev/null +++ b/models/flash_memory.v @@ -0,0 +1,206 @@ +`default_nettype none +`timescale 1ns/1ns + +`include "messages.vh" + +`ifndef SIMULATION + `error_SIMULATION_not_defined +; /* Cause syntax error */ +`endif + +module W25Q16BV_flash + #( + parameter BYTES_TO_INITIALIZE = 0, + parameter INITIAL_CONTENTS_FILE = "some_file.mem" + ) + ( + /* wires we're not using are omitted */ + input wire sdo, + output wire sdi, + input wire sck, + input wire ss_n + ); + + reg outputting; + initial + outputting <= 0; + reg outputted_bit; + assign sdi = (outputting && !ss_n) ? outputted_bit : 1'bz; + + reg powered_up; + initial + powered_up <= 0; + + reg powering_up_in_progress; + initial + powering_up_in_progress <= 0; + + parameter power_up_wait_time = 3000; /* ns */ + integer power_up_time; + + parameter idle = 0; + parameter error = 1; + parameter receiving_instruction = 2; + parameter releasing_power_down = 3; + parameter receiving_fast_read_address = 4; + parameter receiving_fast_read_dummy_byte = 5; + parameter responding_fast_read = 6; + integer state; + initial + state <= idle; + + parameter release_power_down_instruction = 8'hAB; + parameter fast_read_instruction = 8'h0B; + + reg [7:0] instruction; + integer instruction_bits_received; + + reg [23:0] address; + integer address_bits_received; + reg [2:0] bit_in_byte; + + integer dummy_bits_received; + + parameter memory_size = 1024 * 1024 * 2; /* 2 megabytes */ + reg [7:0] memory [memory_size - 1 : 0]; + initial + $readmemh(INITIAL_CONTENTS_FILE, memory, 0, BYTES_TO_INITIALIZE - 1); + + always @ (posedge sck) begin + if (!powered_up && power_up_time + power_up_wait_time < $time) begin + powered_up <= 1; + if (state == releasing_power_down) + state = idle; + end + + case (state) + idle : begin + if (!ss_n) begin + state <= receiving_instruction; + instruction_bits_received <= 1; + instruction[7] <= sdo; + end + end + error : begin + if (ss_n) begin + state <= idle; + end + end + receiving_instruction : begin + if (ss_n) begin + state <= idle; + `MSG(("SPI: error: operation aborted after only %0d instruction bits received", + instruction_bits_received)); + end else begin + instruction[7 - instruction_bits_received] <= sdo; + instruction_bits_received <= instruction_bits_received + 1; + + if (instruction_bits_received + 1 == 8) begin + if (!powered_up && ({instruction[7:1], sdo} != + release_power_down_instruction)) begin + state <= error; + `MSG(("SPI: error: attempted instruction 0x%x while in power down mode", + {instruction[7:1], sdo})); + end else begin + case ({instruction[7:1], sdo}) + release_power_down_instruction : begin + state <= releasing_power_down; + power_up_time <= $time; + `DBG(("SPI: release power down issued")); + end + fast_read_instruction : begin + state <= receiving_fast_read_address; + address_bits_received <= 0; + `DBG(("SPI: fast read issued")); + end + default : begin + state <= error; + `MSG(("SPI: error: unknown instruction: 0x%x", + {instruction[7:1], sdo})); + end + endcase // case ({instruction[7:1], sdo}) + end // else: !if(!powered_up && ({instruction[7:1], sdo} !=... + end // if (instruction_bits_received + 1 == 8) + end // else: !if(ss_n) + end // case: receiving_instruction + releasing_power_down : begin + if (!ss_n) begin + state <= receiving_instruction; + instruction_bits_received <= 1; + instruction[7] <= sdo; + + if (power_up_time + power_up_wait_time >= $time) begin + `MSG(("SPI: error: release power down interrupted %0d ns before finishing", + power_up_time + power_up_wait_time - $time)); + end + end // if (!ss_n) + end // case: releasing_power_down + receiving_fast_read_address : begin + if (ss_n) begin + state <= idle; + `MSG(("SPI: error: fast read instruction aborted after %0d bits of address were sent", + address_bits_received)); + end else begin + address[23 - address_bits_received] <= sdo; + address_bits_received <= address_bits_received + 1; + + if (address_bits_received + 1 == 24) begin + state <= receiving_fast_read_dummy_byte; + dummy_bits_received <= 0; + end + end + end + receiving_fast_read_dummy_byte : begin + if (ss_n) begin + state <= idle; + `MSG(("SPI: error: fast read instruction aborted after %0d bits of dummy byte were sent", + dummy_bits_received)); + end else begin + dummy_bits_received <= dummy_bits_received + 1; + + if (dummy_bits_received + 1 == 8) begin + bit_in_byte <= 7; + + if (address >= memory_size) begin + state <= error; + `MSG(("SPI: error: memory address too high (0x%x)", + address)); + end else begin + state <= responding_fast_read; + end + end + end // else: !if(ss_n) + end // case: receiving_fast_read_dummy_byte + responding_fast_read : begin + if (ss_n) begin + state <= idle; + end else begin + bit_in_byte <= bit_in_byte - 1; + + if (bit_in_byte == 0) begin + address <= address + 1; + + if (address + 1 >= memory_size) begin + state <= error; + `MSG(("SPI: error: memory address too high (0x%x)", + address)); + end + end + end // else: !if(ss_n) + end // case: responding_fast_read + endcase // case (state) + end // always @ (posedge sck) + + always @ (negedge sck) begin + if (ss_n) begin + outputting <= 0; + end else if (state == responding_fast_read) begin + outputting <= 1; + outputted_bit <= memory[address][bit_in_byte]; + end else if (state == error) begin + outputted_bit <= 1'bx; + end else begin + outputting <= 0; + end + end // always @ (negedge sck) +endmodule // W25Q16BV_flash diff --git a/tests/spi_slave/Makefile b/tests/spi_slave/Makefile new file mode 100644 index 0000000..8a8d3e8 --- /dev/null +++ b/tests/spi_slave/Makefile @@ -0,0 +1,9 @@ +DEPENDS = operations.mem master.v spi_slave.v flash_memory.v messages.vh rom.mem + +IVFLAGS = \ + -DMASTER_OPERATIONS_COUNT=$(call FILE_LINES,operations.mem) \ + -DROM_WORDS_COUNT=$(call FILE_LINES,rom.mem) + +TOP = spi_test + +include ../../Makefile.test diff --git a/tests/spi_slave/operations.memv b/tests/spi_slave/operations.memv new file mode 100644 index 0000000..084353b --- /dev/null +++ b/tests/spi_slave/operations.memv @@ -0,0 +1,62 @@ +`include "macroasm.vh" // look into macroasm.vh for more info + +// power up flash ship +`WRITE (00100, 0001) // set bytes_to_output to 1 +`WRITE (00101, 0000) // set bytes_to_receive to 0 + +`WRITE (00000, 00AB) // release power-down spi command + +`WRITE (00102, 1111) // start spi operation + + +// reading this reg during operation should yield 1's +`READ (00102, FFFF) + + +// the completions of first write after spi operation has been started +// will be delayed until the operations has finished. This is of no concern +// here, since the master will just gently wait for ACK from slave. + + +// read contents at addresses h3A through h4A +`WRITE (00101, 0010) // set bytes_to_receive to 16 (h10) +`READ (00102, 0000) // see, that operation indeed finished + +`WRITE (00000, 000B) // fast read spi command + 8 high address bits +`WRITE (00001, 3A00) // 16 low address bits +`WRITE (00002, 0000) // dummy byte + +`WRITE (00100, 0005) // set bytes_to_output to 5 + +// Cause delay b4 starting operation - chip's power-up takes 3000ns +`DESELECT +`DESELECT +`WAIT +`DESELECT +`WAIT +`DESELECT + +`WRITE (00102, 1111) // start spi operation (bits written to h102 don't matter) + +`WRITE (00100, 0000) // force wait for operation completion + +// check the data we've just read +`READ (00000, 00CB) +`READ (00001, 00D2) +`READ (00002, 00D9) +`READ (00003, 00E0) +`READ (00004, 00E7) +`READ (00005, 00EE) +`READ (00006, 00F5) +`READ (00007, 00FC) + +// how about reading a single byte? +`WRITE (00100, 0005) // set bytes_to_output to 5 +`WRITE (00101, 0001) // set bytes_to_receive to 1 +`WRITE (00000, 000B) // fast read spi command + 8 high address bits +`WRITE (00001, E400) // 16 low address bits +//`WRITE (00002, 0000) // dummy byte +`WRITE (00102, BEEF) // start spi operation +`WRITE (00100, 0000) // force wait for operation completion + +`READ (00000, xx1E) // check the byte we've just read diff --git a/tests/spi_slave/rom.mem b/tests/spi_slave/rom.mem new file mode 100644 index 0000000..06fff24 --- /dev/null +++ b/tests/spi_slave/rom.mem @@ -0,0 +1,258 @@ +// numbers 0, 7, 2*7, 3*7, ..., 256*7 in hex (2 LE bytes for each number) +0 0 +7 0 +e 0 +15 0 +1c 0 +23 0 +2a 0 +31 0 +38 0 +3f 0 +46 0 +4d 0 +54 0 +5b 0 +62 0 +69 0 +70 0 +77 0 +7e 0 +85 0 +8c 0 +93 0 +9a 0 +a1 0 +a8 0 +af 0 +b6 0 +bd 0 +c4 0 +cb 0 +d2 0 +d9 0 +e0 0 +e7 0 +ee 0 +f5 0 +fc 0 +3 1 +a 1 +11 1 +18 1 +1f 1 +26 1 +2d 1 +34 1 +3b 1 +42 1 +49 1 +50 1 +57 1 +5e 1 +65 1 +6c 1 +73 1 +7a 1 +81 1 +88 1 +8f 1 +96 1 +9d 1 +a4 1 +ab 1 +b2 1 +b9 1 +c0 1 +c7 1 +ce 1 +d5 1 +dc 1 +e3 1 +ea 1 +f1 1 +f8 1 +ff 1 +6 2 +d 2 +14 2 +1b 2 +22 2 +29 2 +30 2 +37 2 +3e 2 +45 2 +4c 2 +53 2 +5a 2 +61 2 +68 2 +6f 2 +76 2 +7d 2 +84 2 +8b 2 +92 2 +99 2 +a0 2 +a7 2 +ae 2 +b5 2 +bc 2 +c3 2 +ca 2 +d1 2 +d8 2 +df 2 +e6 2 +ed 2 +f4 2 +fb 2 +2 3 +9 3 +10 3 +17 3 +1e 3 +25 3 +2c 3 +33 3 +3a 3 +41 3 +48 3 +4f 3 +56 3 +5d 3 +64 3 +6b 3 +72 3 +79 3 +80 3 +87 3 +8e 3 +95 3 +9c 3 +a3 3 +aa 3 +b1 3 +b8 3 +bf 3 +c6 3 +cd 3 +d4 3 +db 3 +e2 3 +e9 3 +f0 3 +f7 3 +fe 3 +5 4 +c 4 +13 4 +1a 4 +21 4 +28 4 +2f 4 +36 4 +3d 4 +44 4 +4b 4 +52 4 +59 4 +60 4 +67 4 +6e 4 +75 4 +7c 4 +83 4 +8a 4 +91 4 +98 4 +9f 4 +a6 4 +ad 4 +b4 4 +bb 4 +c2 4 +c9 4 +d0 4 +d7 4 +de 4 +e5 4 +ec 4 +f3 4 +fa 4 +1 5 +8 5 +f 5 +16 5 +1d 5 +24 5 +2b 5 +32 5 +39 5 +40 5 +47 5 +4e 5 +55 5 +5c 5 +63 5 +6a 5 +71 5 +78 5 +7f 5 +86 5 +8d 5 +94 5 +9b 5 +a2 5 +a9 5 +b0 5 +b7 5 +be 5 +c5 5 +cc 5 +d3 5 +da 5 +e1 5 +e8 5 +ef 5 +f6 5 +fd 5 +4 6 +b 6 +12 6 +19 6 +20 6 +27 6 +2e 6 +35 6 +3c 6 +43 6 +4a 6 +51 6 +58 6 +5f 6 +66 6 +6d 6 +74 6 +7b 6 +82 6 +89 6 +90 6 +97 6 +9e 6 +a5 6 +ac 6 +b3 6 +ba 6 +c1 6 +c8 6 +cf 6 +d6 6 +dd 6 +e4 6 +eb 6 +f2 6 +f9 6 +0 7 diff --git a/tests/spi_slave/test.v b/tests/spi_slave/test.v new file mode 100644 index 0000000..f489fee --- /dev/null +++ b/tests/spi_slave/test.v @@ -0,0 +1,141 @@ +`default_nettype none +`timescale 1ns/1ns + +`include "messages.vh" + +`ifndef MASTER_OPERATIONS_COUNT + `error_MASTER_OPERATIONS_COUNT_must_be_defined +; /* Cause syntax error */ +`endif + +`ifndef ROM_WORDS_COUNT + `error_ROM_WORDS_COUNT_must_be_defined +; /* Cause syntax error */ +`endif + +`ifndef SIMULATION + `error_SIMULATION_not_defined +; /* Cause syntax error */ +`endif + +module spi_test(); + wire M_ACK_I; + wire M_CLK_I; + wire [19:0] M_ADR_O; + wire [15:0] M_DAT_I; + wire [15:0] M_DAT_O; + wire M_SEL_O; /* Ignored, assumed always high */ + wire M_RST_I; + wire M_STB_O; + wire M_CYC_O; + wire M_WE_O; + wire M_STALL_I; + + wire S_ACK_O; + wire S_CLK_I; + wire [8:0] S_ADR_I; + wire [15:0] S_DAT_I; + wire [15:0] S_DAT_O; + wire S_RST_I; + wire S_STB_I; + wire S_WE_I; + wire S_STALL_O; + + /* Non-wishbone */ + wire sdo; + wire sdi; + wire sck; + wire ss_n; + + wire M_finished; + + master_model + #( + .MASTER_NR(0), + .OPERATIONS_FILE("operations.mem"), + .OPERATIONS_COUNT(`MASTER_OPERATIONS_COUNT) + ) master + ( + .ACK_I(M_ACK_I), + .CLK_I(M_CLK_I), + .ADR_O(M_ADR_O), + .DAT_I(M_DAT_I), + .DAT_O(M_DAT_O), + .SEL_O(M_SEL_O), + .RST_I(M_RST_I), + .STB_O(M_STB_O), + .CYC_O(M_CYC_O), + .WE_O(M_WE_O), + .STALL_I(M_STALL_I), + + .finished(M_finished) + ); + + spi_slave slave + ( + .ACK_O(S_ACK_O), + .CLK_I(S_CLK_I), + .ADR_I(S_ADR_I), + .DAT_I(S_DAT_I), + .DAT_O(S_DAT_O), + .RST_I(S_RST_I), + .STB_I(S_STB_I), + .WE_I(S_WE_I), + .STALL_O(S_STALL_O), + + .sdo(sdo), + .sdi(sdi), + .sck(sck), + .ss_n(ss_n) + ); + + W25Q16BV_flash + #( + .BYTES_TO_INITIALIZE(`ROM_WORDS_COUNT * 2), + .INITIAL_CONTENTS_FILE("rom.mem") + ) flash + ( + .sdo(sdo), + .sdi(sdi), + .sck(sck), + .ss_n(ss_n) + ); + + reg CLK; + reg RST; + + assign M_ACK_I = S_ACK_O; + assign M_CLK_I = CLK; + assign M_DAT_I = S_DAT_O; + assign M_RST_I = RST; + assign M_STALL_I = S_STALL_O; + + assign S_CLK_I = CLK; + assign S_ADR_I = M_ADR_O[8:0]; /* Ignore 11 topmost bits */ + assign S_DAT_I = M_DAT_O; + assign S_RST_I = RST; + assign S_STB_I = M_STB_O && M_CYC_O; + assign S_WE_I = M_WE_O; + + integer i; + + initial begin + CLK <= 0; + RST <= 1; + + for (i = 0; i < 600; i++) begin + #100; /* longer wait time so that power-up requires less idle ticks */ + + CLK <= ~CLK; + + if (CLK) + RST <= 0; + + if (M_finished) + $finish; + end + + $display("error: master hasn't finished its operations in 300 ticks"); + $finish; + end +endmodule // spi_test -- cgit v1.2.3