SummerCart64/fw/rtl/n64_pi.v
2020-10-08 02:04:42 +02:00

96 lines
3.1 KiB
Verilog

module n64_pi (
input i_clk,
input i_reset,
input [1:0] i_n64_pi_alel,
input [1:0] i_n64_pi_aleh,
input i_n64_pi_read,
input i_n64_pi_write,
input [15:0] i_n64_pi_ad,
output reg [15:0] o_n64_pi_ad,
output o_n64_pi_ad_mode,
output reg o_read_rq,
output reg o_write_rq,
input i_ack,
output reg [31:0] o_address,
input [31:0] i_data,
output reg [31:0] o_data,
input i_address_valid
);
reg r_last_n64_pi_alel;
reg r_last_n64_pi_aleh;
reg r_last_n64_pi_read;
reg r_last_n64_pi_write;
reg r_first_transfer;
reg r_word_select;
reg [31:0] r_data_i_buffer;
reg [15:0] r_word_buffer;
reg r_address_valid;
reg r_address_valid_buffer;
wire w_aleh_valid = (&i_n64_pi_alel) && (&i_n64_pi_aleh);
wire w_alel_valid = (&i_n64_pi_alel) && (~|i_n64_pi_aleh);
wire w_address_op = r_last_n64_pi_alel && !i_n64_pi_alel[0] && !i_n64_pi_aleh[0];
wire w_read_op = r_last_n64_pi_read && !i_n64_pi_read;
wire w_write_op = r_last_n64_pi_write && !i_n64_pi_write;
wire w_bus_read_op = w_read_op && r_word_select;
wire w_bus_write_op = w_write_op && !r_word_select;
wire w_address_increment = w_bus_read_op || (w_bus_write_op && !r_first_transfer);
assign o_n64_pi_ad_mode = !i_reset && !i_n64_pi_alel[0] && !i_n64_pi_aleh[0] && !i_n64_pi_read && !r_last_n64_pi_read && r_address_valid;
always @(posedge i_clk) begin
r_last_n64_pi_alel <= i_n64_pi_alel[0];
r_last_n64_pi_aleh <= i_n64_pi_aleh[0];
r_last_n64_pi_read <= i_n64_pi_read;
r_last_n64_pi_write <= i_n64_pi_write;
o_read_rq <= 1'b0;
o_write_rq <= 1'b0;
if (!i_reset) begin
o_read_rq <= w_bus_read_op || w_address_op;
o_write_rq <= w_bus_write_op;
if (w_aleh_valid) begin
o_address <= {i_n64_pi_ad, o_address[15:0]};
end
if (w_alel_valid) begin
o_address <= {o_address[31:16], i_n64_pi_ad[15:1], 1'b0};
end
if (w_address_op) begin
r_first_transfer <= 1'b1;
r_word_select <= 1'b1;
end
if (w_read_op || w_write_op) begin
r_word_select <= ~r_word_select;
o_address <= {o_address[31:10], (o_address[9:0] + {w_address_increment, 2'b00})};
end
if (w_write_op && !r_word_select) begin
r_first_transfer <= 1'b0;
end
if (w_read_op) begin
{o_n64_pi_ad, r_word_buffer} <= r_word_select ? r_data_i_buffer : {r_word_buffer, 16'hXXXX};
end
if (w_write_op) begin
o_data <= {o_data[15:0], i_n64_pi_ad};
end
if (w_bus_read_op) begin
r_address_valid <= r_address_valid_buffer;
end
if (o_read_rq) begin
r_address_valid_buffer <= i_address_valid;
end
if (i_ack) begin
r_data_i_buffer <= i_data;
end
end
end
endmodule