SummerCart64/fw/rtl/n64/n64_pi.sv
Mateusz Faderewski ff69030643
[SC64][FW][HW][SW] New version based on LCMXO2 FPGA (#19)
* isv support + usb/dd improvements

* make room for saves

* update offset

* fixed debug address

* idk

* exception

* ironed out all broken stuff

* cleanup

* return epc fix

* better

* more cleanup

* even more cleanup

* mooore cleanup

* fixed printf

* no assert

* improved docker build, pyft232 instead of pyserial

* fixed displaying long message strings

description test

* just straight cleanup

* smallest cleanup

* PAL

* cpu buffer

* n64 bootloader done

* super slow usb storage reading implemented

* reduced buffer size

* usb gets fast

* little cleanup

* double buffered reads

* removed separate event id

* ISV in hardware finally

* small exception changes

* mac testing

* py spacing

* fsd write, rtc, isv and reset fixes

* fixxx

* good stopping point

* usb fixed?

* pretend we have 128 MB sdram

* backup

* chmod

* test

* test done

* more tests

* user rm

* help

* final fix

* updated component values

* nice asset names

* cic 64dd support

* ddipl enable separation

* pre DMA rewrite, created dedicated buffer memory space, simplified code

* dma rewrite, needs testing

* moved xml

* dd basics

* timing

* 64dd working yet again, isv brought back, dma fixes, usb path rewrite, pc code rewrite

* added usb read functionality, general cleanup

* changed mem addressing

* added fpga flash update access

* added mcu update

* chmod

* little cleanup

* update format and stuff

* fixes

* uninitialized fix

* small fixes

* update fixes

* update stuff done

* fpga update tested

* build time fix

* boot fix

* test timing

* readme test

* test 2

* reports

* testseet

* final

* build test

* forgot

* button and naming

* General cleanup

And multiline commit message test

* Exception screen UI touch ups

* display separation and tests beginning

* pc software update

* pc software done

* timing test

* delete launch.json

* sw fixes

* fixed button hole diameter in shell

* small cleanup, rpi testing

* shell fillet fix, pc rtc printing

* added cfg lock mechanism

* moved lock to cfg address space

* extended ROM and ISV fixes

* preliminary sd card support

* little sd card cleanup

* sd menu fixes

* 5 second limit

* reduced shell thickness

* basic led act blinking

* faster sd menu loading

* inst cache invalidate

* sd card writing is working

* SD card CSD and CID registers

* wait for previous command

* led error codes

* fixed cfg_translate_address use

* 64dd from sd card working

* 64dd speedup and button handling

* delayed address latching cycle - might break other builds, needs testing

* bootloader improvements

* small fixes

* return previous cfg when setting new

* cache stuff

* unfloader debug protocol support

* UNFLoader style debug command line support

* requirements.txt

* shell groove fillet

* reset state inside controller

* fixed fast PI read, added PI R/W fifo debug info

* PI access prioritize

* SD clock stop when RX FIFO is more than half full

* flash erase method change

* CFG error handling, TLOZ MM debug ISV support

* CIC5167 support

* general fixes

* USB unplugged cable handling

* turn off led when changing between error/act modes

* rtc 2 bit clock stop support

* line endings

* Revert "line endings"

This reverts commit d0ddfe5ec716d2db7c72561703f51a94bf34e6bb.

* PI address debug

* readme test

* diagram update

* diagram background

* diagram background

* diagram background

* updated readme
2022-11-10 11:46:54 +01:00

490 lines
15 KiB
Systemverilog

module n64_pi (
input clk,
input reset,
mem_bus.controller mem_bus,
n64_reg_bus.controller reg_bus,
n64_scb.pi n64_scb,
input n64_reset,
input n64_nmi,
input n64_pi_alel,
input n64_pi_aleh,
input n64_pi_read,
input n64_pi_write,
inout [15:0] n64_pi_ad
);
// Control signals and input synchronization
logic [1:0] n64_reset_ff;
logic [1:0] n64_nmi_ff;
logic [3:0] n64_pi_alel_ff;
logic [3:0] n64_pi_aleh_ff;
logic [1:0] n64_pi_read_ff;
logic [2:0] n64_pi_write_ff;
always_ff @(posedge clk) begin
n64_reset_ff <= {n64_reset_ff[0], n64_reset};
n64_nmi_ff <= {n64_nmi_ff[0], n64_nmi};
n64_pi_aleh_ff <= {n64_pi_aleh_ff[2:0], n64_pi_aleh};
n64_pi_alel_ff <= {n64_pi_alel_ff[2:0], n64_pi_alel};
n64_pi_read_ff <= {n64_pi_read_ff[0], n64_pi_read};
n64_pi_write_ff <= {n64_pi_write_ff[1:0], n64_pi_write};
end
logic pi_reset;
logic pi_nmi;
logic pi_aleh;
logic pi_alel;
logic pi_read;
logic pi_write;
always_comb begin
pi_reset = n64_reset_ff[1];
pi_nmi = n64_nmi_ff[1];
pi_aleh = n64_pi_aleh_ff[3];
pi_alel = n64_pi_alel_ff[3];
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;
typedef enum bit [1:0] {
PORT_NONE,
PORT_MEM,
PORT_REG
} e_port;
e_pi_mode pi_mode;
e_port read_port;
e_port write_port;
always_comb begin
pi_mode = e_pi_mode'({pi_aleh, pi_alel});
end
logic last_reset;
logic last_nmi;
e_pi_mode last_pi_mode;
logic last_read;
logic last_write;
always_ff @(posedge clk) begin
last_reset <= pi_reset;
last_nmi <= pi_nmi;
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
n64_scb.n64_reset = !last_reset && pi_reset;
n64_scb.n64_nmi = !last_nmi && pi_nmi;
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) && (read_port != PORT_NONE) && (last_read && !pi_read);
write_op = pi_reset && (pi_mode == PI_MODE_VALID) && (write_port != PORT_NONE) && (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 n64_pi_ad_oe;
logic [15:0] n64_pi_ad_out;
logic [15:0] n64_pi_dq_in;
logic [15:0] n64_pi_dq_out;
assign n64_pi_ad = n64_pi_ad_oe ? n64_pi_ad_out : 16'hZZZZ;
always_ff @(posedge clk) begin
n64_pi_ad_oe <= pi_reset && (pi_mode == PI_MODE_VALID) && !last_read && (read_port != PORT_NONE);
n64_pi_ad_out <= n64_pi_dq_out;
n64_pi_dq_in <= n64_pi_ad;
end
// Debug: last accessed PI address
always_ff @(posedge clk) begin
if (aleh_op) begin
n64_scb.pi_debug[31:16] <= n64_pi_dq_in;
end
if (alel_op) begin
n64_scb.pi_debug[15:0] <= n64_pi_dq_in;
end
end
// Address decoding
const bit [31:0] DDIPL_OFFSET = 32'h03BC_0000;
const bit [31:0] SAVE_OFFSET = 32'h03FE_0000;
const bit [31:0] FLASH_OFFSET = 32'h0400_0000;
const bit [31:0] BOOTLOADER_OFFSET = 32'h04E0_0000;
const bit [31:0] SHADOW_OFFSET = 32'h04FE_0000;
const bit [31:0] BUFFER_OFFSET = 32'h0500_0000;
logic [31:0] mem_offset;
always_ff @(posedge clk) begin
if (reset || !pi_reset || end_op) begin
n64_scb.pi_sdram_active <= 1'b0;
n64_scb.pi_flash_active <= 1'b0;
end
if (reset) begin
read_port <= PORT_NONE;
write_port <= PORT_NONE;
reg_bus.dd_select <= 1'b0;
reg_bus.flashram_select <= 1'b0;
reg_bus.cfg_select <= 1'b0;
end else if (aleh_op) begin
read_port <= PORT_NONE;
write_port <= PORT_NONE;
mem_offset <= 32'd0;
reg_bus.dd_select <= 1'b0;
reg_bus.flashram_select <= 1'b0;
reg_bus.cfg_select <= 1'b0;
if (n64_scb.dd_enabled) begin
if (n64_pi_dq_in == 16'h0500) begin
read_port <= PORT_REG;
write_port <= PORT_REG;
reg_bus.dd_select <= 1'b1;
end
end
if (n64_scb.ddipl_enabled) begin
if (n64_pi_dq_in >= 16'h0600 && n64_pi_dq_in < 16'h0640) begin
read_port <= PORT_MEM;
write_port <= PORT_NONE;
mem_offset <= (-32'h0600_0000) + DDIPL_OFFSET;
n64_scb.pi_sdram_active <= 1'b1;
end
end
if (n64_scb.flashram_enabled) begin
if (n64_pi_dq_in >= 16'h0800 && n64_pi_dq_in < 16'h0802) begin
read_port <= PORT_REG;
write_port <= PORT_REG;
mem_offset <= (-32'h0800_0000) + SAVE_OFFSET;
reg_bus.flashram_select <= 1'b1;
if (n64_scb.flashram_read_mode) begin
read_port <= PORT_MEM;
n64_scb.pi_sdram_active <= 1'b1;
end
end
end else if (n64_scb.sram_enabled) begin
if (n64_scb.sram_banked) begin
if (n64_pi_dq_in >= 16'h0800 && n64_pi_dq_in < 16'h0810) begin
if (n64_pi_dq_in[3:2] != 2'b11 && n64_pi_dq_in[1:0] == 2'b00) begin
read_port <= PORT_MEM;
write_port <= PORT_MEM;
mem_offset <= (-32'h0800_0000) - {n64_pi_dq_in[3:2], 18'd0} + {n64_pi_dq_in[3:2], 15'd0} + SAVE_OFFSET;
n64_scb.pi_sdram_active <= 1'b1;
end
end
end else begin
if (n64_pi_dq_in >= 16'h0800 && n64_pi_dq_in < 16'h0802) begin
read_port <= PORT_MEM;
write_port <= PORT_MEM;
mem_offset <= (-32'h0800_0000) + SAVE_OFFSET;
n64_scb.pi_sdram_active <= 1'b1;
end
end
end
if (n64_scb.bootloader_enabled) begin
if (n64_pi_dq_in >= 16'h1000 && n64_pi_dq_in < 16'h101C) begin
read_port <= PORT_MEM;
write_port <= PORT_NONE;
mem_offset <= (-32'h1000_0000) + BOOTLOADER_OFFSET;
n64_scb.pi_flash_active <= 1'b1;
end
end else begin
if (n64_pi_dq_in >= 16'h1000 && n64_pi_dq_in < 16'h1400) begin
read_port <= PORT_MEM;
write_port <= n64_scb.rom_write_enabled ? PORT_MEM : PORT_NONE;
mem_offset <= (-32'h1000_0000);
n64_scb.pi_sdram_active <= 1'b1;
end
end
if (n64_scb.rom_shadow_enabled) begin
if (n64_pi_dq_in >= 16'h13FE && n64_pi_dq_in < 16'h1400) begin
read_port <= PORT_MEM;
write_port <= PORT_NONE;
mem_offset <= (-32'h13FE_0000) + SHADOW_OFFSET;
n64_scb.pi_flash_active <= 1'b1;
end
end
if (n64_scb.rom_extended_enabled) begin
if (n64_pi_dq_in >= 16'h1400 && n64_pi_dq_in < 16'h14E0) begin
read_port <= PORT_MEM;
write_port <= PORT_NONE;
mem_offset <= (-32'h1400_0000) + FLASH_OFFSET;
n64_scb.pi_flash_active <= 1'b1;
end
end
if (n64_scb.cfg_unlock) begin
if (n64_pi_dq_in >= 16'h1FFC && n64_pi_dq_in < 16'h1FFE) begin
read_port <= PORT_MEM;
write_port <= PORT_NONE;
mem_offset <= (-32'h1FFC_0000) + SHADOW_OFFSET;
n64_scb.pi_flash_active <= 1'b1;
end
if (n64_pi_dq_in >= 16'h1FFE && n64_pi_dq_in < 16'h1FFF) begin
read_port <= PORT_MEM;
write_port <= PORT_MEM;
mem_offset <= (-32'h1FFE_0000) + BUFFER_OFFSET;
end
end
if (n64_pi_dq_in >= 16'h1FFF && n64_pi_dq_in < 16'h2000) begin
read_port <= n64_scb.cfg_unlock ? PORT_REG : PORT_NONE;
write_port <= PORT_REG;
reg_bus.cfg_select <= 1'b1;
end
end
end
// Mem bus read FIFO controller
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;
logic read_fifo_wait;
n64_pi_fifo read_fifo_inst (
.clk(clk),
.reset(reset),
.flush(reset || !pi_reset || alel_op),
.full(read_fifo_full),
.write(read_fifo_write),
.wdata(read_fifo_wdata),
.empty(read_fifo_empty),
.read(read_fifo_read),
.rdata(read_fifo_rdata)
);
always_ff @(posedge clk) begin
read_fifo_read <= 1'b0;
if (!pi_reset) begin
n64_scb.pi_debug[33:32] <= 2'b00;
end
if (reset || !pi_reset || alel_op) begin
read_fifo_wait <= 1'b0;
end
if (read_port == PORT_MEM) begin
if (read_op) begin
if (read_fifo_empty) begin
read_fifo_wait <= 1'b1;
n64_scb.pi_debug[32] <= 1'b1;
if (read_fifo_wait) begin
n64_scb.pi_debug[33] <= 1'b1;
end
end else begin
read_fifo_read <= 1'b1;
n64_pi_dq_out <= read_fifo_rdata;
end
end
if (!read_fifo_empty && read_fifo_wait) begin
read_fifo_read <= 1'b1;
read_fifo_wait <= 1'b0;
n64_pi_dq_out <= read_fifo_rdata;
end
end
if (read_port == PORT_REG) begin
if (read_op) begin
n64_pi_dq_out <= reg_bus.rdata;
end
end
end
// Mem bus write FIFO controller
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;
logic write_fifo_wait;
n64_pi_fifo write_fifo_inst (
.clk(clk),
.reset(reset),
.flush(reset),
.full(write_fifo_full),
.write(write_fifo_write),
.wdata(write_fifo_wdata),
.empty(write_fifo_empty),
.read(write_fifo_read),
.rdata(write_fifo_rdata)
);
always_ff @(posedge clk) begin
write_fifo_write <= 1'b0;
if (!pi_reset) begin
n64_scb.pi_debug[35:34] <= 2'b00;
end
if (reset) begin
write_fifo_wait <= 1'b0;
end
if (write_port == PORT_MEM) begin
if (write_op) begin
if (write_fifo_full) begin
write_fifo_wait <= 1'b1;
n64_scb.pi_debug[34] <= 1'b1;
if (write_fifo_wait) begin
n64_scb.pi_debug[35] <= 1'b1;
end
end else begin
write_fifo_write <= 1'b1;
write_fifo_wdata <= n64_pi_dq_in;
end
end
if (!write_fifo_full && write_fifo_wait) begin
write_fifo_write <= 1'b1;
write_fifo_wait <= 1'b0;
write_fifo_wdata <= n64_pi_dq_in;
end
end
end
// Mem bus controller
logic [31:0] starting_address;
logic load_starting_address;
logic read_enabled;
logic first_write_op;
always_ff @(posedge clk) begin
write_fifo_read <= 1'b0;
load_starting_address <= 1'b0;
if (reset || !pi_reset) begin
mem_bus.request <= 1'b0;
read_enabled <= 1'b0;
end else begin
if (aleh_op) begin
starting_address[31:16] <= n64_pi_dq_in;
end
if (alel_op) begin
starting_address <= {starting_address[31:16], n64_pi_dq_in} + mem_offset;
load_starting_address <= 1'b1;
read_enabled <= 1'b1;
first_write_op <= 1'b1;
end
if (load_starting_address) begin
mem_bus.address <= starting_address;
end
if (!mem_bus.request) begin
if ((write_port == PORT_MEM) && !write_fifo_empty) begin
mem_bus.request <= 1'b1;
mem_bus.write <= 1'b1;
mem_bus.wdata <= write_fifo_rdata;
write_fifo_read <= 1'b1;
read_enabled <= 1'b0;
if (first_write_op) begin
mem_bus.address <= starting_address;
first_write_op <= 1'b0;
end
end else if ((read_port == PORT_MEM) && !read_fifo_full && read_enabled) begin
mem_bus.request <= 1'b1;
mem_bus.write <= 1'b0;
end
end
if (mem_bus.ack) begin
mem_bus.request <= 1'b0;
mem_bus.address[16:0] <= mem_bus.address[16:0] + 2'd2;
end
if (end_op) begin
read_enabled <= 1'b0;
end
end
end
always_comb begin
read_fifo_write = !mem_bus.write && mem_bus.ack;
read_fifo_wdata = mem_bus.rdata;
mem_bus.wmask = 2'b11;
end
// Reg bus controller
always_ff @(posedge clk) begin
if (aleh_op) begin
reg_bus.address[16] <= n64_pi_dq_in[0];
end
if (alel_op) begin
reg_bus.address[15:0] <= n64_pi_dq_in;
end
if (read_op || write_op) begin
reg_bus.address <= reg_bus.address + 2'd2;
end
end
always_comb begin
reg_bus.read = read_op && (read_port == PORT_REG);
reg_bus.write = write_op && (write_port == PORT_REG);
reg_bus.wdata = n64_pi_dq_in;
end
endmodule