mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-12-26 04:51:56 +01:00
955 lines
29 KiB
Systemverilog
955 lines
29 KiB
Systemverilog
module mcu_top (
|
|
input clk,
|
|
input reset,
|
|
|
|
n64_scb.controller n64_scb,
|
|
dd_scb.controller dd_scb,
|
|
usb_scb.controller usb_scb,
|
|
dma_scb.controller usb_dma_scb,
|
|
sd_scb.controller sd_scb,
|
|
dma_scb.controller sd_dma_scb,
|
|
flash_scb.controller flash_scb,
|
|
vendor_scb.controller vendor_scb,
|
|
|
|
fifo_bus.controller fifo_bus,
|
|
mem_bus.controller mem_bus,
|
|
|
|
input sd_det,
|
|
input button,
|
|
|
|
output logic mcu_int,
|
|
input mcu_clk,
|
|
input mcu_cs,
|
|
input mcu_mosi,
|
|
output mcu_miso
|
|
);
|
|
|
|
// Button input synchronization
|
|
|
|
logic [2:0] sd_det_ff;
|
|
logic [2:0] button_ff;
|
|
|
|
always_ff @(posedge clk) begin
|
|
sd_det_ff <= {sd_det_ff[1:0], sd_det};
|
|
button_ff <= {button_ff[1:0], button};
|
|
end
|
|
|
|
|
|
// MCU <-> FPGA transport
|
|
|
|
logic frame_start;
|
|
logic data_ready;
|
|
logic [7:0] rdata;
|
|
logic [7:0] wdata;
|
|
|
|
mcu_spi mcu_spi_inst (
|
|
.clk(clk),
|
|
.reset(reset),
|
|
|
|
.frame_start(frame_start),
|
|
.data_ready(data_ready),
|
|
.rx_data(rdata),
|
|
.tx_data(wdata),
|
|
|
|
.mcu_clk(mcu_clk),
|
|
.mcu_cs(mcu_cs),
|
|
.mcu_mosi(mcu_mosi),
|
|
.mcu_miso(mcu_miso)
|
|
);
|
|
|
|
|
|
// Protocol controller
|
|
|
|
const bit [7:0] FPGA_ID = 8'h64;
|
|
|
|
typedef enum bit [1:0] {
|
|
PHASE_CMD,
|
|
PHASE_ADDRESS,
|
|
PHASE_DATA,
|
|
PHASE_NOP
|
|
} phase_e;
|
|
|
|
typedef enum bit [7:0] {
|
|
CMD_IDENTIFY,
|
|
CMD_REG_READ,
|
|
CMD_REG_WRITE,
|
|
CMD_MEM_READ,
|
|
CMD_MEM_WRITE,
|
|
CMD_USB_STATUS,
|
|
CMD_USB_READ,
|
|
CMD_USB_WRITE
|
|
} cmd_e;
|
|
|
|
phase_e phase;
|
|
cmd_e cmd;
|
|
|
|
logic [1:0] counter;
|
|
logic [7:0] address;
|
|
|
|
logic reg_read;
|
|
logic reg_write;
|
|
logic [31:0] reg_rdata;
|
|
logic [31:0] reg_wdata;
|
|
|
|
logic mem_read;
|
|
logic mem_write;
|
|
logic [15:0] mem_rdata;
|
|
logic [15:0] mem_wdata;
|
|
logic mem_word_select;
|
|
|
|
always_ff @(posedge clk) begin
|
|
fifo_bus.rx_read <= 1'b0;
|
|
fifo_bus.tx_write <= 1'b0;
|
|
|
|
reg_read <= 1'b0;
|
|
reg_write <= 1'b0;
|
|
|
|
mem_read <= 1'b0;
|
|
mem_write <= 1'b0;
|
|
|
|
if (reset) begin
|
|
end else begin
|
|
if (frame_start) begin
|
|
counter <= 2'd0;
|
|
phase <= PHASE_CMD;
|
|
end
|
|
|
|
if (reg_read || reg_write || (mem_word_select && (mem_read || mem_write))) begin
|
|
address <= address + 1'd1;
|
|
end
|
|
|
|
if (data_ready) begin
|
|
case (phase)
|
|
PHASE_CMD: begin
|
|
cmd <= cmd_e'(rdata);
|
|
phase <= PHASE_ADDRESS;
|
|
|
|
if (rdata == CMD_USB_STATUS) begin
|
|
phase <= PHASE_NOP;
|
|
end
|
|
|
|
if (rdata == CMD_USB_READ) begin
|
|
fifo_bus.rx_read <= 1'b1;
|
|
phase <= PHASE_DATA;
|
|
end
|
|
|
|
if (rdata == CMD_USB_WRITE) begin
|
|
phase <= PHASE_DATA;
|
|
end
|
|
end
|
|
|
|
PHASE_ADDRESS: begin
|
|
address <= rdata;
|
|
phase <= PHASE_DATA;
|
|
|
|
if (cmd == CMD_REG_READ) begin
|
|
reg_read <= 1'b1;
|
|
end
|
|
|
|
if (cmd == CMD_MEM_READ) begin
|
|
mem_read <= 1'b1;
|
|
mem_word_select <= 1'b0;
|
|
end
|
|
end
|
|
|
|
PHASE_DATA: begin
|
|
counter <= counter + 1'd1;
|
|
|
|
if (cmd == CMD_REG_READ) begin
|
|
if (counter == 2'd3) begin
|
|
reg_read <= 1'd1;
|
|
end
|
|
end
|
|
|
|
if (cmd == CMD_REG_WRITE) begin
|
|
case (counter)
|
|
2'd0: reg_wdata[7:0] <= rdata;
|
|
2'd1: reg_wdata[15:8] <= rdata;
|
|
2'd2: reg_wdata[23:16] <= rdata;
|
|
2'd3: reg_wdata[31:24] <= rdata;
|
|
endcase
|
|
if (counter == 2'd3) begin
|
|
reg_write <= 1'd1;
|
|
end
|
|
end
|
|
|
|
if (cmd == CMD_MEM_READ) begin
|
|
if (counter[0]) begin
|
|
mem_read <= 1'b1;
|
|
mem_word_select <= ~mem_word_select;
|
|
end
|
|
end
|
|
|
|
if (cmd == CMD_MEM_WRITE) begin
|
|
case (counter[0])
|
|
1'd0: mem_wdata[15:8] <= rdata;
|
|
1'd1: mem_wdata[7:0] <= rdata;
|
|
endcase
|
|
if (counter[0]) begin
|
|
mem_write <= 1'b1;
|
|
mem_word_select <= counter[1];
|
|
end
|
|
end
|
|
|
|
if (cmd == CMD_USB_READ) begin
|
|
phase <= PHASE_NOP;
|
|
end
|
|
|
|
if (cmd == CMD_USB_WRITE) begin
|
|
fifo_bus.tx_write <= 1'b1;
|
|
fifo_bus.tx_wdata <= rdata;
|
|
phase <= PHASE_NOP;
|
|
end
|
|
end
|
|
|
|
PHASE_NOP: begin end
|
|
endcase
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
wdata = 8'h00;
|
|
|
|
case (cmd)
|
|
CMD_IDENTIFY: begin
|
|
wdata = FPGA_ID;
|
|
end
|
|
|
|
CMD_REG_READ: begin
|
|
case (counter)
|
|
2'd0: wdata = reg_rdata[7:0];
|
|
2'd1: wdata = reg_rdata[15:8];
|
|
2'd2: wdata = reg_rdata[23:16];
|
|
2'd3: wdata = reg_rdata[31:24];
|
|
endcase
|
|
end
|
|
|
|
CMD_REG_WRITE: begin
|
|
wdata = 8'h00;
|
|
end
|
|
|
|
CMD_MEM_READ: begin
|
|
case (counter[0])
|
|
1'd0: wdata = mem_rdata[15:8];
|
|
1'd1: wdata = mem_rdata[7:0];
|
|
endcase
|
|
end
|
|
|
|
CMD_MEM_WRITE: begin
|
|
wdata = 8'h00;
|
|
end
|
|
|
|
CMD_USB_STATUS: begin
|
|
wdata = {6'd0, ~fifo_bus.tx_full, ~fifo_bus.rx_empty};
|
|
end
|
|
|
|
CMD_USB_READ: begin
|
|
wdata = fifo_bus.rx_rdata;
|
|
end
|
|
|
|
CMD_USB_WRITE: begin
|
|
wdata = 8'h00;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
|
|
// Mem bus controller
|
|
|
|
logic [15:0] mem_buffer [0:511];
|
|
|
|
logic mem_start;
|
|
logic mem_stop;
|
|
logic mem_direction;
|
|
logic [8:0] mem_length;
|
|
logic [31:0] mem_address;
|
|
|
|
logic mem_busy;
|
|
logic mem_stop_pending;
|
|
logic [8:0] mem_counter;
|
|
|
|
always_ff @(posedge clk) begin
|
|
if (reset) begin
|
|
mem_busy <= 1'b0;
|
|
mem_stop_pending <= 1'b0;
|
|
mem_bus.request <= 1'b0;
|
|
end else begin
|
|
if (mem_read) begin
|
|
mem_rdata <= mem_buffer[{address, mem_word_select}];
|
|
end
|
|
|
|
if (mem_write) begin
|
|
mem_buffer[{address, mem_word_select}] <= mem_wdata;
|
|
end
|
|
|
|
if (mem_stop) begin
|
|
mem_stop_pending <= mem_busy;
|
|
end else if (mem_start && !mem_busy) begin
|
|
mem_bus.write <= mem_direction;
|
|
mem_bus.address <= mem_address;
|
|
mem_busy <= 1'b1;
|
|
mem_counter <= 9'd0;
|
|
end
|
|
|
|
if (mem_busy) begin
|
|
if (!mem_bus.request) begin
|
|
mem_bus.request <= 1'b1;
|
|
mem_bus.wdata <= mem_buffer[mem_counter];
|
|
end
|
|
|
|
if (mem_bus.ack) begin
|
|
mem_bus.request <= 1'b0;
|
|
mem_bus.address <= mem_bus.address + 2'd2;
|
|
mem_counter <= mem_counter + 1'd1;
|
|
if (!mem_bus.write) begin
|
|
mem_buffer[mem_counter] <= mem_bus.rdata;
|
|
end
|
|
if ((mem_counter == mem_length) || mem_stop_pending) begin
|
|
mem_busy <= 1'b0;
|
|
mem_stop_pending <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
mem_bus.wmask = 2'b11;
|
|
end
|
|
|
|
|
|
// Register list
|
|
|
|
typedef enum bit [7:0] {
|
|
REG_MEM_ADDRESS,
|
|
REG_MEM_SCR,
|
|
REG_USB_SCR,
|
|
REG_USB_DMA_ADDRESS,
|
|
REG_USB_DMA_LENGTH,
|
|
REG_USB_DMA_SCR,
|
|
REG_CFG_SCR,
|
|
REG_CFG_DATA_0,
|
|
REG_CFG_DATA_1,
|
|
REG_CFG_CMD,
|
|
REG_CFG_IDENTIFIER,
|
|
REG_FLASHRAM_SCR,
|
|
REG_FLASH_SCR,
|
|
REG_RTC_SCR,
|
|
REG_RTC_TIME_0,
|
|
REG_RTC_TIME_1,
|
|
REG_SD_SCR,
|
|
REG_SD_ARG,
|
|
REG_SD_CMD,
|
|
REG_SD_RSP_0,
|
|
REG_SD_RSP_1,
|
|
REG_SD_RSP_2,
|
|
REG_SD_RSP_3,
|
|
REG_SD_DAT,
|
|
REG_SD_DMA_ADDRESS,
|
|
REG_SD_DMA_LENGTH,
|
|
REG_SD_DMA_SCR,
|
|
REG_DD_SCR,
|
|
REG_DD_CMD_DATA,
|
|
REG_DD_HEAD_TRACK,
|
|
REG_DD_SECTOR_INFO,
|
|
REG_DD_DRIVE_ID,
|
|
REG_SAVE_COUNT,
|
|
REG_VENDOR_SCR,
|
|
REG_VENDOR_DATA,
|
|
REG_DEBUG_0,
|
|
REG_DEBUG_1,
|
|
REG_CIC_0,
|
|
REG_CIC_1
|
|
} reg_address_e;
|
|
|
|
logic bootloader_skip;
|
|
|
|
assign n64_scb.cfg_identifier = 32'h53437632;
|
|
assign usb_dma_scb.byte_swap = 1'b0;
|
|
|
|
logic dd_bm_ack;
|
|
|
|
logic cic_invalid_region;
|
|
|
|
|
|
// Register read logic
|
|
|
|
always_ff @(posedge clk) begin
|
|
if (reg_read) begin
|
|
reg_rdata <= 32'd0;
|
|
|
|
case (address)
|
|
REG_MEM_ADDRESS: begin
|
|
reg_rdata <= mem_address;
|
|
end
|
|
|
|
REG_MEM_SCR: begin
|
|
reg_rdata <= {
|
|
28'd0,
|
|
mem_busy,
|
|
3'b000
|
|
};
|
|
end
|
|
|
|
REG_USB_SCR: begin
|
|
reg_rdata <= {
|
|
1'd0,
|
|
usb_scb.fifo_flush_busy,
|
|
usb_scb.pwrsav,
|
|
usb_scb.reset_state,
|
|
usb_scb.tx_count,
|
|
usb_scb.rx_count,
|
|
3'b000,
|
|
~fifo_bus.tx_full,
|
|
~fifo_bus.rx_empty,
|
|
1'b0
|
|
};
|
|
end
|
|
|
|
REG_USB_DMA_ADDRESS: begin
|
|
reg_rdata <= {
|
|
5'd0,
|
|
usb_dma_scb.starting_address
|
|
};
|
|
end
|
|
|
|
REG_USB_DMA_LENGTH: begin
|
|
reg_rdata <= {
|
|
5'd0,
|
|
usb_dma_scb.transfer_length
|
|
};
|
|
end
|
|
|
|
REG_USB_DMA_SCR: begin
|
|
reg_rdata <= {
|
|
28'd0,
|
|
usb_dma_scb.busy,
|
|
usb_dma_scb.direction,
|
|
2'b00
|
|
};
|
|
end
|
|
|
|
REG_CFG_SCR: begin
|
|
reg_rdata <= {
|
|
~button_ff[2],
|
|
19'd0,
|
|
n64_scb.rom_extended_enabled,
|
|
n64_scb.eeprom_16k_mode,
|
|
n64_scb.eeprom_enabled,
|
|
n64_scb.ddipl_enabled,
|
|
n64_scb.dd_enabled,
|
|
n64_scb.flashram_enabled,
|
|
n64_scb.sram_banked,
|
|
n64_scb.sram_enabled,
|
|
n64_scb.rom_shadow_enabled,
|
|
n64_scb.rom_write_enabled,
|
|
bootloader_skip,
|
|
n64_scb.bootloader_enabled
|
|
};
|
|
end
|
|
|
|
REG_CFG_DATA_0: begin
|
|
reg_rdata <= n64_scb.cfg_rdata[0];
|
|
end
|
|
|
|
REG_CFG_DATA_1: begin
|
|
reg_rdata <= n64_scb.cfg_rdata[1];
|
|
end
|
|
|
|
REG_CFG_CMD: begin
|
|
reg_rdata <= {
|
|
23'd0,
|
|
n64_scb.cfg_pending,
|
|
n64_scb.cfg_cmd
|
|
};
|
|
end
|
|
|
|
REG_CFG_IDENTIFIER: begin
|
|
reg_rdata <= n64_scb.cfg_identifier;
|
|
end
|
|
|
|
REG_FLASHRAM_SCR: begin
|
|
reg_rdata <= {
|
|
18'd0,
|
|
n64_scb.flashram_write_or_erase,
|
|
n64_scb.flashram_sector_or_all,
|
|
n64_scb.flashram_page,
|
|
n64_scb.flashram_pending,
|
|
1'b0
|
|
};
|
|
end
|
|
|
|
REG_FLASH_SCR: begin
|
|
reg_rdata <= {
|
|
31'd0,
|
|
flash_scb.erase_pending
|
|
};
|
|
end
|
|
|
|
REG_RTC_SCR: begin
|
|
reg_rdata <= {
|
|
24'h525443,
|
|
7'd0,
|
|
n64_scb.rtc_pending
|
|
};
|
|
end
|
|
|
|
REG_RTC_TIME_0: begin
|
|
reg_rdata <= {
|
|
5'd0, n64_scb.rtc_rdata[28:26],
|
|
2'd0, n64_scb.rtc_rdata[19:14],
|
|
1'd0, n64_scb.rtc_rdata[13:7],
|
|
1'd0, n64_scb.rtc_rdata[6:0]
|
|
};
|
|
end
|
|
|
|
REG_RTC_TIME_1: begin
|
|
reg_rdata <= {
|
|
7'd0, n64_scb.rtc_rdata[42],
|
|
n64_scb.rtc_rdata[41:34],
|
|
3'd0, n64_scb.rtc_rdata[33:29],
|
|
2'd0, n64_scb.rtc_rdata[25:20]
|
|
};
|
|
end
|
|
|
|
REG_SD_SCR: begin
|
|
reg_rdata <= {
|
|
4'd0,
|
|
sd_scb.tx_count,
|
|
sd_scb.rx_count,
|
|
~sd_det_ff[2],
|
|
sd_scb.card_busy,
|
|
sd_scb.cmd_error,
|
|
sd_scb.cmd_busy,
|
|
sd_scb.clock_mode
|
|
};
|
|
end
|
|
|
|
REG_SD_ARG: begin
|
|
reg_rdata <= sd_scb.cmd_arg;
|
|
end
|
|
|
|
REG_SD_CMD: begin
|
|
reg_rdata <= {
|
|
22'd0,
|
|
sd_scb.cmd_ignore_crc,
|
|
sd_scb.cmd_long_response,
|
|
sd_scb.cmd_reserved_response,
|
|
sd_scb.cmd_skip_response,
|
|
sd_scb.cmd_index
|
|
};
|
|
end
|
|
|
|
REG_SD_RSP_0: begin
|
|
reg_rdata <= sd_scb.cmd_rsp[31:0];
|
|
end
|
|
|
|
REG_SD_RSP_1: begin
|
|
reg_rdata <= sd_scb.cmd_rsp[63:32];
|
|
end
|
|
|
|
REG_SD_RSP_2: begin
|
|
reg_rdata <= sd_scb.cmd_rsp[95:64];
|
|
end
|
|
|
|
REG_SD_RSP_3: begin
|
|
reg_rdata <= sd_scb.cmd_rsp[127:96];
|
|
end
|
|
|
|
REG_SD_DAT: begin
|
|
reg_rdata <= {
|
|
18'd0,
|
|
sd_scb.dat_error,
|
|
sd_scb.dat_busy,
|
|
12'd0
|
|
};
|
|
end
|
|
|
|
REG_SD_DMA_ADDRESS: begin
|
|
reg_rdata <= {
|
|
5'd0,
|
|
sd_dma_scb.starting_address
|
|
};
|
|
end
|
|
|
|
REG_SD_DMA_LENGTH: begin
|
|
reg_rdata <= {
|
|
5'd0,
|
|
sd_dma_scb.transfer_length
|
|
};
|
|
end
|
|
|
|
REG_SD_DMA_SCR: begin
|
|
reg_rdata <= {
|
|
27'd0,
|
|
sd_dma_scb.byte_swap,
|
|
sd_dma_scb.busy,
|
|
sd_dma_scb.direction,
|
|
2'b00
|
|
};
|
|
end
|
|
|
|
REG_DD_SCR: begin
|
|
reg_rdata <= {
|
|
14'd0,
|
|
dd_bm_ack,
|
|
dd_scb.bm_micro_error,
|
|
dd_scb.bm_transfer_c2,
|
|
dd_scb.bm_transfer_data,
|
|
dd_scb.bm_transfer_blocks,
|
|
dd_scb.bm_transfer_mode,
|
|
1'b0,
|
|
dd_scb.bm_stop_pending,
|
|
1'b0,
|
|
dd_scb.bm_start_pending,
|
|
dd_scb.disk_changed,
|
|
dd_scb.disk_inserted,
|
|
1'b0,
|
|
dd_scb.bm_pending,
|
|
1'b0,
|
|
dd_scb.cmd_pending,
|
|
1'b0,
|
|
dd_scb.hard_reset
|
|
};
|
|
end
|
|
|
|
REG_DD_CMD_DATA: begin
|
|
reg_rdata <= {8'd0, dd_scb.cmd, dd_scb.data};
|
|
end
|
|
|
|
REG_DD_HEAD_TRACK: begin
|
|
reg_rdata <= {18'd0, dd_scb.index_lock, dd_scb.head_track};
|
|
end
|
|
|
|
REG_DD_SECTOR_INFO: begin
|
|
reg_rdata <= {
|
|
dd_scb.sectors_in_block,
|
|
dd_scb.sector_size_full,
|
|
dd_scb.sector_size,
|
|
dd_scb.sector_num
|
|
};
|
|
end
|
|
|
|
REG_SAVE_COUNT: begin
|
|
reg_rdata <= {16'd0, n64_scb.save_count};
|
|
end
|
|
|
|
REG_VENDOR_SCR: begin
|
|
reg_rdata <= vendor_scb.control_rdata;
|
|
end
|
|
|
|
REG_VENDOR_DATA: begin
|
|
reg_rdata <= vendor_scb.data_rdata;
|
|
end
|
|
|
|
REG_DEBUG_0: begin
|
|
reg_rdata <= n64_scb.pi_debug[31:0];
|
|
end
|
|
|
|
REG_DEBUG_1: begin
|
|
reg_rdata <= {
|
|
24'd0,
|
|
n64_scb.cic_debug,
|
|
n64_scb.pi_debug[35:32]
|
|
};
|
|
end
|
|
|
|
REG_CIC_0: begin
|
|
reg_rdata <= {
|
|
4'd0,
|
|
cic_invalid_region,
|
|
n64_scb.cic_disabled,
|
|
n64_scb.cic_64dd_mode,
|
|
n64_scb.cic_region,
|
|
n64_scb.cic_seed,
|
|
n64_scb.cic_checksum[47:32]
|
|
};
|
|
end
|
|
|
|
REG_CIC_1: begin
|
|
reg_rdata <= n64_scb.cic_checksum[31:0];
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
|
|
// Register write logic
|
|
|
|
always_ff @(posedge clk) begin
|
|
mem_start <= 1'b0;
|
|
mem_stop <= 1'b0;
|
|
|
|
usb_scb.fifo_flush <= 1'b0;
|
|
usb_scb.write_buffer_flush <= 1'b0;
|
|
usb_scb.reset_on_ack <= 1'b0;
|
|
usb_scb.reset_off_ack <= 1'b0;
|
|
|
|
usb_dma_scb.start <= 1'b0;
|
|
usb_dma_scb.stop <= 1'b0;
|
|
|
|
sd_scb.cmd_start <= 1'b0;
|
|
sd_scb.dat_fifo_flush <= 1'b0;
|
|
sd_scb.dat_start_write <= 1'b0;
|
|
sd_scb.dat_start_read <= 1'b0;
|
|
sd_scb.dat_stop <= 1'b0;
|
|
|
|
sd_dma_scb.start <= 1'b0;
|
|
sd_dma_scb.stop <= 1'b0;
|
|
|
|
n64_scb.cfg_done <= 1'b0;
|
|
n64_scb.cfg_error <= 1'b0;
|
|
n64_scb.cfg_irq <= 1'b0;
|
|
|
|
n64_scb.flashram_done <= 1'b0;
|
|
|
|
n64_scb.rtc_done <= 1'b0;
|
|
|
|
dd_scb.hard_reset_clear <= 1'b0;
|
|
dd_scb.cmd_ready <= 1'b0;
|
|
dd_scb.bm_start_clear <= 1'b0;
|
|
dd_scb.bm_stop_clear <= 1'b0;
|
|
dd_scb.bm_clear <= 1'b0;
|
|
dd_scb.bm_ready <= 1'b0;
|
|
|
|
vendor_scb.control_valid <= 1'b0;
|
|
|
|
if (n64_scb.n64_nmi) begin
|
|
n64_scb.bootloader_enabled <= !bootloader_skip;
|
|
end
|
|
|
|
if (flash_scb.erase_done) begin
|
|
flash_scb.erase_pending <= 1'b0;
|
|
end
|
|
|
|
if (dd_scb.bm_interrupt_ack) begin
|
|
dd_bm_ack <= 1'b1;
|
|
end
|
|
|
|
if (n64_scb.cic_invalid_region) begin
|
|
cic_invalid_region <= 1'b1;
|
|
end
|
|
|
|
if (reset) begin
|
|
mcu_int <= 1'b0;
|
|
sd_scb.clock_mode <= 2'd0;
|
|
n64_scb.rom_extended_enabled <= 1'b0;
|
|
n64_scb.eeprom_16k_mode <= 1'b0;
|
|
n64_scb.eeprom_enabled <= 1'b0;
|
|
n64_scb.dd_enabled <= 1'b0;
|
|
n64_scb.ddipl_enabled <= 1'b0;
|
|
n64_scb.flashram_enabled <= 1'b0;
|
|
n64_scb.sram_banked <= 1'b0;
|
|
n64_scb.sram_enabled <= 1'b0;
|
|
n64_scb.rom_shadow_enabled <= 1'b0;
|
|
n64_scb.rom_write_enabled <= 1'b0;
|
|
bootloader_skip <= 1'b0;
|
|
n64_scb.bootloader_enabled <= 1'b1;
|
|
flash_scb.erase_pending <= 1'b0;
|
|
dd_bm_ack <= 1'b0;
|
|
n64_scb.rtc_wdata_valid <= 1'b0;
|
|
cic_invalid_region <= 1'b0;
|
|
n64_scb.cic_disabled <= 1'b0;
|
|
n64_scb.cic_64dd_mode <= 1'b0;
|
|
n64_scb.cic_region <= 1'b0;
|
|
n64_scb.cic_seed <= 8'h3F;
|
|
n64_scb.cic_checksum <= 48'hA536C0F1D859;
|
|
end else if (reg_write) begin
|
|
case (address)
|
|
REG_MEM_ADDRESS: begin
|
|
mem_address <= reg_wdata;
|
|
end
|
|
|
|
REG_MEM_SCR: begin
|
|
{
|
|
mem_length,
|
|
mem_direction,
|
|
mem_stop,
|
|
mem_start
|
|
} <= {(reg_wdata[14:5] - 1'd1), reg_wdata[2:0]};
|
|
end
|
|
|
|
REG_USB_SCR: begin
|
|
usb_scb.write_buffer_flush <= reg_wdata[5];
|
|
usb_scb.reset_off_ack <= reg_wdata[4];
|
|
usb_scb.reset_on_ack <= reg_wdata[3];
|
|
usb_scb.fifo_flush <= reg_wdata[0];
|
|
end
|
|
|
|
REG_USB_DMA_ADDRESS: begin
|
|
usb_dma_scb.starting_address <= reg_wdata[26:0];
|
|
end
|
|
|
|
REG_USB_DMA_LENGTH: begin
|
|
usb_dma_scb.transfer_length <= reg_wdata[26:0];
|
|
end
|
|
|
|
REG_USB_DMA_SCR: begin
|
|
{
|
|
usb_dma_scb.direction,
|
|
usb_dma_scb.stop,
|
|
usb_dma_scb.start
|
|
} <= reg_wdata[2:0];
|
|
end
|
|
|
|
REG_CFG_SCR: begin
|
|
{
|
|
n64_scb.rom_extended_enabled,
|
|
n64_scb.eeprom_16k_mode,
|
|
n64_scb.eeprom_enabled,
|
|
n64_scb.ddipl_enabled,
|
|
n64_scb.dd_enabled,
|
|
n64_scb.flashram_enabled,
|
|
n64_scb.sram_banked,
|
|
n64_scb.sram_enabled,
|
|
n64_scb.rom_shadow_enabled,
|
|
n64_scb.rom_write_enabled,
|
|
bootloader_skip,
|
|
n64_scb.bootloader_enabled
|
|
} <= reg_wdata[11:0];
|
|
end
|
|
|
|
REG_CFG_DATA_0: begin
|
|
n64_scb.cfg_wdata[0] <= reg_wdata;
|
|
end
|
|
|
|
REG_CFG_DATA_1: begin
|
|
n64_scb.cfg_wdata[1] <= reg_wdata;
|
|
end
|
|
|
|
REG_CFG_CMD: begin
|
|
{
|
|
n64_scb.cfg_irq,
|
|
n64_scb.cfg_error,
|
|
n64_scb.cfg_done
|
|
} <= reg_wdata[11:9];
|
|
end
|
|
|
|
REG_FLASHRAM_SCR: begin
|
|
n64_scb.flashram_done <= reg_wdata[0];
|
|
end
|
|
|
|
REG_FLASH_SCR: begin
|
|
flash_scb.erase_pending <= 1'b1;
|
|
flash_scb.erase_block <= reg_wdata[23:16];
|
|
end
|
|
|
|
REG_RTC_SCR: begin
|
|
n64_scb.rtc_done <= reg_wdata[1];
|
|
end
|
|
|
|
REG_RTC_TIME_0: begin
|
|
n64_scb.rtc_wdata_valid <= 1'b0;
|
|
n64_scb.rtc_wdata[28:26] <= reg_wdata[26:24];
|
|
n64_scb.rtc_wdata[19:14] <= reg_wdata[21:16];
|
|
n64_scb.rtc_wdata[13:7] <= reg_wdata[14:8];
|
|
n64_scb.rtc_wdata[6:0] <= reg_wdata[6:0];
|
|
end
|
|
|
|
REG_RTC_TIME_1: begin
|
|
n64_scb.rtc_wdata_valid <= 1'b1;
|
|
n64_scb.rtc_wdata[42] <= reg_wdata[24];
|
|
n64_scb.rtc_wdata[41:34] <= reg_wdata[23:16];
|
|
n64_scb.rtc_wdata[33:29] <= reg_wdata[12:8];
|
|
n64_scb.rtc_wdata[25:20] <= reg_wdata[5:0];
|
|
end
|
|
|
|
REG_SD_SCR: begin
|
|
sd_scb.clock_mode <= reg_wdata[1:0];
|
|
end
|
|
|
|
REG_SD_ARG: begin
|
|
sd_scb.cmd_arg <= reg_wdata;
|
|
end
|
|
|
|
REG_SD_CMD: begin
|
|
sd_scb.cmd_start <= 1'b1;
|
|
sd_scb.cmd_ignore_crc <= reg_wdata[9];
|
|
sd_scb.cmd_long_response <= reg_wdata[8];
|
|
sd_scb.cmd_reserved_response <= reg_wdata[7];
|
|
sd_scb.cmd_skip_response <= reg_wdata[6];
|
|
sd_scb.cmd_index <= reg_wdata[5:0];
|
|
end
|
|
|
|
REG_SD_DAT: begin
|
|
sd_scb.dat_blocks <= reg_wdata[11:4];
|
|
sd_scb.dat_stop <= reg_wdata[3];
|
|
sd_scb.dat_start_read <= reg_wdata[2];
|
|
sd_scb.dat_start_write <= reg_wdata[1];
|
|
sd_scb.dat_fifo_flush <= reg_wdata[0];
|
|
end
|
|
|
|
REG_SD_DMA_ADDRESS: begin
|
|
sd_dma_scb.starting_address <= reg_wdata[26:0];
|
|
end
|
|
|
|
REG_SD_DMA_LENGTH: begin
|
|
sd_dma_scb.transfer_length <= reg_wdata[26:0];
|
|
end
|
|
|
|
REG_SD_DMA_SCR: begin
|
|
sd_dma_scb.byte_swap <= reg_wdata[4];
|
|
sd_dma_scb.direction <= reg_wdata[2];
|
|
sd_dma_scb.stop <= reg_wdata[1];
|
|
sd_dma_scb.start <= reg_wdata[0];
|
|
end
|
|
|
|
REG_DD_SCR: begin
|
|
dd_scb.bm_clear <= reg_wdata[19];
|
|
if (reg_wdata[18]) begin
|
|
dd_bm_ack <= 1'b0;
|
|
end
|
|
dd_scb.bm_micro_error <= reg_wdata[16];
|
|
dd_scb.bm_transfer_c2 <= reg_wdata[15];
|
|
dd_scb.bm_transfer_data <= reg_wdata[14];
|
|
dd_scb.bm_stop_clear <= reg_wdata[11];
|
|
dd_scb.bm_start_clear <= reg_wdata[9];
|
|
dd_scb.disk_changed <= reg_wdata[7];
|
|
dd_scb.disk_inserted <= reg_wdata[6];
|
|
dd_scb.bm_ready <= reg_wdata[5];
|
|
dd_scb.cmd_ready <= reg_wdata[3];
|
|
dd_scb.hard_reset_clear <= reg_wdata[1];
|
|
end
|
|
|
|
REG_DD_CMD_DATA: begin
|
|
dd_scb.cmd_data <= reg_wdata[15:0];
|
|
end
|
|
|
|
REG_DD_HEAD_TRACK: begin
|
|
{dd_scb.index_lock, dd_scb.head_track} <= reg_wdata[13:0];
|
|
end
|
|
|
|
REG_DD_DRIVE_ID: begin
|
|
dd_scb.drive_id <= reg_wdata[15:0];
|
|
end
|
|
|
|
REG_VENDOR_SCR: begin
|
|
vendor_scb.control_valid <= 1'b1;
|
|
vendor_scb.control_wdata <= reg_wdata;
|
|
end
|
|
|
|
REG_VENDOR_DATA: begin
|
|
vendor_scb.data_wdata <= reg_wdata;
|
|
end
|
|
|
|
REG_CIC_0: begin
|
|
if (reg_wdata[28]) begin
|
|
cic_invalid_region <= 1'b0;
|
|
end
|
|
n64_scb.cic_disabled <= reg_wdata[26];
|
|
n64_scb.cic_64dd_mode <= reg_wdata[25];
|
|
n64_scb.cic_region <= reg_wdata[24];
|
|
n64_scb.cic_seed <= reg_wdata[23:16];
|
|
n64_scb.cic_checksum[47:32] <= reg_wdata[15:0];
|
|
end
|
|
|
|
REG_CIC_1: begin
|
|
n64_scb.cic_checksum[31:0] <= reg_wdata;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
endmodule
|