mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-12-29 14:31:54 +01:00
368 lines
12 KiB
Systemverilog
368 lines
12 KiB
Systemverilog
module n64_pi (
|
|
if_system.sys sys,
|
|
if_config.pi cfg,
|
|
if_n64_bus.n64 bus,
|
|
|
|
input n64_pi_alel,
|
|
input n64_pi_aleh,
|
|
input n64_pi_read,
|
|
input n64_pi_write,
|
|
inout [15:0] n64_pi_ad
|
|
);
|
|
|
|
// FIFOs
|
|
|
|
logic read_fifo_flush;
|
|
|
|
logic read_fifo_full;
|
|
logic read_fifo_write;
|
|
logic [15:0] read_fifo_wdata;
|
|
|
|
logic read_fifo_empty;
|
|
logic read_fifo_read;
|
|
logic [15:0] read_fifo_rdata;
|
|
|
|
n64_pi_fifo read_fifo_inst (
|
|
.sys(sys),
|
|
|
|
.flush(read_fifo_flush),
|
|
|
|
.full(read_fifo_full),
|
|
.write(read_fifo_write),
|
|
.wdata(read_fifo_wdata),
|
|
|
|
.empty(read_fifo_empty),
|
|
.read(read_fifo_read),
|
|
.rdata(read_fifo_rdata)
|
|
);
|
|
|
|
logic write_fifo_flush;
|
|
|
|
logic write_fifo_full;
|
|
logic write_fifo_write;
|
|
logic [15:0] write_fifo_wdata;
|
|
|
|
logic write_fifo_empty;
|
|
logic write_fifo_read;
|
|
logic [15:0] write_fifo_rdata;
|
|
|
|
n64_pi_fifo write_fifo_inst (
|
|
.sys(sys),
|
|
|
|
.flush(write_fifo_flush),
|
|
|
|
.full(write_fifo_full),
|
|
.write(write_fifo_write),
|
|
.wdata(write_fifo_wdata),
|
|
|
|
.empty(write_fifo_empty),
|
|
.read(write_fifo_read),
|
|
.rdata(write_fifo_rdata)
|
|
);
|
|
|
|
|
|
// Control signals and input synchronization
|
|
|
|
logic [2:0] n64_pi_alel_ff;
|
|
logic [2:0] n64_pi_aleh_ff;
|
|
logic [2:0] n64_pi_read_ff;
|
|
logic [2:0] n64_pi_write_ff;
|
|
|
|
always_ff @(posedge sys.clk) begin
|
|
n64_pi_aleh_ff <= {n64_pi_aleh_ff[1:0], n64_pi_aleh};
|
|
n64_pi_alel_ff <= {n64_pi_alel_ff[1:0], n64_pi_alel};
|
|
n64_pi_read_ff <= {n64_pi_read_ff[1:0], n64_pi_read};
|
|
n64_pi_write_ff <= {n64_pi_write_ff[1:0], n64_pi_write};
|
|
end
|
|
|
|
logic pi_reset;
|
|
logic pi_aleh;
|
|
logic pi_alel;
|
|
logic pi_read;
|
|
logic pi_write;
|
|
|
|
always_comb begin
|
|
pi_reset = sys.n64_hard_reset;
|
|
pi_aleh = n64_pi_aleh_ff[2];
|
|
pi_alel = n64_pi_alel_ff[2];
|
|
pi_read = n64_pi_read_ff[1];
|
|
pi_write = n64_pi_write_ff[2];
|
|
end
|
|
|
|
|
|
// PI bus state and event generator
|
|
|
|
typedef enum bit [1:0] {
|
|
PI_MODE_IDLE = 2'b10,
|
|
PI_MODE_HIGH = 2'b11,
|
|
PI_MODE_LOW = 2'b01,
|
|
PI_MODE_VALID = 2'b00
|
|
} e_pi_mode;
|
|
|
|
e_pi_mode pi_mode;
|
|
e_pi_mode last_pi_mode;
|
|
logic last_read;
|
|
logic last_write;
|
|
|
|
always_comb begin
|
|
pi_mode = e_pi_mode'({pi_aleh, pi_alel});
|
|
end
|
|
|
|
always_ff @(posedge sys.clk) begin
|
|
last_pi_mode <= pi_mode;
|
|
last_read <= pi_read;
|
|
last_write <= pi_write;
|
|
end
|
|
|
|
logic aleh_op;
|
|
logic alel_op;
|
|
logic read_op;
|
|
logic write_op;
|
|
logic end_op;
|
|
|
|
always_comb begin
|
|
aleh_op = !pi_reset && last_pi_mode != PI_MODE_HIGH && pi_mode == PI_MODE_HIGH;
|
|
alel_op = !pi_reset && last_pi_mode == PI_MODE_HIGH && pi_mode == PI_MODE_LOW;
|
|
read_op = !pi_reset && pi_mode == PI_MODE_VALID && last_read && !pi_read;
|
|
write_op = !pi_reset && pi_mode == PI_MODE_VALID && last_write && !pi_write;
|
|
end_op = !pi_reset && last_pi_mode == PI_MODE_VALID && pi_mode != PI_MODE_VALID;
|
|
end
|
|
|
|
|
|
// Input and output data sampling
|
|
|
|
logic [15:0] n64_pi_ad_input;
|
|
logic [15:0] n64_pi_ad_output;
|
|
logic [15:0] n64_pi_ad_output_data;
|
|
logic n64_pi_ad_output_enable;
|
|
logic n64_pi_ad_output_enable_data;
|
|
|
|
logic n64_pi_address_valid;
|
|
logic pending_operation;
|
|
logic pending_write;
|
|
|
|
always_comb begin
|
|
n64_pi_ad = n64_pi_ad_output_enable ? n64_pi_ad_output : 16'hZZZZ;
|
|
n64_pi_ad_output_enable_data = !pi_reset && pi_mode == PI_MODE_VALID && n64_pi_address_valid && !n64_pi_read_ff[2];
|
|
end
|
|
|
|
always_ff @(posedge sys.clk) begin
|
|
n64_pi_ad_input <= n64_pi_ad;
|
|
n64_pi_ad_output <= n64_pi_ad_output_data;
|
|
n64_pi_ad_output_enable <= n64_pi_ad_output_enable_data;
|
|
end
|
|
|
|
logic wait_for_read_fifo;
|
|
logic wait_for_write_fifo;
|
|
|
|
always_comb begin
|
|
read_fifo_write = bus.ack && !bus.write;
|
|
read_fifo_wdata = bus.rdata;
|
|
|
|
write_fifo_wdata = n64_pi_ad_input;
|
|
end
|
|
|
|
always_ff @(posedge sys.clk) begin
|
|
read_fifo_read <= 1'b0;
|
|
write_fifo_write <= 1'b0;
|
|
|
|
if (sys.reset || sys.n64_hard_reset) begin
|
|
wait_for_read_fifo <= 1'b0;
|
|
wait_for_write_fifo <= 1'b0;
|
|
end else if (n64_pi_address_valid) begin
|
|
if (read_op || wait_for_read_fifo) begin
|
|
if (read_fifo_empty) begin
|
|
wait_for_read_fifo <= 1'b1;
|
|
end else begin
|
|
n64_pi_ad_output_data <= read_fifo_rdata;
|
|
read_fifo_read <= 1'b1;
|
|
wait_for_read_fifo <= 1'b0;
|
|
end
|
|
end
|
|
if (write_op || wait_for_write_fifo) begin
|
|
if (write_fifo_full) begin
|
|
wait_for_write_fifo <= 1'b1;
|
|
end else begin
|
|
write_fifo_write <= 1'b1;
|
|
wait_for_write_fifo <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
bus.n64_active = !pi_reset && pi_mode != PI_MODE_IDLE;
|
|
bus.read_op = read_op;
|
|
bus.write_op = write_op;
|
|
end
|
|
|
|
always_ff @(posedge sys.clk) begin
|
|
if (aleh_op) begin
|
|
bus.real_address[31:16] <= n64_pi_ad_input;
|
|
end
|
|
if (alel_op) begin
|
|
bus.real_address[15:0] <= {n64_pi_ad_input[15:1], 1'b0};
|
|
end
|
|
if (read_op || write_op) begin
|
|
bus.real_address <= bus.real_address + 2'd2;
|
|
end
|
|
end
|
|
|
|
|
|
// Address decoding
|
|
|
|
sc64::e_n64_id next_id;
|
|
logic [31:0] next_offset;
|
|
logic sram_selected;
|
|
logic cfg_selected;
|
|
|
|
always_ff @(posedge sys.clk) begin
|
|
if (aleh_op) begin
|
|
n64_pi_address_valid <= 1'b0;
|
|
next_id <= sc64::__ID_N64_END;
|
|
next_offset <= 32'd0;
|
|
sram_selected <= 1'b0;
|
|
cfg_selected <= 1'b0;
|
|
if (cfg.dd_enabled) begin
|
|
if (n64_pi_ad_input == 16'h0500) begin
|
|
n64_pi_address_valid <= 1'b1;
|
|
next_id <= sc64::ID_N64_DD;
|
|
end
|
|
if (n64_pi_ad_input >= 16'h0600 && n64_pi_ad_input < 16'h0640) begin
|
|
n64_pi_address_valid <= 1'b1;
|
|
next_id <= sc64::ID_N64_SDRAM;
|
|
next_offset <= cfg.ddipl_offset + 32'h0A00_0000;
|
|
end
|
|
end
|
|
if (cfg.flashram_enabled) begin
|
|
if (n64_pi_ad_input >= 16'h0800 && n64_pi_ad_input < 16'h0802) begin
|
|
n64_pi_address_valid <= 1'b1;
|
|
next_id <= sc64::ID_N64_FLASHRAM;
|
|
if (cfg.flashram_read_mode) begin
|
|
next_offset <= cfg.save_offset + 32'h0800_0000;
|
|
end
|
|
end
|
|
end else if (cfg.sram_enabled) begin
|
|
if (cfg.sram_banked) begin
|
|
if (n64_pi_ad_input >= 16'h0800 && n64_pi_ad_input < 16'h0810) begin
|
|
if (n64_pi_ad_input[3:2] != 2'b11 && n64_pi_ad_input[1:0] == 2'b00) begin
|
|
n64_pi_address_valid <= 1'b1;
|
|
next_id <= sc64::ID_N64_SDRAM;
|
|
next_offset <= cfg.save_offset - {n64_pi_ad_input[3:2], 18'd0} + {n64_pi_ad_input[3:2], 15'd0} + 32'h0800_0000;
|
|
sram_selected <= 1'b1;
|
|
end
|
|
end
|
|
end else begin
|
|
if (n64_pi_ad_input == 16'h0800) begin
|
|
n64_pi_address_valid <= 1'b1;
|
|
next_id <= sc64::ID_N64_SDRAM;
|
|
next_offset <= cfg.save_offset + 32'h0800_0000;
|
|
sram_selected <= 1'b1;
|
|
end
|
|
end
|
|
end
|
|
if (n64_pi_ad_input >= 16'h1000 && n64_pi_ad_input < 16'h1400) begin
|
|
n64_pi_address_valid <= 1'b1;
|
|
next_id <= cfg.sdram_switch ? sc64::ID_N64_SDRAM : sc64::ID_N64_BOOTLOADER;
|
|
end
|
|
if (n64_pi_ad_input == 16'h1FFF) begin
|
|
n64_pi_address_valid <= 1'b1;
|
|
next_id <= sc64::ID_N64_CFG;
|
|
cfg_selected <= 1'b1;
|
|
end
|
|
end
|
|
if (alel_op) begin
|
|
if (next_id == sc64::ID_N64_DD) begin
|
|
if (|n64_pi_ad_input[15:11]) begin
|
|
n64_pi_address_valid <= 1'b0;
|
|
end
|
|
end
|
|
if (sram_selected) begin
|
|
if (n64_pi_ad_input[15]) begin
|
|
n64_pi_address_valid <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
// Bus controller
|
|
|
|
logic can_read;
|
|
logic first_write_op;
|
|
logic load_starting_address;
|
|
sc64::e_n64_id starting_id;
|
|
logic [31:0] starting_address;
|
|
|
|
always_ff @(posedge sys.clk) begin
|
|
read_fifo_flush <= 1'b0;
|
|
|
|
write_fifo_read <= 1'b0;
|
|
|
|
if (sys.reset || sys.n64_hard_reset) begin
|
|
bus.request <= 1'b0;
|
|
read_fifo_flush <= 1'b1;
|
|
write_fifo_flush <= 1'b1;
|
|
end else begin
|
|
write_fifo_flush <= starting_id == sc64::ID_N64_SDRAM && !cfg.sdram_writable && !sram_selected;
|
|
|
|
if (aleh_op) begin
|
|
starting_address[31:16] <= n64_pi_ad_input;
|
|
end
|
|
|
|
if (alel_op) begin
|
|
read_fifo_flush <= 1'b1;
|
|
can_read <= 1'b1;
|
|
first_write_op <= 1'b1;
|
|
load_starting_address <= 1'b1;
|
|
starting_id <= next_id;
|
|
starting_address <= {starting_address[31:16], n64_pi_ad_input[15:1], 1'b0};
|
|
end
|
|
|
|
if (write_op) begin
|
|
can_read <= 1'b0;
|
|
if (first_write_op) begin
|
|
first_write_op <= 1'b0;
|
|
load_starting_address <= 1'b1;
|
|
end
|
|
end
|
|
|
|
if (!bus.request) begin
|
|
if (!write_fifo_empty) begin
|
|
bus.request <= 1'b1;
|
|
bus.write <= 1'b1;
|
|
if (load_starting_address) begin
|
|
bus.id <= starting_id;
|
|
bus.address <= starting_address + next_offset;
|
|
if (starting_id == sc64::ID_N64_FLASHRAM) begin
|
|
bus.address <= starting_address;
|
|
end
|
|
load_starting_address <= 1'b0;
|
|
end
|
|
bus.wdata <= write_fifo_rdata;
|
|
write_fifo_read <= 1'b1;
|
|
end else if (!read_fifo_full && can_read) begin
|
|
bus.request <= 1'b1;
|
|
bus.write <= 1'b0;
|
|
if (load_starting_address) begin
|
|
bus.id <= starting_id;
|
|
bus.address <= starting_address + next_offset;
|
|
if (starting_id == sc64::ID_N64_FLASHRAM && cfg.flashram_read_mode) begin
|
|
bus.id <= sc64::ID_N64_SDRAM;
|
|
end
|
|
load_starting_address <= 1'b0;
|
|
end
|
|
end
|
|
end else if (bus.ack) begin
|
|
bus.request <= 1'b0;
|
|
bus.address <= bus.address + 2'd2;
|
|
end
|
|
|
|
if (end_op) begin
|
|
can_read <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
endmodule
|