diff options
| author | Leonard Kugis <leonard@kug.is> | 2021-02-11 14:31:02 +0100 |
|---|---|---|
| committer | Leonard Kugis <leonard@kug.is> | 2021-02-11 14:31:02 +0100 |
| commit | 52f60a20c9d95ecf67b662589d4a4c1160ce0a2a (patch) | |
| tree | b0425a0acd757aa2a33c4db8ccaa897acea409b3 | |
| parent | 266f2ebc6322eeccf85fcc67eccc6d6200014dab (diff) | |
| download | turboswap-52f60a20c9d95ecf67b662589d4a4c1160ce0a2a.tar.gz | |
Reimplemented all HDL files
| -rw-r--r-- | hdl/clock_divider.v | 147 | ||||
| -rw-r--r-- | hdl/fifo_buffer.v | 157 | ||||
| -rw-r--r-- | hdl/sdio_to_spi.v | 235 | ||||
| -rw-r--r-- | hdl/spi_controller.v | 290 | ||||
| -rw-r--r-- | hdl/turbo_top.v | 159 |
5 files changed, 988 insertions, 0 deletions
diff --git a/hdl/clock_divider.v b/hdl/clock_divider.v new file mode 100644 index 0000000..adffe0e --- /dev/null +++ b/hdl/clock_divider.v @@ -0,0 +1,147 @@ +`timescale 1ns / 1ps + +module clock_divider ( + input wire clk_in, + input wire rst_n, + + output wire clk_12mhz, + output wire clk_50mhz, + output wire clk_sdio, + output wire clk_spi +); + + reg [1:0] div_counter_50mhz; + reg [7:0] div_counter_sdio; + reg [7:0] div_counter_spi; + + reg clk_50mhz_reg; + reg clk_sdio_reg; + reg clk_spi_reg; + + reg [7:0] sdio_div_ratio; + reg [7:0] spi_div_ratio; + + reg sdio_clk_en; + reg spi_clk_en; + + assign clk_12mhz = clk_in; + assign clk_50mhz = clk_50mhz_reg; + assign clk_sdio = sdio_clk_en ? clk_sdio_reg : 1'b0; + assign clk_spi = spi_clk_en ? clk_spi_reg : 1'b0; + + always @(posedge clk_in or negedge rst_n) begin + if (!rst_n) begin + div_counter_50mhz <= 2'b00; + clk_50mhz_reg <= 1'b0; + end else begin + div_counter_50mhz <= div_counter_50mhz + 1; + + case (div_counter_50mhz) + 2'b00: clk_50mhz_reg <= 1'b1; + 2'b01: clk_50mhz_reg <= 1'b1; + 2'b10: clk_50mhz_reg <= 1'b0; + 2'b11: clk_50mhz_reg <= 1'b0; + endcase + end + end + + always @(posedge clk_50mhz_reg or negedge rst_n) begin + if (!rst_n) begin + div_counter_sdio <= 8'd0; + clk_sdio_reg <= 1'b0; + sdio_div_ratio <= 8'd1; + end else if (sdio_clk_en) begin + if (div_counter_sdio >= sdio_div_ratio) begin + div_counter_sdio <= 8'd0; + clk_sdio_reg <= ~clk_sdio_reg; + end else begin + div_counter_sdio <= div_counter_sdio + 1; + end + end else begin + div_counter_sdio <= 8'd0; + clk_sdio_reg <= 1'b0; + end + end + + always @(posedge clk_50mhz_reg or negedge rst_n) begin + if (!rst_n) begin + div_counter_spi <= 8'd0; + clk_spi_reg <= 1'b0; + spi_div_ratio <= 8'd1; + end else if (spi_clk_en) begin + if (div_counter_spi >= spi_div_ratio) begin + div_counter_spi <= 8'd0; + clk_spi_reg <= ~clk_spi_reg; + end else begin + div_counter_spi <= div_counter_spi + 1; + end + end else begin + div_counter_spi <= 8'd0; + clk_spi_reg <= 1'b0; + end + end + + always @(posedge clk_50mhz_reg or negedge rst_n) begin + if (!rst_n) begin + sdio_clk_en <= 1'b0; + spi_clk_en <= 1'b0; + end else begin + sdio_clk_en <= 1'b1; + spi_clk_en <= 1'b1; + end + end + + task set_sdio_frequency; + input [7:0] divider; + begin + sdio_div_ratio <= divider; + end + endtask + + task set_spi_frequency; + input [7:0] divider; + begin + spi_div_ratio <= divider; + end + endtask + + task enable_sdio_clock; + input enable; + begin + sdio_clk_en <= enable; + end + endtask + + task enable_spi_clock; + input enable; + begin + spi_clk_en <= enable; + end + endtask + + function [7:0] calc_sdio_divider; + input [7:0] freq_mhz; + begin + if (freq_mhz == 0) + calc_sdio_divider = 8'd0; + else + calc_sdio_divider = 8'd25 / freq_mhz; + end + endfunction + + function [7:0] calc_spi_divider; + input [7:0] freq_mhz; + begin + if (freq_mhz == 0) + calc_spi_divider = 8'd0; + else + calc_spi_divider = 8'd25 / freq_mhz; + end + endfunction + + initial begin + sdio_div_ratio = calc_sdio_divider(8'd25); + spi_div_ratio = calc_spi_divider(8'd25); + end + +endmodule
\ No newline at end of file diff --git a/hdl/fifo_buffer.v b/hdl/fifo_buffer.v new file mode 100644 index 0000000..dd56537 --- /dev/null +++ b/hdl/fifo_buffer.v @@ -0,0 +1,157 @@ +`timescale 1ns / 1ps + +module fifo_buffer ( + input wire wr_clk, + input wire [7:0] wr_data, + input wire wr_valid, + output wire wr_ready, + + input wire rd_clk, + output wire [7:0] rd_data, + output wire rd_valid, + input wire rd_ready, + + input wire rst_n, + + output wire fifo_empty, + output wire fifo_full, + output wire [7:0] fifo_level +); + + parameter DEPTH = 512; + parameter ADDR_WIDTH = 9; + + reg [7:0] mem [0:DEPTH-1]; + + reg [ADDR_WIDTH:0] wr_ptr; + reg [ADDR_WIDTH:0] wr_ptr_gray; + reg [ADDR_WIDTH:0] wr_ptr_gray_sync1; + reg [ADDR_WIDTH:0] wr_ptr_gray_sync2; + + reg [ADDR_WIDTH:0] rd_ptr; + reg [ADDR_WIDTH:0] rd_ptr_gray; + reg [ADDR_WIDTH:0] rd_ptr_gray_sync1; + reg [ADDR_WIDTH:0] rd_ptr_gray_sync2; + + wire [ADDR_WIDTH:0] wr_ptr_bin; + wire [ADDR_WIDTH:0] rd_ptr_bin; + wire [ADDR_WIDTH:0] fifo_count; + + reg wr_en; + reg rd_en; + + reg [7:0] rd_data_reg; + reg rd_valid_reg; + + assign wr_ready = ~fifo_full; + + always @(posedge wr_clk or negedge rst_n) begin + if (!rst_n) begin + wr_ptr <= 0; + wr_ptr_gray <= 0; + wr_en <= 1'b0; + end else begin + wr_en <= wr_valid && wr_ready; + + if (wr_en) begin + mem[wr_ptr[ADDR_WIDTH-1:0]] <= wr_data; + wr_ptr <= wr_ptr + 1; + end + + wr_ptr_gray <= binary_to_gray(wr_ptr); + end + end + + always @(posedge wr_clk or negedge rst_n) begin + if (!rst_n) begin + rd_ptr_gray_sync1 <= 0; + rd_ptr_gray_sync2 <= 0; + end else begin + rd_ptr_gray_sync1 <= rd_ptr_gray; + rd_ptr_gray_sync2 <= rd_ptr_gray_sync1; + end + end + + assign rd_data = rd_data_reg; + assign rd_valid = rd_valid_reg; + + always @(posedge rd_clk or negedge rst_n) begin + if (!rst_n) begin + rd_ptr <= 0; + rd_ptr_gray <= 0; + rd_en <= 1'b0; + rd_data_reg <= 8'h00; + rd_valid_reg <= 1'b0; + end else begin + rd_en <= rd_ready && ~fifo_empty; + + if (rd_en) begin + rd_data_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]]; + rd_valid_reg <= 1'b1; + rd_ptr <= rd_ptr + 1; + end else if (rd_ready) begin + rd_valid_reg <= 1'b0; + end + + rd_ptr_gray <= binary_to_gray(rd_ptr); + end + end + + always @(posedge rd_clk or negedge rst_n) begin + if (!rst_n) begin + wr_ptr_gray_sync1 <= 0; + wr_ptr_gray_sync2 <= 0; + end else begin + wr_ptr_gray_sync1 <= wr_ptr_gray; + wr_ptr_gray_sync2 <= wr_ptr_gray_sync1; + end + end + + assign wr_ptr_bin = gray_to_binary(wr_ptr_gray_sync2); + assign rd_ptr_bin = gray_to_binary(rd_ptr_gray_sync2); + + wire [ADDR_WIDTH:0] fifo_count_wr; + assign fifo_count_wr = wr_ptr - gray_to_binary(rd_ptr_gray_sync2); + + wire [ADDR_WIDTH:0] fifo_count_rd; + assign fifo_count_rd = gray_to_binary(wr_ptr_gray_sync2) - rd_ptr; + + assign fifo_full = (fifo_count_wr >= DEPTH); + assign fifo_empty = (fifo_count_rd == 0); + + reg [7:0] fifo_level_reg; + always @(*) begin + if (fifo_count_wr > DEPTH) + fifo_level_reg = DEPTH; + else + fifo_level_reg = fifo_count_wr[7:0]; + end + + assign fifo_level = fifo_level_reg; + + function [ADDR_WIDTH:0] binary_to_gray; + input [ADDR_WIDTH:0] binary; + begin + binary_to_gray = binary ^ (binary >> 1); + end + endfunction + + function [ADDR_WIDTH:0] gray_to_binary; + input [ADDR_WIDTH:0] gray; + reg [ADDR_WIDTH:0] binary; + integer i; + begin + binary[ADDR_WIDTH] = gray[ADDR_WIDTH]; + for (i = ADDR_WIDTH-1; i >= 0; i = i - 1) + binary[i] = binary[i+1] ^ gray[i]; + gray_to_binary = binary; + end + endfunction + + integer i; + initial begin + for (i = 0; i < DEPTH; i = i + 1) + mem[i] = 8'h00; + end + +endmodule
\ No newline at end of file diff --git a/hdl/sdio_to_spi.v b/hdl/sdio_to_spi.v new file mode 100644 index 0000000..6e83ca0 --- /dev/null +++ b/hdl/sdio_to_spi.v @@ -0,0 +1,235 @@ +`timescale 1ns / 1ps + +module sdio_to_spi ( + input wire sd_clk, + inout wire sd_cmd, + inout wire [3:0] sd_dat, + + output reg sd_cmd_dir, + output reg [3:0] sd_dat_dir, + + input wire clk_sys, + input wire rst_n, + + output reg [7:0] cmd_opcode, + output reg [31:0] cmd_address, + output reg [15:0] cmd_length, + output reg cmd_valid, + input wire cmd_ready, + + output reg [7:0] data_out, + output reg data_out_valid, + input wire data_out_ready, + + input wire [7:0] data_in, + input wire data_in_valid, + output reg data_in_ready, + + output reg [3:0] sdio_state, + output reg [3:0] status_reg +); + + localparam CMD0_GO_IDLE_STATE = 6'h00; + localparam CMD2_ALL_SEND_CID = 6'h02; + localparam CMD3_SEND_RELATIVE_ADDR = 6'h03; + localparam CMD7_SELECT_CARD = 6'h07; + localparam CMD8_SEND_IF_COND = 6'h08; + localparam CMD9_SEND_CSD = 6'h09; + localparam CMD12_STOP_TRANSMISSION = 6'h0C; + localparam CMD16_SET_BLOCKLEN = 6'h10; + localparam CMD17_READ_SINGLE_BLOCK = 6'h11; + localparam CMD18_READ_MULTIPLE_BLOCK = 6'h12; + localparam CMD24_WRITE_BLOCK = 6'h18; + localparam CMD25_WRITE_MULTIPLE_BLOCK = 6'h19; + localparam CMD55_APP_CMD = 6'h37; + localparam ACMD41_SD_SEND_OP_COND = 6'h29; + + localparam STATE_IDLE = 4'h0; + localparam STATE_CMD_RX = 4'h1; + localparam STATE_CMD_PROCESS = 4'h2; + localparam STATE_RESP_TX = 4'h3; + localparam STATE_DATA_RX = 4'h4; + localparam STATE_DATA_TX = 4'h5; + localparam STATE_WAIT_SPI = 4'h6; + localparam STATE_ERROR = 4'h7; + + localparam SPI_READ = 8'h03; + localparam SPI_FAST_READ = 8'h0B; + localparam SPI_PP = 8'h02; + localparam SPI_SE = 8'h20; + localparam SPI_BE = 8'hD8; + localparam SPI_CE = 8'hC7; + localparam SPI_RDSR = 8'h05; + localparam SPI_WREN = 8'h06; + localparam SPI_RDID = 8'h9F; + + reg [47:0] cmd_reg; + reg [5:0] cmd_index; + reg cmd_start; + reg cmd_done; + + reg [135:0] resp_reg; + reg [6:0] resp_bit_count; + reg resp_start; + reg resp_done; + + reg [31:0] block_size; + reg [31:0] rca; + reg card_selected; + reg [3:0] dat_bus_width; + + reg [15:0] data_counter; + reg [7:0] crc7; + reg [15:0] crc16; + + always @(posedge sd_clk or negedge rst_n) begin + if (!rst_n) begin + cmd_reg <= 48'h0; + cmd_index <= 6'd0; + cmd_start <= 1'b0; + cmd_done <= 1'b0; + sd_cmd_dir <= 1'b1; + sdio_state <= STATE_IDLE; + end else begin + case (sdio_state) + STATE_IDLE: begin + cmd_start <= 1'b0; + cmd_done <= 1'b0; + sd_cmd_dir <= 1'b1; + + if (sd_cmd === 1'b0) begin + sdio_state <= STATE_CMD_RX; + cmd_index <= 6'd1; + cmd_reg <= 48'h0; + end + end + + STATE_CMD_RX: begin + if (cmd_index < 6'd48) begin + cmd_reg[47] <= sd_cmd; + cmd_reg <= cmd_reg << 1; + cmd_index <= cmd_index + 1; + end else begin + sdio_state <= STATE_CMD_PROCESS; + cmd_start <= 1'b1; + cmd_done <= 1'b0; + end + end + + STATE_CMD_PROCESS: begin + cmd_start <= 1'b0; + if (cmd_ready && cmd_valid) begin + sdio_state <= STATE_RESP_TX; + resp_start <= 1'b1; + end + end + + STATE_RESP_TX: begin + resp_start <= 1'b0; + sd_cmd_dir <= 1'b0; + if (resp_done) begin + if (cmd_reg[45:40] == CMD17_READ_SINGLE_BLOCK || + cmd_reg[45:40] == CMD18_READ_MULTIPLE_BLOCK) begin + sdio_state <= STATE_DATA_TX; + end else if (cmd_reg[45:40] == CMD24_WRITE_BLOCK || + cmd_reg[45:40] == CMD25_WRITE_MULTIPLE_BLOCK) begin + sdio_state <= STATE_DATA_RX; + end else begin + sdio_state <= STATE_IDLE; + end + end + end + + STATE_DATA_RX: begin + end + + STATE_DATA_TX: begin + end + + STATE_WAIT_SPI: begin + end + + STATE_ERROR: begin + end + endcase + end + end + + always @(*) begin + cmd_valid = 1'b0; + cmd_opcode = 8'h00; + cmd_address = 32'h0; + cmd_length = 16'h0; + + if (cmd_start && !cmd_done) begin + case (cmd_reg[45:40]) + CMD17_READ_SINGLE_BLOCK: begin + cmd_valid = 1'b1; + cmd_opcode = SPI_READ; + cmd_address = cmd_reg[39:8]; + cmd_length = block_size; + end + + CMD24_WRITE_BLOCK: begin + cmd_valid = 1'b1; + cmd_opcode = SPI_PP; + cmd_address = cmd_reg[39:8]; + cmd_length = block_size; + end + + CMD9_SEND_CSD: begin + cmd_valid = 1'b0; + end + + CMD2_ALL_SEND_CID: begin + cmd_valid = 1'b0; + end + + default: begin + cmd_valid = 1'b0; + end + endcase + end + end + + always @(posedge sd_clk) begin + if (resp_start) begin + case (cmd_reg[45:40]) + CMD0_GO_IDLE_STATE: begin + resp_reg <= {136{1'b1}}; + end + + CMD8_SEND_IF_COND: begin + resp_reg <= {8'hAA, 24'h0, 8'h01}; + end + + CMD17_READ_SINGLE_BLOCK, + CMD24_WRITE_BLOCK: begin + resp_reg <= {8'h00, 120'h0}; + end + + default: begin + resp_reg <= {136{1'b1}}; + end + endcase + end + end + + always @(posedge sd_clk) begin + if (!rst_n) begin + data_out_valid <= 1'b0; + data_in_ready <= 1'b0; + sd_dat_dir <= 4'b1111; + end else begin + end + end + + initial begin + block_size = 32'd512; + rca = 32'h00010000; + card_selected = 1'b0; + dat_bus_width = 4'b0001; + status_reg = 4'b0000; + end + +endmodule
\ No newline at end of file diff --git a/hdl/spi_controller.v b/hdl/spi_controller.v new file mode 100644 index 0000000..5bc71f6 --- /dev/null +++ b/hdl/spi_controller.v @@ -0,0 +1,290 @@ +`timescale 1ns / 1ps + +module spi_controller ( + input wire clk, + input wire rst_n, + + input wire [7:0] cmd_opcode, + input wire [31:0] cmd_address, + input wire [15:0] cmd_length, + input wire cmd_valid, + output wire cmd_ready, + + input wire [7:0] data_in, + input wire data_in_valid, + output wire data_in_ready, + + output wire [7:0] data_out, + output wire data_out_valid, + input wire data_out_ready, + + output wire spi0_sck, + output wire spi0_mosi, + input wire spi0_miso, + output wire spi0_cs, + + output wire spi1_sck, + output wire spi1_mosi, + input wire spi1_miso, + output wire spi1_cs, + + output reg [3:0] flash_select, + output reg [3:0] spi_state, + output reg [3:0] status_reg +); + + localparam STATE_IDLE = 4'h0; + localparam STATE_CMD = 4'h1; + localparam STATE_ADDR = 4'h2; + localparam STATE_DUMMY = 4'h3; + localparam STATE_DATA_RX = 4'h4; + localparam STATE_DATA_TX = 4'h5; + localparam STATE_WAIT = 4'h6; + localparam STATE_ERROR = 4'h7; + + localparam MODE_STANDARD = 2'b00; + localparam MODE_FAST = 2'b01; + localparam MODE_DUAL = 2'b10; + localparam MODE_QUAD = 2'b11; + + localparam CMD_WREN = 8'h06; + localparam CMD_WRDI = 8'h04; + localparam CMD_RDSR = 8'h05; + localparam CMD_WRSR = 8'h01; + localparam CMD_READ = 8'h03; + localparam CMD_FAST_READ = 8'h0B; + localparam CMD_DREAD = 8'h3B; + localparam CMD_QREAD = 8'h6B; + localparam CMD_PP = 8'h02; + localparam CMD_SE = 8'h20; + localparam CMD_BE32 = 8'h52; + localparam CMD_BE64 = 8'hD8; + localparam CMD_CE = 8'hC7; + localparam CMD_RDID = 8'h9F; + localparam CMD_RDFR = 8'h48; + localparam CMD_WRFR = 8'h42; + + reg [7:0] spi_mode; + reg [2:0] spi_divider; + reg [31:0] current_addr; + reg [15:0] bytes_remaining; + reg [7:0] command_reg; + reg [3:0] state; + reg [3:0] next_state; + + reg [7:0] tx_shift_reg; + reg [7:0] rx_shift_reg; + reg [3:0] bit_counter; + reg tx_active; + reg rx_active; + + reg cs0_active; + reg cs1_active; + reg sck_active; + + reg [23:0] delay_counter; + + reg [7:0] clk_div_counter; + wire sck_posedge; + wire sck_negedge; + + assign sck_posedge = (clk_div_counter == spi_divider); + assign sck_negedge = (clk_div_counter == (spi_divider >> 1)); + + assign spi0_sck = sck_active & cs0_active & ~spi0_cs; + assign spi1_sck = sck_active & cs1_active & ~spi1_cs; + assign spi0_cs = ~cs0_active; + assign spi1_cs = ~cs1_active; + + assign spi0_mosi = tx_active ? tx_shift_reg[7] : 1'bz; + assign spi1_mosi = tx_active ? tx_shift_reg[7] : 1'bz; + + assign cmd_ready = (state == STATE_IDLE); + + assign data_in_ready = (state == STATE_DATA_TX) && tx_active && sck_negedge; + assign data_out_valid = (state == STATE_DATA_RX) && rx_active && sck_posedge; + + always @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + state <= STATE_IDLE; + spi_state <= STATE_IDLE; + cs0_active <= 1'b0; + cs1_active <= 1'b0; + sck_active <= 1'b0; + tx_active <= 1'b0; + rx_active <= 1'b0; + spi_mode <= MODE_STANDARD; + spi_divider <= 3'd1; + flash_select <= 2'b00; + status_reg <= 4'b0000; + end else begin + state <= next_state; + spi_state <= state; + + case (state) + STATE_IDLE: begin + cs0_active <= 1'b0; + cs1_active <= 1'b0; + sck_active <= 1'b0; + tx_active <= 1'b0; + rx_active <= 1'b0; + + if (cmd_valid && cmd_ready) begin + if (cmd_address[24] == 1'b0) begin + cs0_active <= 1'b1; + flash_select <= 2'b01; + end else begin + cs1_active <= 1'b1; + flash_select <= 2'b10; + end + + command_reg <= cmd_opcode; + current_addr <= cmd_address; + bytes_remaining <= cmd_length; + next_state <= STATE_CMD; + end + end + + STATE_CMD: begin + if (sck_negedge) begin + if (bit_counter == 4'd7) begin + bit_counter <= 4'd0; + if (command_reg == CMD_READ || + command_reg == CMD_FAST_READ || + command_reg == CMD_PP) begin + next_state <= STATE_ADDR; + end else if (command_reg == CMD_RDSR || + command_reg == CMD_RDID) begin + next_state <= STATE_DATA_RX; + end else begin + next_state <= STATE_WAIT; + end + end else begin + tx_shift_reg <= tx_shift_reg << 1; + bit_counter <= bit_counter + 1; + end + end + end + + STATE_ADDR: begin + if (sck_negedge) begin + if (bit_counter == 4'd7) begin + bit_counter <= 4'd0; + if (addr_byte_counter == 3'd2) begin + if (command_reg == CMD_FAST_READ || + command_reg == CMD_DREAD || + command_reg == CMD_QREAD) begin + next_state <= STATE_DUMMY; + end else if (command_reg == CMD_READ) begin + next_state <= STATE_DATA_RX; + end else if (command_reg == CMD_PP) begin + next_state <= STATE_DATA_TX; + end else begin + next_state <= STATE_WAIT; + end + end else begin + addr_byte_counter <= addr_byte_counter + 1; + end + end else begin + tx_shift_reg <= tx_shift_reg << 1; + bit_counter <= bit_counter + 1; + end + end + end + + STATE_DATA_RX: begin + rx_active <= 1'b1; + if (sck_posedge) begin + rx_shift_reg <= {rx_shift_reg[6:0], (cs0_active ? spi0_miso : spi1_miso)}; + if (bit_counter == 4'd7) begin + bit_counter <= 4'd0; + data_out <= rx_shift_reg; + if (bytes_remaining > 0) begin + bytes_remaining <= bytes_remaining - 1; + end else begin + next_state <= STATE_IDLE; + rx_active <= 1'b0; + end + end else begin + bit_counter <= bit_counter + 1; + end + end + end + + STATE_DATA_TX: begin + tx_active <= 1'b1; + if (sck_negedge) begin + if (bit_counter == 4'd7) begin + bit_counter <= 4'd0; + if (data_in_valid && data_in_ready) begin + tx_shift_reg <= data_in; + if (bytes_remaining > 0) begin + bytes_remaining <= bytes_remaining - 1; + end else begin + next_state <= STATE_WAIT; + tx_active <= 1'b0; + end + end + end else begin + tx_shift_reg <= tx_shift_reg << 1; + bit_counter <= bit_counter + 1; + end + end + end + + STATE_WAIT: begin + if (delay_counter == 24'hFFFFFF) begin + next_state <= STATE_IDLE; + end else begin + delay_counter <= delay_counter + 1; + end + end + + STATE_ERROR: begin + cs0_active <= 1'b0; + cs1_active <= 1'b0; + sck_active <= 1'b0; + next_state <= STATE_IDLE; + end + endcase + end + end + + always @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + clk_div_counter <= 8'd0; + sck_active <= 1'b0; + end else begin + if (cs0_active || cs1_active) begin + if (clk_div_counter >= spi_divider) begin + clk_div_counter <= 8'd0; + sck_active <= ~sck_active; + end else begin + clk_div_counter <= clk_div_counter + 1; + end + end else begin + clk_div_counter <= 8'd0; + sck_active <= 1'b0; + end + end + end + + reg [2:0] addr_byte_counter; + + always @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + addr_byte_counter <= 3'd0; + end else if (state == STATE_ADDR) begin + end else begin + addr_byte_counter <= 3'd0; + end + end + + initial begin + tx_shift_reg = 8'h00; + rx_shift_reg = 8'h00; + bit_counter = 4'd0; + delay_counter = 24'h0; + end + +endmodule
\ No newline at end of file diff --git a/hdl/turbo_top.v b/hdl/turbo_top.v new file mode 100644 index 0000000..eb17446 --- /dev/null +++ b/hdl/turbo_top.v @@ -0,0 +1,159 @@ +`timescale 1ns / 1ps + +module turbo_top ( + input wire SD_CLK, + inout wire SD_CMD, + inout wire [3:0] SD_DAT, + + output wire SPI0_SCK, + output wire SPI0_MOSI, + input wire SPI0_MISO, + output wire SPI0_CS, + + output wire SPI1_SCK, + output wire SPI1_MOSI, + input wire SPI1_MISO, + output wire SPI1_CS, + + output wire UART_TX, + input wire UART_RX, + + output wire LED0, + output wire LED1, + output wire LED2, + output wire LED3, + + input wire CRESET_B, + output wire CDONE, + + input wire CLK_12MHZ, + + output wire PWR_EN, + input wire PWR_GOOD +); + + wire clk_12mhz; + wire clk_50mhz; + wire clk_sdio; + wire clk_spi; + + wire rst_n; + wire sdio_cmd_dir; + wire [3:0] sdio_dat_dir; + + wire [7:0] cmd_opcode; + wire [31:0] cmd_address; + wire [15:0] cmd_length; + wire cmd_valid; + wire cmd_ready; + + wire [7:0] data_in; + wire data_in_valid; + wire data_in_ready; + + wire [7:0] data_out; + wire data_out_valid; + wire data_out_ready; + + wire [3:0] sdio_state; + wire [3:0] spi_state; + wire [3:0] flash_select; + + wire [7:0] status_reg; + + clock_divider clock_div ( + .clk_in(CLK_12MHZ), + .rst_n(CRESET_B), + .clk_12mhz(clk_12mhz), + .clk_50mhz(clk_50mhz), + .clk_sdio(clk_sdio), + .clk_spi(clk_spi) + ); + + sdio_to_spi sdio_converter ( + .sd_clk(SD_CLK), + .sd_cmd(SD_CMD), + .sd_dat(SD_DAT), + .sd_cmd_dir(sdio_cmd_dir), + .sd_dat_dir(sdio_dat_dir), + .clk_sys(clk_50mhz), + .rst_n(rst_n), + .cmd_opcode(cmd_opcode), + .cmd_address(cmd_address), + .cmd_length(cmd_length), + .cmd_valid(cmd_valid), + .cmd_ready(cmd_ready), + .data_out(data_out), + .data_out_valid(data_out_valid), + .data_out_ready(data_out_ready), + .data_in(data_in), + .data_in_valid(data_in_valid), + .data_in_ready(data_in_ready), + .sdio_state(sdio_state), + .status_reg(status_reg[3:0]) + ); + + spi_controller spi_ctrl ( + .clk(clk_spi), + .rst_n(rst_n), + .cmd_opcode(cmd_opcode), + .cmd_address(cmd_address), + .cmd_length(cmd_length), + .cmd_valid(cmd_valid), + .cmd_ready(cmd_ready), + .data_in(data_in), + .data_in_valid(data_in_valid), + .data_in_ready(data_in_ready), + .data_out(data_out), + .data_out_valid(data_out_valid), + .data_out_ready(data_out_ready), + .spi0_sck(SPI0_SCK), + .spi0_mosi(SPI0_MOSI), + .spi0_miso(SPI0_MISO), + .spi0_cs(SPI0_CS), + .spi1_sck(SPI1_SCK), + .spi1_mosi(SPI1_MOSI), + .spi1_miso(SPI1_MISO), + .spi1_cs(SPI1_CS), + .flash_select(flash_select), + .spi_state(spi_state), + .status_reg(status_reg[7:4]) + ); + + fifo_buffer data_fifo ( + .wr_clk(clk_sdio), + .rd_clk(clk_spi), + .rst_n(rst_n), + .wr_data(data_out), + .wr_valid(data_out_valid), + .wr_ready(data_out_ready), + .rd_data(data_in), + .rd_valid(data_in_valid), + .rd_ready(data_in_ready), + .fifo_empty(), + .fifo_full(), + .fifo_level() + ); + + assign rst_n = CRESET_B & PWR_GOOD; + + assign SD_CMD = sdio_cmd_dir ? 1'bz : 1'b0; + generate + genvar i; + for (i = 0; i < 4; i = i + 1) begin : dat_dir_gen + assign SD_DAT[i] = sdio_dat_dir[i] ? 1'bz : 1'b0; + end + endgenerate + + assign LED0 = ~rst_n; + assign LED1 = |sdio_state; + assign LED2 = |spi_state; + assign LED3 = |flash_select; + + assign UART_TX = UART_RX; + + assign PWR_EN = 1'b1; + + assign CDONE = 1'b1; + +endmodule
\ No newline at end of file |
