mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-22 22:19:14 +01:00
211 lines
6.9 KiB
Coq
211 lines
6.9 KiB
Coq
|
module n64_si (
|
||
|
input i_clk,
|
||
|
input i_reset,
|
||
|
|
||
|
input i_si_clk,
|
||
|
input i_si_reset,
|
||
|
input i_si_dq,
|
||
|
output reg o_si_dq,
|
||
|
|
||
|
input i_eeprom_select,
|
||
|
input i_read_rq,
|
||
|
input i_write_rq,
|
||
|
output reg o_ack,
|
||
|
input [31:0] i_address,
|
||
|
input [31:0] i_data,
|
||
|
output [31:0] o_data,
|
||
|
|
||
|
input i_eeprom_enable,
|
||
|
input i_eeprom_16k_enable
|
||
|
);
|
||
|
|
||
|
localparam CMD_EEPROM_STATUS = 8'h00;
|
||
|
localparam CMD_EEPROM_READ = 8'h04;
|
||
|
localparam CMD_EEPROM_WRITE = 8'h05;
|
||
|
|
||
|
localparam EEPROM_4K_ID = 8'h80;
|
||
|
localparam EEPROM_16K_ID = 8'hC0;
|
||
|
|
||
|
reg r_last_si_clk;
|
||
|
reg r_last_si_dq;
|
||
|
|
||
|
wire w_si_clk_falling_edge = !i_reset && !i_si_reset && r_last_si_clk && !i_si_clk;
|
||
|
wire w_si_clk_rising_edge = !i_reset && !i_si_reset && !r_last_si_clk && i_si_clk;
|
||
|
wire w_si_dq_falling_edge = r_last_si_dq && !i_si_dq;
|
||
|
wire w_si_dq_rising_edge = !r_last_si_dq && i_si_dq;
|
||
|
|
||
|
always @(posedge i_clk) begin
|
||
|
r_last_si_clk <= i_si_clk;
|
||
|
if (w_si_clk_rising_edge) r_last_si_dq <= i_si_dq;
|
||
|
end
|
||
|
|
||
|
// RX module
|
||
|
|
||
|
reg r_rx_enabled;
|
||
|
reg [2:0] r_rx_sub_bit_counter;
|
||
|
reg [2:0] r_rx_bit_counter;
|
||
|
reg [3:0] r_rx_byte_counter;
|
||
|
reg [7:0] r_rx_buffer;
|
||
|
reg r_rx_byte_ready;
|
||
|
reg r_rx_finished, r_last_rx_finished;
|
||
|
|
||
|
wire w_rx_sub_bit_counter_timeout = &r_rx_sub_bit_counter;
|
||
|
wire w_rx_bit_value = r_rx_sub_bit_counter <= 3'd4;
|
||
|
wire w_rx_start = r_last_rx_finished && !r_rx_finished;
|
||
|
wire w_rx_finish = !r_last_rx_finished && r_rx_finished;
|
||
|
|
||
|
always @(posedge i_clk) begin
|
||
|
r_rx_byte_ready <= 1'b0;
|
||
|
r_last_rx_finished <= r_rx_finished;
|
||
|
|
||
|
if (r_rx_enabled && w_si_clk_rising_edge) begin
|
||
|
if (w_rx_sub_bit_counter_timeout) r_rx_finished <= 1'b1;
|
||
|
else r_rx_sub_bit_counter <= r_rx_sub_bit_counter + 3'd1;
|
||
|
|
||
|
if (w_si_dq_falling_edge) begin
|
||
|
r_rx_sub_bit_counter <= 3'd0;
|
||
|
if (r_rx_finished) begin
|
||
|
r_rx_bit_counter <= 3'd0;
|
||
|
r_rx_byte_counter <= 4'b1111;
|
||
|
end
|
||
|
r_rx_finished <= 1'b0;
|
||
|
end
|
||
|
|
||
|
if (w_si_dq_rising_edge) begin
|
||
|
r_rx_bit_counter <= r_rx_bit_counter + 3'd1;
|
||
|
r_rx_buffer <= {r_rx_buffer[6:0], w_rx_bit_value};
|
||
|
if (&r_rx_bit_counter) begin
|
||
|
r_rx_byte_counter <= r_rx_byte_counter + 4'd1;
|
||
|
r_rx_byte_ready <= 1'b1;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
reg r_tx_finished;
|
||
|
|
||
|
reg r_cmd_eeprom_status;
|
||
|
reg r_cmd_eeprom_read;
|
||
|
reg r_cmd_eeprom_write;
|
||
|
|
||
|
wire w_cmd_valid = r_cmd_eeprom_status || r_cmd_eeprom_read || r_cmd_eeprom_write;
|
||
|
wire w_cmd_op = r_rx_byte_ready && r_rx_byte_counter == 4'd0;
|
||
|
|
||
|
always @(posedge i_clk) begin
|
||
|
if (i_reset || i_si_reset || w_rx_start || r_tx_finished) begin
|
||
|
r_cmd_eeprom_status <= 1'b0;
|
||
|
r_cmd_eeprom_read <= 1'b0;
|
||
|
r_cmd_eeprom_write <= 1'b0;
|
||
|
end else if (w_cmd_op) begin
|
||
|
if (i_eeprom_enable) begin
|
||
|
r_cmd_eeprom_status <= r_rx_buffer == CMD_EEPROM_STATUS;
|
||
|
r_cmd_eeprom_read <= r_rx_buffer == CMD_EEPROM_READ;
|
||
|
r_cmd_eeprom_write <= r_rx_buffer == CMD_EEPROM_WRITE;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
reg r_eeprom_read_rq;
|
||
|
reg [10:0] r_eeprom_address;
|
||
|
|
||
|
wire w_eeprom_write_op = r_rx_byte_ready && r_rx_byte_counter >= 4'd2 && r_cmd_eeprom_write;
|
||
|
wire w_eeprom_address_op = r_rx_byte_ready && r_rx_byte_counter == 4'd1 && (r_cmd_eeprom_read || r_cmd_eeprom_write);
|
||
|
wire w_eeprom_address_next_op = r_eeprom_read_rq || w_eeprom_write_op;
|
||
|
|
||
|
always @(posedge i_clk) begin
|
||
|
if (w_eeprom_address_op) r_eeprom_address <= {r_rx_buffer, 3'b000};
|
||
|
if (w_eeprom_address_next_op) r_eeprom_address[2:0] <= r_eeprom_address[2:0] + 3'd1;
|
||
|
end
|
||
|
|
||
|
// TX module
|
||
|
|
||
|
reg [2:0] r_tx_sub_bit_counter;
|
||
|
reg [2:0] r_tx_bit_counter;
|
||
|
reg [3:0] r_tx_byte_counter;
|
||
|
reg [3:0] r_tx_bytes_to_send;
|
||
|
reg [7:0] r_tx_data;
|
||
|
|
||
|
wire [7:0] w_eeprom_o_data;
|
||
|
|
||
|
wire w_tx_current_bit = r_tx_data[3'd7 - r_tx_bit_counter];
|
||
|
wire w_tx_stop_bit = r_tx_byte_counter == r_tx_bytes_to_send;
|
||
|
|
||
|
always @(*) begin
|
||
|
r_tx_data = 8'h00;
|
||
|
if (r_cmd_eeprom_status && r_tx_byte_counter == 4'd1) r_tx_data = i_eeprom_16k_enable ? EEPROM_16K_ID : EEPROM_4K_ID;
|
||
|
if (r_cmd_eeprom_read) r_tx_data = w_eeprom_o_data;
|
||
|
end
|
||
|
|
||
|
always @(posedge i_clk) begin
|
||
|
if (i_reset || i_si_reset) begin
|
||
|
o_si_dq <= 1'b1;
|
||
|
r_rx_enabled <= 1'b1;
|
||
|
r_tx_finished <= 1'b0;
|
||
|
r_eeprom_read_rq <= 1'b0;
|
||
|
end else begin
|
||
|
r_tx_finished <= 1'b0;
|
||
|
r_eeprom_read_rq <= 1'b0;
|
||
|
|
||
|
if (w_rx_finish && w_cmd_valid) begin
|
||
|
r_rx_enabled <= 1'b0;
|
||
|
r_tx_sub_bit_counter <= 3'd0;
|
||
|
r_tx_bit_counter <= 3'd0;
|
||
|
r_tx_byte_counter <= 4'd0;
|
||
|
r_tx_bytes_to_send <= 4'd0;
|
||
|
if (r_cmd_eeprom_status) r_tx_bytes_to_send <= 4'd3;
|
||
|
if (r_cmd_eeprom_read) r_tx_bytes_to_send <= 4'd8;
|
||
|
if (r_cmd_eeprom_write) r_tx_bytes_to_send <= 4'd1;
|
||
|
end
|
||
|
|
||
|
if (!r_rx_enabled) begin
|
||
|
if (w_si_clk_falling_edge) begin
|
||
|
r_tx_sub_bit_counter <= r_tx_sub_bit_counter + 3'd1;
|
||
|
|
||
|
if (r_tx_sub_bit_counter == 3'd0) o_si_dq <= 1'b0;
|
||
|
|
||
|
if ((w_tx_current_bit && r_tx_sub_bit_counter == 3'd2) ||
|
||
|
(!w_tx_current_bit && r_tx_sub_bit_counter == 3'd6) ||
|
||
|
(w_tx_stop_bit && r_tx_sub_bit_counter == 3'd4)) begin
|
||
|
o_si_dq <= 1'b1;
|
||
|
end
|
||
|
|
||
|
if (&r_tx_sub_bit_counter) begin
|
||
|
if (w_tx_stop_bit) begin
|
||
|
r_rx_enabled <= 1'b1;
|
||
|
r_tx_finished <= 1'b1;
|
||
|
end
|
||
|
r_tx_bit_counter <= r_tx_bit_counter + 3'd1;
|
||
|
if (&r_tx_bit_counter) begin
|
||
|
r_eeprom_read_rq <= 1'b1;
|
||
|
r_tx_byte_counter <= r_tx_byte_counter + 4'd1;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
// Block RAM
|
||
|
|
||
|
ram_n64_eeprom ram_n64_eeprom_inst (
|
||
|
.clock(i_clk),
|
||
|
|
||
|
.address_a(r_eeprom_address),
|
||
|
.data_a(r_rx_buffer),
|
||
|
.wren_a(w_eeprom_write_op),
|
||
|
.q_a(w_eeprom_o_data),
|
||
|
|
||
|
.address_b(i_address[10:2]),
|
||
|
.data_b({i_data[7:0], i_data[15:8], i_data[23:16], i_data[31:24]}),
|
||
|
.wren_b(!i_reset && i_eeprom_select && i_write_rq),
|
||
|
.q_b({o_data[7:0], o_data[15:8], o_data[23:16], o_data[31:24]})
|
||
|
);
|
||
|
|
||
|
// Bus logic
|
||
|
|
||
|
always @(posedge i_clk) begin
|
||
|
o_ack <= !i_reset && i_eeprom_select && (i_read_rq || i_write_rq);
|
||
|
end
|
||
|
|
||
|
endmodule
|