SummerCart64/fw/rtl/usb/usb_ft1248.sv

231 lines
6.5 KiB
Systemverilog
Raw Normal View History

2021-08-12 21:07:47 +02:00
module usb_ft1248 (
2021-08-18 13:54:07 +02:00
if_system.sys sys,
2021-08-12 21:07:47 +02:00
output usb_clk,
output usb_cs,
input usb_miso,
inout [3:0] usb_miosi,
2021-08-18 13:54:07 +02:00
input usb_pwren,
2021-08-12 21:07:47 +02:00
2021-08-15 21:49:02 +02:00
input rx_flush,
output rx_empty,
output rx_almost_empty,
input rx_read,
output [7:0] rx_rdata,
input tx_flush,
output tx_full,
output tx_almost_full,
input tx_write,
input [7:0] tx_wdata
2021-08-12 21:07:47 +02:00
);
2021-08-15 21:49:02 +02:00
// FIFOs
wire rx_full;
wire rx_almost_full;
reg rx_write;
reg [7:0] rx_wdata;
wire tx_empty;
reg tx_read;
wire [7:0] tx_rdata;
fifo8 fifo_8_rx_inst (
2021-08-18 13:54:07 +02:00
.clock(sys.clk),
2021-08-15 21:49:02 +02:00
.sclr(rx_flush),
.empty(rx_empty),
.almost_empty(rx_almost_empty),
.rdreq(rx_read),
.q(rx_rdata),
.full(rx_full),
.almost_full(rx_almost_full),
.wrreq(rx_write),
.data(rx_wdata)
);
fifo8 fifo_8_tx_inst (
2021-08-18 13:54:07 +02:00
.clock(sys.clk),
2021-08-15 21:49:02 +02:00
.sclr(tx_flush),
.empty(tx_empty),
.rdreq(tx_read),
.q(tx_rdata),
.full(tx_full),
.almost_full(tx_almost_full),
.wrreq(tx_write),
.data(tx_wdata)
);
// FT1248 interface controller
// Constants definition
2021-08-12 21:07:47 +02:00
typedef enum bit [2:0] {
2021-08-15 21:49:02 +02:00
S_TRY_RX = 3'b000,
S_TRY_TX = 3'b001,
2021-08-12 21:07:47 +02:00
S_COMMAND = 3'b100,
S_DATA = 3'b101,
2021-08-15 21:49:02 +02:00
S_END = 3'b111
2021-08-12 21:07:47 +02:00
} e_state;
typedef enum bit [7:0] {
C_WRITE = 8'h00,
C_READ = 8'h04
} e_command;
2021-08-15 21:49:02 +02:00
// FSM state
2021-08-12 21:07:47 +02:00
e_state state;
2021-08-15 21:49:02 +02:00
// Clock divider and generator
2021-08-12 21:07:47 +02:00
reg [3:0] clock_divider;
2021-08-15 21:49:02 +02:00
wire rising_edge = clock_divider[1];
2021-08-12 21:07:47 +02:00
2021-08-18 13:54:07 +02:00
always_ff @(posedge sys.clk) begin
if (sys.reset || state == S_TRY_RX || state == S_TRY_TX) begin
2021-08-12 21:07:47 +02:00
clock_divider <= 4'b0001;
end else begin
clock_divider <= {clock_divider[2:0], clock_divider[3]};
end
end
2021-08-15 21:49:02 +02:00
// Output chip select and data register behavior
2021-08-12 21:07:47 +02:00
reg [1:0] bit_counter;
2021-08-15 21:49:02 +02:00
reg [7:0] tx_buffer;
wire clk_data;
reg cs_data;
wire [3:0] miosi_data;
reg miosi_output_enable_data;
reg clk_output;
reg cs_output;
reg [3:0] miosi_input;
reg [3:0] miosi_output;
reg miosi_output_enable;
reg miso_input;
always_comb begin
clk_data = 1'b0;
if (state == S_COMMAND || state == S_DATA) clk_data = (clock_divider[2] | clock_divider[3]);
usb_clk = clk_output;
usb_cs = cs_output;
miosi_data = bit_counter[0] ? tx_buffer[3:0] : tx_buffer[7:4];
usb_miosi = miosi_output_enable ? miosi_output : 4'bZZZZ;
end
2021-08-12 21:07:47 +02:00
2021-08-18 13:54:07 +02:00
always_ff @(posedge sys.clk) begin
2021-08-15 21:49:02 +02:00
clk_output <= clk_data;
cs_output <= cs_data;
miosi_input <= usb_miosi;
miosi_output <= miosi_data;
miosi_output_enable <= miosi_output_enable_data;
miso_input <= usb_miso;
end
2021-08-12 21:07:47 +02:00
2021-08-15 21:49:02 +02:00
// FSM
2021-08-12 21:07:47 +02:00
2021-08-15 21:49:02 +02:00
reg is_write;
2021-08-12 21:07:47 +02:00
2021-08-18 13:54:07 +02:00
always_ff @(posedge sys.clk) begin
2021-08-15 21:49:02 +02:00
rx_write <= 1'b0;
tx_read <= 1'b0;
2021-08-12 21:07:47 +02:00
2021-08-18 13:54:07 +02:00
if (sys.reset) begin
2021-08-15 21:49:02 +02:00
state <= S_TRY_RX;
cs_data <= 1'b1;
miosi_output_enable_data <= 1'b0;
2021-08-12 21:07:47 +02:00
end else begin
case (state)
2021-08-15 21:49:02 +02:00
S_TRY_RX: begin
if (!rx_full) begin
state <= S_COMMAND;
tx_buffer <= C_READ;
bit_counter <= 2'b11;
is_write <= 1'b0;
end else begin
state <= S_TRY_TX;
end
end
S_TRY_TX: begin
if (!tx_empty) begin
state <= S_COMMAND;
tx_buffer <= C_WRITE;
bit_counter <= 2'b11;
is_write <= 1'b1;
end else begin
state <= S_TRY_RX;
2021-08-12 21:07:47 +02:00
end
end
S_COMMAND: begin
2021-08-15 21:49:02 +02:00
cs_data <= 1'b0;
2021-08-12 21:07:47 +02:00
if (rising_edge) begin
bit_counter <= bit_counter + 1'd1;
2021-08-15 21:49:02 +02:00
miosi_output_enable_data <= 1'b1;
if (bit_counter == 2'd1) begin
miosi_output_enable_data <= 1'b0;
end
2021-08-12 21:07:47 +02:00
if (bit_counter == 2'd2) begin
2021-08-15 21:49:02 +02:00
if (!miso_input) begin
state <= S_DATA;
bit_counter <= 2'b11;
tx_buffer <= tx_rdata;
miosi_output_enable_data <= is_write;
end else begin
state <= S_END;
miosi_output_enable_data <= 1'b0;
end
2021-08-12 21:07:47 +02:00
end
end
end
S_DATA: begin
if (rising_edge) begin
2021-08-15 21:49:02 +02:00
bit_counter <= {1'b0, ~bit_counter[0]};
miosi_output_enable_data <= is_write;
rx_wdata <= {miosi_input, rx_wdata[7:4]};
if (bit_counter == 1'd1) begin
tx_buffer <= tx_rdata;
end
if (!is_write && (bit_counter[0] == 1'd0)) begin
rx_write <= 1'b1;
end
if (is_write && (bit_counter[0] == 1'd1)) begin
tx_read <= 1'b1;
end
if (
(bit_counter[0] == 1'd1 && miso_input) ||
(bit_counter[0] == 1'd0 && (
(is_write && tx_empty) ||
(!is_write && rx_almost_full)
))) begin
2021-08-12 21:07:47 +02:00
state <= S_END;
2021-08-15 21:49:02 +02:00
miosi_output_enable_data <= 1'b0;
2021-08-12 21:07:47 +02:00
end
end
end
S_END: begin
2021-08-15 21:49:02 +02:00
cs_data <= 1'b1;
state <= is_write ? S_TRY_RX : S_TRY_TX;
2021-08-12 21:07:47 +02:00
end
default: begin
2021-08-15 21:49:02 +02:00
state <= S_TRY_RX;
cs_data <= 1'b1;
miosi_output_enable_data <= 1'b0;
2021-08-12 21:07:47 +02:00
end
endcase
end
end
endmodule