mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-25 15:16:53 +01:00
277 lines
7.8 KiB
Verilog
277 lines
7.8 KiB
Verilog
`include "../constants.vh"
|
|
|
|
module n64_pi (
|
|
input i_clk,
|
|
input i_reset,
|
|
|
|
input i_n64_reset,
|
|
input i_n64_pi_alel,
|
|
input i_n64_pi_aleh,
|
|
input i_n64_pi_read,
|
|
input i_n64_pi_write,
|
|
inout reg [15:0] io_n64_pi_ad,
|
|
|
|
output reg o_request,
|
|
output reg o_write,
|
|
input i_busy,
|
|
input i_ack,
|
|
output [3:0] o_bank,
|
|
output reg [25:0] o_address,
|
|
input [31:0] i_data,
|
|
output reg [31:0] o_data,
|
|
|
|
output o_sram_pi_request,
|
|
output o_flashram_pi_request,
|
|
|
|
input i_ddipl_enable,
|
|
input i_sram_enable,
|
|
input i_flashram_enable,
|
|
input i_sd_enable,
|
|
input i_eeprom_pi_enable,
|
|
|
|
input [23:0] i_ddipl_address,
|
|
input [23:0] i_save_address,
|
|
|
|
input i_flashram_read_mode
|
|
);
|
|
|
|
// Parameters
|
|
|
|
parameter bit PREFETCH_DISABLE = 1'b0;
|
|
|
|
|
|
// Input synchronization
|
|
|
|
reg r_reset_ff1, r_reset_ff2;
|
|
reg r_alel_ff1, r_alel_ff2, r_alel_ff3;
|
|
reg r_aleh_ff1, r_aleh_ff2, r_aleh_ff3;
|
|
reg r_read_ff1, r_read_ff2;
|
|
reg r_write_ff1, r_write_ff2;
|
|
|
|
always @(posedge i_clk) begin
|
|
{r_reset_ff2, r_reset_ff1} <= {r_reset_ff1, i_n64_reset};
|
|
{r_alel_ff3, r_alel_ff2, r_alel_ff1} <= {r_alel_ff2, r_alel_ff1, i_n64_pi_alel};
|
|
{r_aleh_ff3, r_aleh_ff2, r_aleh_ff1} <= {r_aleh_ff2, r_aleh_ff1, i_n64_pi_aleh};
|
|
{r_read_ff2, r_read_ff1} <= {r_read_ff1, i_n64_pi_read};
|
|
{r_write_ff2, r_write_ff1} <= {r_write_ff1, i_n64_pi_write};
|
|
end
|
|
|
|
|
|
// PI event signals generator
|
|
|
|
wire [1:0] w_pi_mode = {r_aleh_ff3, r_alel_ff3};
|
|
reg [1:0] r_last_pi_mode;
|
|
reg r_last_read;
|
|
reg r_last_write;
|
|
|
|
always @(posedge i_clk) begin
|
|
r_last_pi_mode <= w_pi_mode;
|
|
r_last_read <= r_read_ff2;
|
|
r_last_write <= r_write_ff2;
|
|
end
|
|
|
|
localparam [1:0] PI_MODE_IDLE = 2'b10;
|
|
localparam [1:0] PI_MODE_HIGH = 2'b11;
|
|
localparam [1:0] PI_MODE_LOW = 2'b01;
|
|
localparam [1:0] PI_MODE_VALID = 2'b00;
|
|
|
|
wire w_address_high_op = r_reset_ff2 && (r_last_pi_mode != PI_MODE_HIGH) && (w_pi_mode == PI_MODE_HIGH);
|
|
wire w_address_low_op = r_reset_ff2 && (r_last_pi_mode == PI_MODE_HIGH) && (w_pi_mode == PI_MODE_LOW);
|
|
wire w_read_op = r_reset_ff2 && (w_pi_mode == PI_MODE_VALID) && r_last_read && !r_read_ff2;
|
|
wire w_write_op = r_reset_ff2 && (w_pi_mode == PI_MODE_VALID) && r_last_write && !r_write_ff2;
|
|
|
|
reg r_address_valid_op;
|
|
|
|
always @(posedge i_clk) begin
|
|
r_address_valid_op <= w_address_low_op;
|
|
end
|
|
|
|
|
|
// Bank decoder, address translator and prefetch signal
|
|
|
|
wire w_bank_prefetch;
|
|
wire w_ddipl_pi_request;
|
|
|
|
wire w_prefetch = !PREFETCH_DISABLE && w_bank_prefetch;
|
|
|
|
n64_bank_decoder n64_bank_decoder_inst (
|
|
.i_clk(i_clk),
|
|
|
|
.i_address_high_op(w_address_high_op),
|
|
.i_n64_pi_ad(io_n64_pi_ad),
|
|
|
|
.o_bank(o_bank),
|
|
.o_prefetch(w_bank_prefetch),
|
|
.o_ddipl_pi_request(w_ddipl_pi_request),
|
|
.o_sram_pi_request(o_sram_pi_request),
|
|
.o_flashram_pi_request(o_flashram_pi_request),
|
|
|
|
.i_ddipl_enable(i_ddipl_enable),
|
|
.i_sram_enable(i_sram_enable),
|
|
.i_flashram_enable(i_flashram_enable),
|
|
.i_eeprom_pi_enable(i_eeprom_pi_enable),
|
|
.i_sd_enable(i_sd_enable)
|
|
);
|
|
|
|
|
|
// Read/write current word logic
|
|
|
|
reg r_word_counter;
|
|
|
|
wire w_bus_read_op = w_read_op && !r_word_counter;
|
|
wire w_bus_write_op = w_write_op && r_word_counter;
|
|
|
|
always @(posedge i_clk) begin
|
|
if (r_address_valid_op) begin
|
|
r_word_counter <= 1'b0;
|
|
end
|
|
|
|
if (w_read_op || w_write_op) begin
|
|
r_word_counter <= ~r_word_counter;
|
|
end
|
|
end
|
|
|
|
|
|
// N64 PI output data logic
|
|
|
|
reg [31:0] r_pi_output_data;
|
|
|
|
always @(*) begin
|
|
io_n64_pi_ad = 16'hZZZZ;
|
|
if (r_reset_ff2 && !r_read_ff2 && o_bank != `BANK_INVALID) begin
|
|
io_n64_pi_ad = r_word_counter ? r_pi_output_data[31:16] : r_pi_output_data[15:0];
|
|
end
|
|
end
|
|
|
|
|
|
// Read buffer logic
|
|
|
|
reg r_prefetch_read;
|
|
reg [31:0] r_pi_read_buffer;
|
|
|
|
always @(posedge i_clk) begin
|
|
if (r_address_valid_op) begin
|
|
r_prefetch_read <= w_prefetch;
|
|
end
|
|
if (i_ack) begin
|
|
r_prefetch_read <= 1'b0;
|
|
|
|
if (w_prefetch) begin
|
|
r_pi_read_buffer <= i_data;
|
|
end else begin
|
|
r_pi_output_data <= i_data;
|
|
end
|
|
|
|
if (r_prefetch_read) begin
|
|
r_pi_output_data <= i_data;
|
|
end
|
|
end
|
|
if (w_prefetch && w_bus_read_op) begin
|
|
r_pi_output_data <= r_pi_read_buffer;
|
|
end
|
|
end
|
|
|
|
|
|
// Write data logic
|
|
|
|
reg [15:0] r_pi_write_buffer;
|
|
|
|
always @(posedge i_clk) begin
|
|
if (w_write_op) begin
|
|
if (!r_word_counter) begin
|
|
r_pi_write_buffer <= io_n64_pi_ad;
|
|
end else begin
|
|
o_data <= {r_pi_write_buffer, io_n64_pi_ad};
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
// Bus request logic
|
|
|
|
reg r_pending_request;
|
|
reg r_pending_request_write;
|
|
|
|
wire w_bus_request_op = (r_address_valid_op && w_prefetch) || w_bus_read_op || w_bus_write_op;
|
|
wire w_request_successful = o_request && !i_busy;
|
|
|
|
always @(posedge i_clk) begin
|
|
if (i_reset) begin
|
|
o_request <= 1'b0;
|
|
o_write <= 1'b0;
|
|
r_pending_request <= 1'b0;
|
|
end else begin
|
|
if (w_request_successful) begin
|
|
o_request <= 1'b0;
|
|
o_write <= 1'b0;
|
|
end
|
|
|
|
if (w_bus_request_op) begin
|
|
if (o_request) begin
|
|
r_pending_request <= 1'b1;
|
|
r_pending_request_write <= w_bus_write_op;
|
|
end else begin
|
|
o_request <= 1'b1;
|
|
o_write <= w_bus_write_op;
|
|
end
|
|
end
|
|
|
|
if (r_pending_request && !i_busy) begin
|
|
o_request <= 1'b1;
|
|
o_write <= r_pending_request_write;
|
|
r_pending_request <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
// Address latch and increment logic
|
|
|
|
wire [9:0] w_pi_high_address = io_n64_pi_ad[9:0];
|
|
wire [15:0] w_pi_low_address = {io_n64_pi_ad[15:1], 1'b0};
|
|
wire [25:0] w_ddipl_translated_address = o_address + {i_ddipl_address, 2'b00};
|
|
wire [25:0] w_save_translated_address = o_address + {i_save_address, 2'b00};
|
|
|
|
reg r_first_transfer;
|
|
reg [14:0] r_address_low_buffer;
|
|
|
|
always @(posedge i_clk) begin
|
|
if (w_address_high_op) begin
|
|
o_address[25:16] <= w_pi_high_address;
|
|
end
|
|
|
|
if (w_address_low_op) begin
|
|
o_address[15:0] <= w_pi_low_address;
|
|
end
|
|
|
|
if (r_address_valid_op) begin
|
|
r_first_transfer <= w_prefetch;
|
|
r_address_low_buffer <= o_address[15:1];
|
|
|
|
if (w_ddipl_pi_request) begin
|
|
o_address <= w_ddipl_translated_address;
|
|
r_address_low_buffer <= w_ddipl_translated_address[15:1];
|
|
end
|
|
|
|
if (o_sram_pi_request) begin
|
|
o_address <= w_save_translated_address;
|
|
r_address_low_buffer <= w_save_translated_address[15:1];
|
|
end
|
|
|
|
if (o_flashram_pi_request && i_flashram_read_mode) begin
|
|
o_address <= w_save_translated_address;
|
|
end
|
|
end
|
|
|
|
if (w_request_successful) begin
|
|
o_address[15:2] <= o_address[15:2] + 1'd1;
|
|
end
|
|
|
|
if (w_bus_write_op && r_first_transfer) begin
|
|
r_first_transfer <= 1'b0;
|
|
o_address[15:1] <= r_address_low_buffer;
|
|
end
|
|
end
|
|
|
|
endmodule
|