SummerCart64/fw/rtl/usb/usb_ft1248.sv

222 lines
6.1 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,
input rx_read,
output [7:0] rx_rdata,
input tx_flush,
output tx_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
2021-08-23 00:35:50 +02:00
logic rx_full;
logic rx_write;
logic [7:0] rx_wdata;
2021-08-15 21:49:02 +02:00
2021-08-23 00:35:50 +02:00
logic tx_empty;
logic tx_read;
logic [7:0] tx_rdata;
2021-08-15 21:49:02 +02:00
2021-08-21 23:51:54 +02:00
intel_fifo_8 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),
.rdreq(rx_read),
.q(rx_rdata),
.full(rx_full),
.wrreq(rx_write),
.data(rx_wdata)
);
2021-08-21 23:51:54 +02:00
intel_fifo_8 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),
.wrreq(tx_write),
.data(tx_wdata)
);
2021-08-23 00:35:50 +02:00
// FT1248 interface controller
2021-08-15 21:49:02 +02:00
2021-08-23 00:35:50 +02:00
typedef enum bit [1:0] {
S_TRY_RX,
S_TRY_TX,
S_COMMAND,
S_DATA
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-23 00:35:50 +02:00
typedef enum bit [1:0] {
P_PRE_RISING,
P_RISING,
P_PRE_FALLING,
P_FALLING
} e_clock_phase;
2021-08-15 21:49:02 +02:00
2021-08-12 21:07:47 +02:00
e_state state;
2021-08-23 00:35:50 +02:00
logic [3:0] clock_phase;
logic usb_clk_output;
logic usb_cs_output;
logic [3:0] usb_miosi_input;
logic [3:0] usb_miosi_output;
logic [3:0] usb_miosi_output_data;
logic usb_miosi_output_enable;
logic usb_miosi_output_enable_data;
logic usb_miso_input;
logic usb_pwren_input;
2021-08-12 21:07:47 +02:00
2021-08-23 00:35:50 +02:00
logic is_cmd_write;
logic [1:0] nibble_counter;
logic [7:0] tx_buffer;
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-23 00:35:50 +02:00
clock_phase <= 4'b0001;
2021-08-12 21:07:47 +02:00
end else begin
2021-08-23 00:35:50 +02:00
clock_phase <= {clock_phase[2:0], clock_phase[3]};
2021-08-12 21:07:47 +02:00
end
end
2021-08-23 00:35:50 +02:00
always_ff @(posedge sys.clk) begin
usb_clk <= usb_clk_output;
usb_cs <= usb_cs_output;
2021-08-15 21:49:02 +02:00
2021-08-23 00:35:50 +02:00
usb_miosi_input <= usb_miosi;
usb_miosi_output <= usb_miosi_output_data;
usb_miosi_output_enable <= usb_miosi_output_enable_data;
usb_miso_input <= usb_miso;
usb_pwren_input <= usb_pwren;
2021-08-15 21:49:02 +02:00
2021-08-23 00:35:50 +02:00
tx_buffer <= tx_rdata;
end
2021-08-15 21:49:02 +02:00
always_comb begin
2021-08-23 00:35:50 +02:00
usb_miosi = usb_miosi_output_enable ? usb_miosi_output : 4'bZZZZ;
2021-08-15 21:49:02 +02:00
end
2021-08-12 21:07:47 +02:00
2021-08-23 00:35:50 +02:00
always_comb begin
case (state)
S_COMMAND: begin
usb_clk_output = clock_phase[P_PRE_FALLING] || clock_phase[P_FALLING];
usb_cs_output = 1'b0;
if (is_cmd_write) begin
usb_miosi_output_data = nibble_counter[0] ? C_WRITE[3:0] : C_WRITE[7:4];
end else begin
usb_miosi_output_data = nibble_counter[0] ? C_READ[3:0] : C_READ[7:4];
end
usb_miosi_output_enable_data = nibble_counter < 2'd2;
end
S_DATA: begin
usb_clk_output = clock_phase[P_PRE_FALLING] || clock_phase[P_FALLING];
usb_cs_output = 1'b0;
usb_miosi_output_data = nibble_counter[0] ? tx_buffer[7:4] : tx_buffer[3:0];
usb_miosi_output_enable_data = is_cmd_write;
end
default: begin
usb_clk_output = 1'b0;
usb_cs_output = 1'b1;
usb_miosi_output_data = 4'hF;
usb_miosi_output_enable_data = 1'b0;
end
endcase
2021-08-15 21:49:02 +02:00
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
rx_write <= 1'b0;
tx_read <= 1'b0;
2021-08-12 21:07:47 +02:00
2021-08-23 00:35:50 +02:00
if (clock_phase[P_RISING]) begin
nibble_counter <= nibble_counter + 1'd1;
end
2021-08-18 13:54:07 +02:00
if (sys.reset) begin
2021-08-15 21:49:02 +02:00
state <= S_TRY_RX;
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;
2021-08-23 00:35:50 +02:00
is_cmd_write <= 1'b0;
nibble_counter <= 2'b11;
2021-08-15 21:49:02 +02:00
end else begin
state <= S_TRY_TX;
end
end
S_TRY_TX: begin
if (!tx_empty) begin
state <= S_COMMAND;
2021-08-23 00:35:50 +02:00
is_cmd_write <= 1'b1;
nibble_counter <= 2'b11;
2021-08-15 21:49:02 +02:00
end else begin
state <= S_TRY_RX;
2021-08-12 21:07:47 +02:00
end
end
S_COMMAND: begin
2021-08-23 00:35:50 +02:00
if (clock_phase[P_RISING]) begin
if (nibble_counter == 2'd2) begin
if (usb_miso_input) begin
state <= is_cmd_write ? S_TRY_RX : S_TRY_TX;
2021-08-15 21:49:02 +02:00
end else begin
2021-08-23 00:35:50 +02:00
state <= S_DATA;
nibble_counter <= 2'd0;
2021-08-15 21:49:02 +02:00
end
2021-08-12 21:07:47 +02:00
end
end
end
S_DATA: begin
2021-08-23 00:35:50 +02:00
if (clock_phase[P_FALLING]) begin
if (nibble_counter[0]) begin
tx_read <= is_cmd_write;
2021-08-15 21:49:02 +02:00
end
2021-08-23 00:35:50 +02:00
end
if (clock_phase[P_RISING]) begin
rx_wdata <= {usb_miosi_input, rx_wdata[7:4]};
if (nibble_counter[0]) begin
rx_write <= !is_cmd_write;
2021-08-15 21:49:02 +02:00
end
2021-08-23 00:35:50 +02:00
if (usb_miso_input || (!is_cmd_write && rx_full) || (is_cmd_write && tx_empty)) begin
state <= is_cmd_write ? S_TRY_RX : S_TRY_TX;
2021-08-12 21:07:47 +02:00
end
end
end
default: begin
2021-08-15 21:49:02 +02:00
state <= S_TRY_RX;
2021-08-12 21:07:47 +02:00
end
endcase
end
end
endmodule