diff options
-rw-r--r-- | src/example.v | 488 |
1 files changed, 432 insertions, 56 deletions
diff --git a/src/example.v b/src/example.v index 63ad7ed..c588dba 100644 --- a/src/example.v +++ b/src/example.v @@ -660,50 +660,365 @@ module on_button_write(input wire clock_50mhz, end // always @ (posedge clock_50mhz) endmodule -module dumb_write(input wire clock_50mhz, - input wire reset, - - input wire can_write, - output wire [15:0] write_data, +module winbond_spi(input wire clock_50mhz, + input wire reset, + + input wire operate, + input wire [31:0] send_data, + input wire [2:0] bytes_to_send, + input wire [14:0] bytes_to_receive, + + output reg byte_ready, + output reg [7:0] received_data, + output reg operation_finished, + + output reg sdo, + input wire sdi, + output wire sck, + output reg ss_n + ); + reg working; + reg operating; - output wire want_to_write, - output wire [17:0] write_addr, + reg [31:0] sdo_data; + reg [5:0] bits_to_output; - input wire [17:0] written_memory_base, - input wire start_operating - ); - reg [9:0] write_idx; - /* To each word we'll be writing its offset from written_memory_base */ - assign write_data = write_idx; - assign write_addr = written_memory_base + write_idx; + parameter sending = 0; + parameter receiving = 1; + reg state; - parameter max_idx = 599; - reg operating; - assign want_to_write = operating; + reg [6:0] sdi_data; + reg [17:0] bits_to_receive; + reg [3:0] bits_received; + reg send_only_operation; - reg [1:0] write_state; + assign sck = clock_50mhz; always @ (posedge clock_50mhz) begin - if (reset) begin - write_idx <= 10'bxxxxxxxxxx; + if (reset || !operate) begin operating <= 0; + byte_ready <= 0; + operation_finished <= 0; + + bits_to_receive <= 18'hXXXXX; + bits_to_output <= 6'hXX; + sdi_data <= 7'hXX; + sdo_data <= 32'hXXXXXXXX; + received_data <= 8'hXX; + send_only_operation <= 1'bx; + state <= 1'bx; end else begin - if (start_operating && !operating) begin - operating <= 1; - write_state <= 0; - write_idx <= 0; + operating <= 1; + + if (!operating && operate) begin + bits_to_receive <= bytes_to_receive * 8; + bits_to_output <= bytes_to_send * 8; + sdo_data <= send_data; + send_only_operation <= bytes_to_receive == 0; + state <= sending; + byte_ready <= 0; + operation_finished <= 0; + + sdi_data <= 7'hXX; + received_data <= 8'hXX; end - else if (operating) begin - if (can_write) begin - write_idx <= write_idx + 1; - if (write_idx == max_idx) - operating <= 0; + else begin + if (operation_finished) begin + byte_ready <= 0; + + bits_to_receive <= 18'hXXXXX; + bits_to_output <= 6'hXX; + sdi_data <= 7'hXX; + sdo_data <= 32'hXXXXXXXX; + received_data <= 8'hXX; + send_only_operation <= 1'bx; + state <= 1'bx; end + else begin + if (state == sending) begin + byte_ready <= 0; + bits_to_output <= bits_to_output - 1; + sdo_data <= {sdo_data[30:0], 1'bx}; + + if (bits_to_output - 1 == 0) begin + state <= receiving; + if (send_only_operation) + operation_finished <= 1; + end + + sdi_data <= 7'hXX; + received_data <= 8'hXX; + end // if (state == sending) + + if (state == receiving) begin + + bits_to_receive <= bits_to_receive - 1; + sdi_data <= {sdi_data[5:0], sdi}; + + if (bits_to_receive % 8 - 1 == 0) begin + byte_ready <= 1; + received_data <= {sdi_data[6:0], sdi}; + end + else begin + byte_ready <= 0; + received_data <= 8'hXX; + end + + if (bits_to_receive - 1 == 0) + operation_finished <= 1; + + bits_to_output <= 6'hXX; + sdo_data <= 32'hXXXXXXXX; + end // if (state == receiving) + end // else: !if(operation_finished) + end // else: !if(!operating && operate) + end // else: !if(reset || !operate) + end // always @ (posedge clock_50mhz) + + always @ (negedge clock_50mhz) begin + sdo <= sdo_data[31]; + + if (!operating) begin + ss_n <= 1; + end + else begin + if (operation_finished) + ss_n <= 1; + else + ss_n <= 0; + end + end // always @ (negedge clock_50mhz) +endmodule // winbond_spi + +module spi_chip_powerup(input wire clock_50mhz, + input wire reset, + + output reg want_spi_operation, + output wire [31:0] spi_send_data, + output wire [2:0] spi_bytes_to_send, + output wire [14:0] spi_bytes_to_receive, + + input wire spi_operation_finished, + + input wire operate, + output reg finished_operating + ); + parameter power_up_instruction = 8'hAB; + + assign spi_send_data = {power_up_instruction, 24'hXXXXXX}; + assign spi_bytes_to_send = 1; + assign spi_bytes_to_receive = 0; + + parameter sending_power_up = 0; + parameter waiting = 1; + reg state; + + parameter freq = 50; /* Mhz */ + parameter powerup_wait_time = 3000; /* ns */ + parameter powerup_wait_ticks = powerup_wait_time * freq / 1000; + reg [7:0] powerup_wait_counter; + + reg operating; + + always @ (posedge clock_50mhz) begin + if (reset || !operate) begin + want_spi_operation <= 0; + finished_operating <= 0; + operating <= 0; + + state <= 1'bx; + powerup_wait_counter <= 8'hXX; + end + else begin + operating <= 1; + + if (!operating && operate) begin + want_spi_operation <= 1; + finished_operating <= 0; + state <= sending_power_up; + + powerup_wait_counter <= 8'hXX; end - end // else: !if(reset) + else begin + if (state == sending_power_up) begin + finished_operating <= 0; + + if (spi_operation_finished) begin + powerup_wait_counter <= powerup_wait_ticks; + state <= waiting; + want_spi_operation <= 0; + end + else begin + want_spi_operation <= 1; + + powerup_wait_counter <= 8'hXX; + end + end // if (state == sending_power_up) + + if (state == waiting) begin + want_spi_operation <= 0; + + if (powerup_wait_counter == 0) begin + finished_operating <= 1; + end + else begin + finished_operating <= 0; + powerup_wait_counter <= powerup_wait_counter - 1; + end + end // if (state == waiting) + end // else: !if(!operating && operate) + end // else: !if(reset || !operate) + end // always @ (posedge clock_50mhz) +endmodule // spi_chip_powerup + +module spi_sram_copy(input wire clock_50mhz, + input wire reset, + + input wire can_write, + output reg [15:0] write_data, + + output wire want_to_write, /* sram memory */ + output wire [17:0] write_addr, + + input wire [17:0] written_memory_base, + + output reg want_spi_operation, + output wire [31:0] spi_send_data, + output wire [2:0] spi_bytes_to_send, + output wire [14:0] spi_bytes_to_receive, + + input wire spi_byte_ready, + input wire [7:0] received_byte, + + input wire [23:0] flash_memory_base, + + input wire operate, + output reg finished_operating + ); + parameter fast_read_instruction = 8'h0B; + + parameter words_to_copy = 600; + + assign spi_bytes_to_send = 5; + + reg [9:0] words_left_to_receive; + assign spi_bytes_to_receive = words_left_to_receive * 2; + + reg [9:0] word_idx; + + assign write_addr = written_memory_base + word_idx; + + wire [23:0] read_addr; + assign read_addr = flash_memory_base + 16 * word_idx; + assign spi_send_data = {fast_read_instruction, read_addr}; + + reg write_word_ready; + assign want_to_write = write_word_ready; + + wire write_happens; + assign write_happens = want_to_write && can_write; + + reg [7:0] high_byte; + reg high_byte_received; + + wire word_received; + assign word_received = high_byte_received && spi_byte_ready; + + /* true if next spi data word came b4 we handled the previous one :c */ + wire data_discarded; + assign data_discarded = word_received && write_word_ready && !write_happens; + + reg reading_finished; + + reg operating; + + always @ (posedge clock_50mhz) begin + if (reset || !operate) begin + operating <= 0; + want_spi_operation <= 0; + finished_operating <= 0; + write_word_ready <= 0; + + words_left_to_receive <= 10'hXXX; + word_idx <= 10'hXXX; + high_byte <= 8'hXX; + high_byte_received <= 1'bx; + reading_finished <= 1'bx; + end // if (reset || !operate) + else begin + operating <= 1; + + if (operate && !operating) begin + want_spi_operation <= 1; + finished_operating <= 0; + write_word_ready <= 0; + words_left_to_receive <= words_to_copy; + word_idx <= 0; + reading_finished <= 0; + high_byte_received <= 0; + + high_byte <= 8'hXX; + end // if (operate && !operating) + else if (finished_operating) begin + want_spi_operation <= 0; + write_word_ready <= 0; + words_left_to_receive <= 10'hXX; + word_idx <= 10'hXX; + reading_finished <= 1'bx; + high_byte_received <= 1'bx; + high_byte <= 8'hXX; + end + else begin + /* + * if spi data comes too fast, we discard it and start reading + * anew once we write current data + */ + if (reading_finished) + want_spi_operation <= 0; + else if (data_discarded) + want_spi_operation <= 0; + else if (write_happens) + want_spi_operation <= 1; + + if (spi_byte_ready) begin + if (high_byte_received) begin + high_byte_received <= 0; + + high_byte <= 8'hXX; + end + else begin + high_byte <= received_byte; + high_byte_received <= 1; + end + end // if (spi_byte_ready) + + if (word_received && !data_discarded) begin + words_left_to_receive <= words_left_to_receive - 1; + write_word_ready <= 1; + write_data <= {high_byte, received_byte}; + + if (words_left_to_receive - 1 == 0) + reading_finished <= 1; + end + else if (write_happens) begin + write_word_ready <= 0; + write_data <= 16'hXXXX; + end + else if (!write_word_ready) begin + write_data <= 16'hXXXX; + end + + if (write_happens) begin + word_idx <= word_idx + 1; + + if (reading_finished) + finished_operating <= 1; + end + end // else: !if(finished_operating) + end // else: !if(reset || !operate) end // always @ (posedge clock_50mhz) -endmodule // dumb_write +endmodule // spi_sram_copy module top(input wire clock_100mhz, input wire but1, @@ -732,20 +1047,25 @@ module top(input wire clock_100mhz, * timing problems */ reg reset; - /* - * `initial` usually isn't synthesizable, but in case - * it is on some particular FPGA - we try to make use of it - */ - initial - reset <= 1; reg err_disabled; reg clock_50mhz; + /* + * `initial` usually isn't synthesizable, but it helps run the code + * in test-benches + */ + initial begin + reset <= 1; + clock_50mhz <= 0; + err_disabled <= 0; + end + always @ (posedge clock_100mhz) clock_50mhz <= clock_50mhz + 1; parameter memory_base = 18'b010101010101010101; + parameter flash_base = 24'h000000; wire vga_io_available; assign vga_io_available = 1; @@ -760,19 +1080,80 @@ module top(input wire clock_100mhz, always @ (posedge clock_50mhz) last_reset <= reset; - wire dumbwrite_io_available; - assign dumbwrite_io_available = vga_io_available && !vga_wants_io; - - wire dumbwrite_wants_io; - wire [17:0] dumbwrite_io_addr; - wire [15:0] dumbwrite_write_data; - - dumb_write dumbwrite(clock_50mhz, reset, dumbwrite_io_available, dumbwrite_write_data, - dumbwrite_wants_io, dumbwrite_io_addr, memory_base, - !reset && last_reset); + wire spi_operation_wanted; + wire [31:0] spi_send_data; + wire [2:0] spi_bytes_to_send; + wire [14:0] spi_bytes_to_receive; + wire spi_byte_ready; + wire [7:0] spi_received_data; + wire spi_operation_finished; + + winbond_spi spi(clock_50mhz, reset, spi_operation_wanted, + spi_send_data, spi_bytes_to_send, + spi_bytes_to_receive, spi_byte_ready, + spi_received_data, spi_operation_finished, + sdo, sdi, sck, ss_n); + + wire chip_powerup_wants_operation; + wire [31:0] chip_powerup_send_data; + wire [2:0] chip_powerup_bytes_to_send; + wire [14:0] chip_powerup_bytes_to_receive; + wire chip_powerup_finished_operating; + + spi_chip_powerup chip_powerup(clock_50mhz, reset, + chip_powerup_wants_operation, + chip_powerup_send_data, + chip_powerup_bytes_to_send, + chip_powerup_bytes_to_receive, + spi_operation_finished, !reset, + chip_powerup_finished_operating); + + wire data_copy_sram_io_available; + assign data_copy_sram_io_available = vga_io_available && !vga_wants_io; + wire [15:0] data_copy_write_data; + wire data_copy_wants_sram_io; + wire [17:0] data_copy_sram_io_addr; + wire data_copy_wants_spi_operation; + wire [31:0] data_copy_spi_send_data; + wire [2:0] data_copy_spi_bytes_to_send; + wire [14:0] data_copy_spi_bytes_to_receive; + wire data_copy_finished_operating; + + spi_sram_copy data_copy(clock_50mhz, reset, data_copy_sram_io_available, + data_copy_write_data, data_copy_wants_sram_io, + data_copy_sram_io_addr, memory_base, + data_copy_wants_spi_operation, + data_copy_spi_send_data, data_copy_spi_bytes_to_send, + data_copy_spi_bytes_to_receive, spi_byte_ready, + spi_received_data, flash_base, + chip_powerup_finished_operating, + data_copy_finished_operating); + + assign { + spi_operation_wanted, + spi_send_data, + spi_bytes_to_send, + spi_bytes_to_receive + } + = !chip_powerup_finished_operating ? + { + chip_powerup_wants_operation, + chip_powerup_send_data, + chip_powerup_bytes_to_send, + chip_powerup_bytes_to_receive + } : + !data_copy_finished_operating ? + { + data_copy_wants_spi_operation, + data_copy_spi_send_data, + data_copy_spi_bytes_to_send, + data_copy_spi_bytes_to_receive + } : + {1'b0, 32'hXXXXXXXX, 3'hX, 15'hXXXX}; wire butwrite_io_available; - assign butwrite_io_available = dumbwrite_io_available && !dumbwrite_wants_io; + assign butwrite_io_available = data_copy_sram_io_available + && !data_copy_wants_sram_io; wire butwrite_wants_io; wire [17:0] butwrite_io_addr; @@ -805,12 +1186,12 @@ module top(input wire clock_100mhz, sram_cs_n <= 1'b0; sram_addr <= vga_io_addr; end - else if (dumbwrite_wants_io) begin + else if (data_copy_wants_sram_io) begin write_in_progress <= 1; sram_oe_n <= 1'b1; sram_cs_n <= 1'b0; - sram_addr <= dumbwrite_io_addr; - write_data <= dumbwrite_write_data; + sram_addr <= data_copy_sram_io_addr; + write_data <= data_copy_write_data; end else if (butwrite_wants_io) begin write_in_progress <= 1; @@ -842,9 +1223,4 @@ module top(input wire clock_100mhz, end assign sram_io = sram_we_n ? 16'bzzzzzzzzzzzzzzzz : write_data; - - assign sdo = sdi; - assign sck = 1; - assign ss_n = 1; - endmodule // top |