mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-27 08:04:14 +01:00
231 lines
6.5 KiB
Systemverilog
231 lines
6.5 KiB
Systemverilog
module usb_ft1248 (
|
|
if_system.sys sys,
|
|
|
|
output usb_clk,
|
|
output usb_cs,
|
|
input usb_miso,
|
|
inout [3:0] usb_miosi,
|
|
input usb_pwren,
|
|
|
|
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
|
|
);
|
|
|
|
// 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 (
|
|
.clock(sys.clk),
|
|
.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 (
|
|
.clock(sys.clk),
|
|
.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
|
|
|
|
typedef enum bit [2:0] {
|
|
S_TRY_RX = 3'b000,
|
|
S_TRY_TX = 3'b001,
|
|
S_COMMAND = 3'b100,
|
|
S_DATA = 3'b101,
|
|
S_END = 3'b111
|
|
} e_state;
|
|
|
|
typedef enum bit [7:0] {
|
|
C_WRITE = 8'h00,
|
|
C_READ = 8'h04
|
|
} e_command;
|
|
|
|
// FSM state
|
|
|
|
e_state state;
|
|
|
|
// Clock divider and generator
|
|
|
|
reg [3:0] clock_divider;
|
|
wire rising_edge = clock_divider[1];
|
|
|
|
always_ff @(posedge sys.clk) begin
|
|
if (sys.reset || state == S_TRY_RX || state == S_TRY_TX) begin
|
|
clock_divider <= 4'b0001;
|
|
end else begin
|
|
clock_divider <= {clock_divider[2:0], clock_divider[3]};
|
|
end
|
|
end
|
|
|
|
// Output chip select and data register behavior
|
|
|
|
reg [1:0] bit_counter;
|
|
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
|
|
|
|
always_ff @(posedge sys.clk) begin
|
|
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
|
|
|
|
// FSM
|
|
|
|
reg is_write;
|
|
|
|
always_ff @(posedge sys.clk) begin
|
|
rx_write <= 1'b0;
|
|
tx_read <= 1'b0;
|
|
|
|
if (sys.reset) begin
|
|
state <= S_TRY_RX;
|
|
cs_data <= 1'b1;
|
|
miosi_output_enable_data <= 1'b0;
|
|
end else begin
|
|
case (state)
|
|
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;
|
|
end
|
|
end
|
|
|
|
S_COMMAND: begin
|
|
cs_data <= 1'b0;
|
|
if (rising_edge) begin
|
|
bit_counter <= bit_counter + 1'd1;
|
|
miosi_output_enable_data <= 1'b1;
|
|
if (bit_counter == 2'd1) begin
|
|
miosi_output_enable_data <= 1'b0;
|
|
end
|
|
if (bit_counter == 2'd2) begin
|
|
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
|
|
end
|
|
end
|
|
end
|
|
|
|
S_DATA: begin
|
|
if (rising_edge) begin
|
|
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
|
|
state <= S_END;
|
|
miosi_output_enable_data <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
S_END: begin
|
|
cs_data <= 1'b1;
|
|
state <= is_write ? S_TRY_RX : S_TRY_TX;
|
|
end
|
|
|
|
default: begin
|
|
state <= S_TRY_RX;
|
|
cs_data <= 1'b1;
|
|
miosi_output_enable_data <= 1'b0;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
endmodule
|