`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]; generate if (BYTES_TO_INITIALIZE) begin initial $readmemh(INITIAL_CONTENTS_FILE, memory, 0, BYTES_TO_INITIALIZE - 1); end endgenerate 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