mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-21 21:49:15 +01:00
added cfg lock mechanism
This commit is contained in:
parent
8a8a3b4439
commit
30f0fc002e
Binary file not shown.
@ -42,6 +42,9 @@
|
||||
<Source name="../../rtl/n64/n64_flashram.sv" type="Verilog" type_short="Verilog">
|
||||
<Options VerilogStandard="System Verilog"/>
|
||||
</Source>
|
||||
<Source name="../../rtl/n64/n64_lock.sv" type="Verilog" type_short="Verilog">
|
||||
<Options VerilogStandard="System Verilog"/>
|
||||
</Source>
|
||||
<Source name="../../rtl/n64/n64_pi.sv" type="Verilog" type_short="Verilog">
|
||||
<Options VerilogStandard="System Verilog"/>
|
||||
</Source>
|
||||
|
@ -607,6 +607,7 @@ module mcu_top (
|
||||
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;
|
||||
|
@ -20,21 +20,25 @@ module n64_cfg (
|
||||
REG_VERSION_L
|
||||
} e_reg;
|
||||
|
||||
logic cfg_error;
|
||||
|
||||
always_comb begin
|
||||
reg_bus.rdata = 16'd0;
|
||||
case (reg_bus.address[3:1])
|
||||
REG_STATUS: reg_bus.rdata = {
|
||||
n64_scb.cfg_pending,
|
||||
n64_scb.cfg_error,
|
||||
14'd0
|
||||
};
|
||||
REG_DATA_0_H: reg_bus.rdata = n64_scb.cfg_wdata[0][31:16];
|
||||
REG_DATA_0_L: reg_bus.rdata = n64_scb.cfg_wdata[0][15:0];
|
||||
REG_DATA_1_H: reg_bus.rdata = n64_scb.cfg_wdata[1][31:16];
|
||||
REG_DATA_1_L: reg_bus.rdata = n64_scb.cfg_wdata[1][15:0];
|
||||
REG_VERSION_H: reg_bus.rdata = n64_scb.cfg_version[31:16];
|
||||
REG_VERSION_L: reg_bus.rdata = n64_scb.cfg_version[15:0];
|
||||
endcase
|
||||
if (reg_bus.address[16] && (reg_bus.address[15:4] == 12'd0)) begin
|
||||
case (reg_bus.address[3:1])
|
||||
REG_STATUS: reg_bus.rdata = {
|
||||
n64_scb.cfg_pending,
|
||||
cfg_error,
|
||||
14'd0
|
||||
};
|
||||
REG_DATA_0_H: reg_bus.rdata = n64_scb.cfg_wdata[0][31:16];
|
||||
REG_DATA_0_L: reg_bus.rdata = n64_scb.cfg_wdata[0][15:0];
|
||||
REG_DATA_1_H: reg_bus.rdata = n64_scb.cfg_wdata[1][31:16];
|
||||
REG_DATA_1_L: reg_bus.rdata = n64_scb.cfg_wdata[1][15:0];
|
||||
REG_VERSION_H: reg_bus.rdata = n64_scb.cfg_version[31:16];
|
||||
REG_VERSION_L: reg_bus.rdata = n64_scb.cfg_version[15:0];
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
@ -42,9 +46,11 @@ module n64_cfg (
|
||||
n64_scb.cfg_pending <= 1'b0;
|
||||
n64_scb.cfg_cmd <= 8'h00;
|
||||
irq <= 1'b0;
|
||||
cfg_error <= 1'b0;
|
||||
end else begin
|
||||
if (n64_scb.cfg_done) begin
|
||||
n64_scb.cfg_pending <= 1'b0;
|
||||
cfg_error <= n64_scb.cfg_error;
|
||||
end
|
||||
|
||||
if (n64_scb.cfg_irq) begin
|
||||
@ -52,17 +58,20 @@ module n64_cfg (
|
||||
end
|
||||
|
||||
if (reg_bus.write) begin
|
||||
case (reg_bus.address[3:1])
|
||||
REG_COMMAND: begin
|
||||
n64_scb.cfg_pending <= 1'b1;
|
||||
n64_scb.cfg_cmd <= reg_bus.wdata[7:0];
|
||||
end
|
||||
REG_DATA_0_H: n64_scb.cfg_rdata[0][31:16] <= reg_bus.wdata;
|
||||
REG_DATA_0_L: n64_scb.cfg_rdata[0][15:0] <= reg_bus.wdata;
|
||||
REG_DATA_1_H: n64_scb.cfg_rdata[1][31:16] <= reg_bus.wdata;
|
||||
REG_DATA_1_L: n64_scb.cfg_rdata[1][15:0] <= reg_bus.wdata;
|
||||
REG_VERSION_L: irq <= 1'b0;
|
||||
endcase
|
||||
if (reg_bus.address[16] && (reg_bus.address[15:4] == 12'd0)) begin
|
||||
case (reg_bus.address[3:1])
|
||||
REG_COMMAND: begin
|
||||
n64_scb.cfg_pending <= 1'b1;
|
||||
n64_scb.cfg_cmd <= reg_bus.wdata[7:0];
|
||||
cfg_error <= 1'b0;
|
||||
end
|
||||
REG_DATA_0_H: n64_scb.cfg_rdata[0][31:16] <= reg_bus.wdata;
|
||||
REG_DATA_0_L: n64_scb.cfg_rdata[0][15:0] <= reg_bus.wdata;
|
||||
REG_DATA_1_H: n64_scb.cfg_rdata[1][31:16] <= reg_bus.wdata;
|
||||
REG_DATA_1_L: n64_scb.cfg_rdata[1][15:0] <= reg_bus.wdata;
|
||||
REG_VERSION_L: irq <= 1'b0;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
52
fw/rtl/n64/n64_lock.sv
Normal file
52
fw/rtl/n64/n64_lock.sv
Normal file
@ -0,0 +1,52 @@
|
||||
module n64_lock (
|
||||
input clk,
|
||||
input reset,
|
||||
|
||||
n64_reg_bus.lock reg_bus,
|
||||
|
||||
n64_scb.lock n64_scb,
|
||||
);
|
||||
|
||||
const bit [15:0] UNLOCK_SEQUENCE [4] = {
|
||||
16'h5F55,
|
||||
16'h4E4C,
|
||||
16'h4F43,
|
||||
16'h4B5F
|
||||
};
|
||||
|
||||
always_comb begin
|
||||
reg_bus.rdata = 16'd0;
|
||||
end
|
||||
|
||||
logic [1:0] sequence_counter;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (reset || n64_scb.n64_reset || n64_scb.n64_nmi) begin
|
||||
n64_scb.cfg_unlock <= 1'b0;
|
||||
sequence_counter <= 2'd0;
|
||||
end else begin
|
||||
if (reg_bus.write) begin
|
||||
if (reg_bus.address[16] && (reg_bus.address[15:2] == 14'd0)) begin
|
||||
for (int i = 0; i < $size(UNLOCK_SEQUENCE); i++) begin
|
||||
if (sequence_counter == i) begin
|
||||
if (reg_bus.wdata == UNLOCK_SEQUENCE[i]) begin
|
||||
sequence_counter <= sequence_counter + 1'd1;
|
||||
if (i == ($size(UNLOCK_SEQUENCE) - 1'd1)) begin
|
||||
n64_scb.cfg_unlock <= 1'b1;
|
||||
sequence_counter <= 2'd0;
|
||||
end
|
||||
end else begin
|
||||
n64_scb.cfg_unlock <= 1'b0;
|
||||
sequence_counter <= 2'd0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
n64_scb.cfg_unlock <= 1'b0;
|
||||
sequence_counter <= 2'd0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
@ -139,6 +139,7 @@ module n64_pi (
|
||||
write_port <= PORT_NONE;
|
||||
reg_bus.dd_select <= 1'b0;
|
||||
reg_bus.flashram_select <= 1'b0;
|
||||
reg_bus.lock_select <= 1'b0;
|
||||
reg_bus.cfg_select <= 1'b0;
|
||||
end else if (aleh_op) begin
|
||||
read_port <= PORT_NONE;
|
||||
@ -146,6 +147,7 @@ module n64_pi (
|
||||
mem_offset <= 32'd0;
|
||||
reg_bus.dd_select <= 1'b0;
|
||||
reg_bus.flashram_select <= 1'b0;
|
||||
reg_bus.lock_select <= 1'b0;
|
||||
reg_bus.cfg_select <= 1'b0;
|
||||
|
||||
if (n64_scb.dd_enabled) begin
|
||||
@ -220,16 +222,24 @@ module n64_pi (
|
||||
mem_offset <= (-32'h1400_0000) + FLASH_OFFSET;
|
||||
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;
|
||||
if (n64_pi_dq_in >= 16'h1FFD && n64_pi_dq_in < 16'h1FFE) begin
|
||||
read_port <= PORT_NONE;
|
||||
write_port <= PORT_REG;
|
||||
reg_bus.lock_select <= 1'b1;
|
||||
end
|
||||
|
||||
if (n64_pi_dq_in >= 16'h1FFF && n64_pi_dq_in < 16'h2000) begin
|
||||
read_port <= PORT_REG;
|
||||
write_port <= PORT_REG;
|
||||
reg_bus.cfg_select <= 1'b1;
|
||||
if (n64_scb.cfg_unlock) begin
|
||||
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
|
||||
|
||||
if (n64_pi_dq_in >= 16'h1FFF && n64_pi_dq_in < 16'h2000) begin
|
||||
read_port <= PORT_REG;
|
||||
write_port <= PORT_REG;
|
||||
reg_bus.cfg_select <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2,6 +2,7 @@ interface n64_reg_bus ();
|
||||
|
||||
logic flashram_select;
|
||||
logic dd_select;
|
||||
logic lock_select;
|
||||
logic cfg_select;
|
||||
|
||||
logic read;
|
||||
@ -12,12 +13,14 @@ interface n64_reg_bus ();
|
||||
|
||||
logic [15:0] flashram_rdata;
|
||||
logic [15:0] dd_rdata;
|
||||
logic [15:0] lock_rdata;
|
||||
logic [15:0] cfg_rdata;
|
||||
|
||||
modport controller (
|
||||
output flashram_select,
|
||||
output dd_select,
|
||||
output cfg_select,
|
||||
output lock_select,
|
||||
|
||||
output read,
|
||||
output write,
|
||||
@ -34,6 +37,9 @@ interface n64_reg_bus ();
|
||||
if (dd_select) begin
|
||||
rdata = dd_rdata;
|
||||
end
|
||||
if (lock_select) begin
|
||||
rdata = lock_rdata;
|
||||
end
|
||||
if (cfg_select) begin
|
||||
rdata = cfg_rdata;
|
||||
end
|
||||
@ -55,6 +61,14 @@ interface n64_reg_bus ();
|
||||
input wdata
|
||||
);
|
||||
|
||||
modport lock (
|
||||
input .read(read && lock_select),
|
||||
input .write(write && lock_select),
|
||||
input address,
|
||||
output .rdata(lock_rdata),
|
||||
input wdata
|
||||
);
|
||||
|
||||
modport cfg (
|
||||
input .read(read && cfg_select),
|
||||
input .write(write && cfg_select),
|
||||
|
@ -40,6 +40,7 @@ interface n64_scb ();
|
||||
logic [41:0] rtc_rdata;
|
||||
logic [41:0] rtc_wdata;
|
||||
|
||||
logic cfg_unlock;
|
||||
logic cfg_pending;
|
||||
logic cfg_done;
|
||||
logic cfg_error;
|
||||
@ -99,7 +100,9 @@ interface n64_scb ();
|
||||
input dd_enabled,
|
||||
input ddipl_enabled,
|
||||
|
||||
input flashram_read_mode
|
||||
input flashram_read_mode,
|
||||
|
||||
input cfg_unlock
|
||||
);
|
||||
|
||||
modport flashram (
|
||||
@ -158,6 +161,13 @@ interface n64_scb ();
|
||||
input dd_wdata
|
||||
);
|
||||
|
||||
modport lock (
|
||||
input n64_reset,
|
||||
input n64_nmi,
|
||||
|
||||
output cfg_unlock
|
||||
);
|
||||
|
||||
modport cfg (
|
||||
input n64_reset,
|
||||
|
||||
|
@ -67,6 +67,15 @@ module n64_top (
|
||||
.n64_scb(n64_scb)
|
||||
);
|
||||
|
||||
n64_lock n64_lock_inst (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
|
||||
.reg_bus(reg_bus),
|
||||
|
||||
.n64_scb(n64_scb)
|
||||
);
|
||||
|
||||
n64_cfg n64_cfg_inst (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
|
@ -11,6 +11,8 @@ void init (void) {
|
||||
|
||||
exception_install();
|
||||
|
||||
sc64_unlock();
|
||||
|
||||
if (!sc64_check_presence()) {
|
||||
error_display("SC64 hardware not detected");
|
||||
}
|
||||
@ -29,4 +31,5 @@ void init (void) {
|
||||
void deinit (void) {
|
||||
exception_disable_interrupts();
|
||||
exception_disable_watchdog();
|
||||
sc64_lock();
|
||||
}
|
||||
|
@ -225,6 +225,14 @@ typedef struct {
|
||||
#define PIFRAM ((io8_t *) PIFRAM_BASE)
|
||||
|
||||
|
||||
typedef struct {
|
||||
io32_t KEY;
|
||||
} sc64_lock_t;
|
||||
|
||||
#define SC64_LOCK_BASE (0x1FFD0000UL)
|
||||
#define SC64_LOCK ((sc64_lock_t *) SC64_LOCK_BASE)
|
||||
|
||||
|
||||
typedef struct {
|
||||
io8_t BUFFER[8192];
|
||||
io8_t EEPROM[2048];
|
||||
|
@ -40,6 +40,16 @@ static bool sc64_execute_cmd (uint8_t cmd, uint32_t *args, uint32_t *result) {
|
||||
return error;
|
||||
}
|
||||
|
||||
void sc64_unlock (void) {
|
||||
pi_io_write(&SC64_LOCK->KEY, 0x00000000);
|
||||
pi_io_write(&SC64_LOCK->KEY, 0x5F554E4C);
|
||||
pi_io_write(&SC64_LOCK->KEY, 0x4F434B5F);
|
||||
}
|
||||
|
||||
void sc64_lock (void) {
|
||||
pi_io_write(&SC64_LOCK->KEY, 0x00000000);
|
||||
}
|
||||
|
||||
bool sc64_check_presence (void) {
|
||||
uint32_t version = pi_io_read(&SC64_REGS->VERSION);
|
||||
return (version == SC64_VERSION_2);
|
||||
|
@ -91,6 +91,8 @@ typedef struct {
|
||||
} rtc_time_t;
|
||||
|
||||
|
||||
void sc64_unlock (void);
|
||||
void sc64_lock (void);
|
||||
bool sc64_check_presence (void);
|
||||
cmd_error_t sc64_get_error (void);
|
||||
void sc64_set_config (cfg_id_t id, uint32_t value);
|
||||
|
@ -54,7 +54,7 @@ void button_process (void) {
|
||||
if (p.trigger) {
|
||||
switch (p.mode) {
|
||||
case BUTTON_MODE_N64_IRQ:
|
||||
fpga_reg_set(REG_CFG_CMD, fpga_reg_get(REG_CFG_CMD) | CFG_CMD_IRQ);
|
||||
fpga_reg_set(REG_CFG_CMD, CFG_CMD_IRQ);
|
||||
p.trigger = false;
|
||||
break;
|
||||
|
||||
|
@ -11,7 +11,7 @@ from dd64 import BadBlockError, DD64Image
|
||||
from enum import Enum, IntEnum
|
||||
from serial.tools import list_ports
|
||||
from threading import Thread
|
||||
from typing import Optional
|
||||
from typing import Callable, Optional
|
||||
|
||||
|
||||
|
||||
@ -394,8 +394,6 @@ class SC64:
|
||||
|
||||
def upload_save(self, data: bytes) -> None:
|
||||
save_type = self.SaveType(self.__get_config(self.__CfgId.SAVE_TYPE))
|
||||
if (save_type not in self.SaveType):
|
||||
raise ConnectionError('Unknown save type fetched from SC64 device')
|
||||
if (save_type == self.SaveType.NONE):
|
||||
raise ValueError('No save type set inside SC64 device')
|
||||
if (len(data) != self.__SaveLength[save_type.name]):
|
||||
@ -407,8 +405,6 @@ class SC64:
|
||||
|
||||
def download_save(self) -> bytes:
|
||||
save_type = self.SaveType(self.__get_config(self.__CfgId.SAVE_TYPE))
|
||||
if (save_type not in self.SaveType):
|
||||
raise ConnectionError('Unknown save type fetched from SC64 device')
|
||||
if (save_type == self.SaveType.NONE):
|
||||
raise ValueError('No save type set inside SC64 device')
|
||||
address = self.__Address.SAVE
|
||||
@ -432,8 +428,6 @@ class SC64:
|
||||
self.__link.execute_cmd(cmd=b'T', args=[self.__get_int(data[0:4]), self.__get_int(data[4:8])])
|
||||
|
||||
def set_boot_mode(self, mode: BootMode) -> None:
|
||||
if (mode not in self.BootMode):
|
||||
raise ValueError('Boot mode outside of allowed values')
|
||||
self.__set_config(self.__CfgId.BOOT_MODE, mode)
|
||||
|
||||
def set_cic_seed(self, seed: int) -> None:
|
||||
@ -443,13 +437,9 @@ class SC64:
|
||||
self.__set_config(self.__CfgId.CIC_SEED, seed)
|
||||
|
||||
def set_tv_type(self, type: TVType) -> None:
|
||||
if (type not in self.TVType):
|
||||
raise ValueError('TV type outside of allowed values')
|
||||
self.__set_config(self.__CfgId.TV_TYPE, type)
|
||||
|
||||
def set_save_type(self, type: SaveType) -> None:
|
||||
if (type not in self.SaveType):
|
||||
raise ValueError('Save type outside of allowed values')
|
||||
self.__set_config(self.__CfgId.SAVE_TYPE, type)
|
||||
|
||||
def set_cic_parameters(self, dd_mode: bool=False, seed: int=0x3F, checksum: bytes=bytes([0xA5, 0x36, 0xC0, 0xF1, 0xD8, 0x59])) -> None:
|
||||
@ -461,7 +451,7 @@ class SC64:
|
||||
data = [*data, *checksum]
|
||||
self.__link.execute_cmd(cmd=b'B', args=[self.__get_int(data[0:4]), self.__get_int(data[4:8])])
|
||||
|
||||
def update_firmware(self, data: bytes) -> None:
|
||||
def update_firmware(self, data: bytes, status_callback: Optional[Callable[[str], None]]=None) -> None:
|
||||
address = self.__Address.FIRMWARE
|
||||
self.__write_memory(address, data)
|
||||
response = self.__link.execute_cmd(cmd=b'F', args=[address, len(data)])
|
||||
@ -477,7 +467,8 @@ class SC64:
|
||||
if (cmd != b'F'):
|
||||
raise ConnectionException('Wrong update status packet')
|
||||
status = self.__UpdateStatus(self.__get_int(data))
|
||||
print(f'Update status [{status.name}]')
|
||||
if (status_callback):
|
||||
status_callback(status.name)
|
||||
if (status == self.__UpdateStatus.ERROR):
|
||||
raise ConnectionException('Update error, device is most likely bricked')
|
||||
time.sleep(2)
|
||||
@ -616,8 +607,8 @@ class EnumAction(argparse.Action):
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='SC64 control software')
|
||||
parser.add_argument('--backup', help='backup SC64 firmware and write it to specified file')
|
||||
parser.add_argument('--update', help='update SC64 firmware from specified file')
|
||||
parser.add_argument('--backup-firmware', help='backup SC64 firmware and write it to specified file')
|
||||
parser.add_argument('--update-firmware', help='update SC64 firmware from specified file')
|
||||
parser.add_argument('--reset-state', action='store_true', help='reset SC64 internal state')
|
||||
parser.add_argument('--print-state', action='store_true', help='print SC64 internal state')
|
||||
parser.add_argument('--boot', type=SC64.BootMode, action=EnumAction, help='set boot mode')
|
||||
@ -632,7 +623,7 @@ if __name__ == '__main__':
|
||||
parser.add_argument('--ddipl', help='upload 64DD IPL from specified file')
|
||||
parser.add_argument('--disk', action='append', help='path to 64DD disk (.ndd format), can be specified multiple times')
|
||||
parser.add_argument('--isv', action='store_true', help='enable IS-Viewer64 support')
|
||||
parser.add_argument('--debug', action='store_true', help='run debug loop (required for IS-Viewer64 and 64DD)')
|
||||
parser.add_argument('--debug', action='store_true', help='run debug loop (required for 64DD and IS-Viewer64)')
|
||||
|
||||
if (len(sys.argv) <= 1):
|
||||
parser.print_help()
|
||||
@ -643,16 +634,17 @@ if __name__ == '__main__':
|
||||
try:
|
||||
sc64 = SC64()
|
||||
|
||||
if (args.backup):
|
||||
with open(args.backup, 'wb+') as f:
|
||||
if (args.backup_firmware):
|
||||
with open(args.backup_firmware, 'wb+') as f:
|
||||
print('Generating backup, this might take a while... ', end='', flush=True)
|
||||
f.write(sc64.backup_firmware())
|
||||
print('done')
|
||||
|
||||
if (args.update):
|
||||
with open(args.update, 'rb+') as f:
|
||||
if (args.update_firmware):
|
||||
with open(args.update_firmware, 'rb+') as f:
|
||||
print('Updating firmware, this might take a while... ', end='', flush=True)
|
||||
sc64.update_firmware(f.read())
|
||||
status_callback = lambda status: print(f'{status} ', end='', flush=True)
|
||||
sc64.update_firmware(f.read(), status_callback)
|
||||
print('done')
|
||||
|
||||
if (args.reset_state):
|
||||
|
Loading…
Reference in New Issue
Block a user