mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-12-24 03:51:57 +01:00
[SC64][FW][SW] Added 64DD implementation with USB streaming (#14)
This commit is contained in:
parent
0929dbeff4
commit
92e5c5747b
@ -54,6 +54,7 @@ set_global_assignment -name SDC_FILE SummerCart64.sdc
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE picorv32/picorv32.v
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_bus.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_cfg.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_dd.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_dma.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_flash.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_flashram.sv
|
||||
|
@ -46,6 +46,8 @@ module SummerCart64 (
|
||||
logic [7:0] gpio_i;
|
||||
logic [7:0] gpio_oe;
|
||||
|
||||
logic dd_interrupt;
|
||||
|
||||
if_system sys (
|
||||
.in_clk(i_clk),
|
||||
.n64_reset(i_n64_reset),
|
||||
@ -64,6 +66,10 @@ module SummerCart64 (
|
||||
|
||||
if_flash flash ();
|
||||
|
||||
if_dd dd (
|
||||
.dd_interrupt(dd_interrupt)
|
||||
);
|
||||
|
||||
system system_inst (
|
||||
.sys(sys)
|
||||
);
|
||||
@ -82,6 +88,7 @@ module SummerCart64 (
|
||||
.flashram(flashram),
|
||||
.si(si),
|
||||
.flash(flash),
|
||||
.dd(dd),
|
||||
|
||||
.n64_pi_alel(i_n64_pi_alel),
|
||||
.n64_pi_aleh(i_n64_pi_aleh),
|
||||
@ -109,6 +116,7 @@ module SummerCart64 (
|
||||
.flashram(flashram),
|
||||
.si(si),
|
||||
.flash(flash),
|
||||
.dd(dd),
|
||||
|
||||
.gpio_o(gpio_o),
|
||||
.gpio_i(gpio_i),
|
||||
@ -131,9 +139,12 @@ module SummerCart64 (
|
||||
.sd_dat(io_sd_dat)
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
o_n64_irq = dd_interrupt ? 1'b0 : 1'bZ;
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
o_led = gpio_oe[0] ? gpio_o[0] : 1'bZ;
|
||||
o_n64_irq = gpio_oe[1] ? gpio_o[1] : 1'bZ;
|
||||
end
|
||||
|
||||
always_ff @(posedge sys.clk) begin
|
||||
|
141
fw/rtl/cpu/cpu_dd.sv
Normal file
141
fw/rtl/cpu/cpu_dd.sv
Normal file
@ -0,0 +1,141 @@
|
||||
module cpu_dd (
|
||||
if_system.sys sys,
|
||||
if_cpu_bus bus,
|
||||
if_dd.cpu dd
|
||||
);
|
||||
|
||||
const bit [8:0] M_SECTOR_BUFFER = 9'h100;
|
||||
|
||||
logic bm_ack;
|
||||
logic [31:0] seek_timer;
|
||||
|
||||
typedef enum bit [2:0] {
|
||||
R_SCR,
|
||||
R_CMD_DATA,
|
||||
R_HEAD_TRACK,
|
||||
R_SECTOR_INFO,
|
||||
R_DRIVE_ID,
|
||||
R_SEEK_TIMER
|
||||
} e_reg_id;
|
||||
|
||||
always_ff @(posedge sys.clk) begin
|
||||
bus.ack <= 1'b0;
|
||||
if (bus.request) begin
|
||||
bus.ack <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
bus.rdata = 32'd0;
|
||||
if (bus.ack) begin
|
||||
if (bus.address[8] == M_SECTOR_BUFFER[8]) begin
|
||||
bus.rdata = {
|
||||
dd.sector_rdata[7:0],
|
||||
dd.sector_rdata[15:8],
|
||||
dd.sector_rdata[23:16],
|
||||
dd.sector_rdata[31:24]
|
||||
};
|
||||
end else begin
|
||||
case (bus.address[5:2])
|
||||
R_SCR: bus.rdata = {
|
||||
14'd0,
|
||||
bm_ack,
|
||||
dd.bm_micro_error,
|
||||
dd.bm_transfer_c2,
|
||||
dd.bm_transfer_data,
|
||||
dd.bm_transfer_blocks,
|
||||
dd.bm_transfer_mode,
|
||||
1'b0,
|
||||
dd.bm_stop_pending,
|
||||
1'b0,
|
||||
dd.bm_start_pending,
|
||||
dd.disk_changed,
|
||||
dd.disk_inserted,
|
||||
1'b0,
|
||||
dd.bm_pending,
|
||||
1'b0,
|
||||
dd.cmd_pending,
|
||||
1'b0,
|
||||
dd.hard_reset
|
||||
};
|
||||
R_CMD_DATA: bus.rdata = {8'd0, dd.cmd, dd.data};
|
||||
R_HEAD_TRACK: bus.rdata = {18'd0, dd.index_lock, dd.head_track};
|
||||
R_SECTOR_INFO: bus.rdata = {
|
||||
dd.sectors_in_block,
|
||||
dd.sector_size_full,
|
||||
dd.sector_size,
|
||||
dd.sector_num
|
||||
};
|
||||
R_DRIVE_ID: bus.rdata = {dd.drive_id};
|
||||
R_SEEK_TIMER: bus.rdata = seek_timer;
|
||||
default: bus.rdata = 32'd0;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
dd.sector_address = bus.address[7:2];
|
||||
dd.sector_address_valid = bus.request && bus.address[8] == M_SECTOR_BUFFER[8];
|
||||
dd.sector_write = (&bus.wmask) && dd.sector_address_valid;
|
||||
dd.sector_wdata = {bus.wdata[7:0], bus.wdata[15:8], bus.wdata[23:16], bus.wdata[31:24]};
|
||||
end
|
||||
|
||||
always_ff @(posedge sys.clk) begin
|
||||
dd.hard_reset_clear <= 1'b0;
|
||||
dd.cmd_ready <= 1'b0;
|
||||
dd.bm_start_clear <= 1'b0;
|
||||
dd.bm_stop_clear <= 1'b0;
|
||||
dd.bm_clear <= 1'b0;
|
||||
dd.bm_ready <= 1'b0;
|
||||
|
||||
if (dd.bm_interrupt_ack) begin
|
||||
bm_ack <= 1'b1;
|
||||
end
|
||||
|
||||
if (!(&seek_timer)) begin
|
||||
seek_timer <= seek_timer + 1'd1;
|
||||
end
|
||||
|
||||
if (sys.reset) begin
|
||||
bm_ack <= 1'b0;
|
||||
end else begin
|
||||
if (bus.request && (!bus.address[8])) begin
|
||||
case (bus.address[4:2])
|
||||
R_SCR: if (&bus.wmask) begin
|
||||
if (bus.wdata[20]) begin
|
||||
seek_timer <= 32'd0;
|
||||
end
|
||||
dd.bm_clear <= bus.wdata[19];
|
||||
if (bus.wdata[18]) begin
|
||||
bm_ack <= 1'b0;
|
||||
end
|
||||
dd.bm_micro_error <= bus.wdata[16];
|
||||
dd.bm_transfer_c2 <= bus.wdata[15];
|
||||
dd.bm_transfer_data <= bus.wdata[14];
|
||||
dd.bm_stop_clear <= bus.wdata[11];
|
||||
dd.bm_start_clear <= bus.wdata[9];
|
||||
dd.disk_changed <= bus.wdata[7];
|
||||
dd.disk_inserted <= bus.wdata[6];
|
||||
dd.bm_ready <= bus.wdata[5];
|
||||
dd.cmd_ready <= bus.wdata[3];
|
||||
dd.hard_reset_clear <= bus.wdata[1];
|
||||
end
|
||||
|
||||
R_CMD_DATA: if (&bus.wmask[1:0]) begin
|
||||
dd.cmd_data <= bus.wdata[15:0];
|
||||
end
|
||||
|
||||
R_HEAD_TRACK: if (&bus.wmask[1:0]) begin
|
||||
{dd.index_lock, dd.head_track} <= bus.wdata[13:0];
|
||||
end
|
||||
|
||||
R_DRIVE_ID: if (&bus.wmask[1:0]) begin
|
||||
dd.drive_id <= bus.wdata[15:0];
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
@ -6,6 +6,7 @@ module cpu_soc (
|
||||
if_flashram.cpu flashram,
|
||||
if_si.cpu si,
|
||||
if_flash.cpu flash,
|
||||
if_dd.cpu dd,
|
||||
|
||||
input [7:0] gpio_i,
|
||||
output [7:0] gpio_o,
|
||||
@ -113,6 +114,12 @@ module cpu_soc (
|
||||
.si(si)
|
||||
);
|
||||
|
||||
cpu_dd cpu_dd_inst (
|
||||
.sys(sys),
|
||||
.bus(bus.at[sc64::ID_CPU_DD].device),
|
||||
.dd(dd)
|
||||
);
|
||||
|
||||
assign sd_clk = 1'bZ;
|
||||
assign sd_cmd = 1'bZ;
|
||||
assign sd_dat = 4'bZZZZ;
|
||||
|
@ -9,6 +9,9 @@ interface if_n64_bus ();
|
||||
logic [31:0] address;
|
||||
logic [15:0] wdata;
|
||||
logic [15:0] rdata;
|
||||
logic [31:0] real_address;
|
||||
logic read_op;
|
||||
logic write_op;
|
||||
|
||||
logic device_ack [(NUM_DEVICES - 1):0];
|
||||
logic [15:0] device_rdata [(NUM_DEVICES - 1):0];
|
||||
@ -30,7 +33,11 @@ interface if_n64_bus ();
|
||||
output write,
|
||||
output address,
|
||||
output wdata,
|
||||
input rdata
|
||||
input rdata,
|
||||
|
||||
output real_address,
|
||||
output read_op,
|
||||
output write_op
|
||||
);
|
||||
|
||||
genvar n;
|
||||
@ -48,7 +55,11 @@ interface if_n64_bus ();
|
||||
input .write(write),
|
||||
input .address(address),
|
||||
input .wdata(wdata),
|
||||
output .rdata(device_rdata[n])
|
||||
output .rdata(device_rdata[n]),
|
||||
|
||||
input .real_address(real_address),
|
||||
input .read_op(read_op),
|
||||
input .write_op(write_op)
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
@ -1,40 +1,158 @@
|
||||
interface if_dd();
|
||||
interface if_dd (
|
||||
output dd_interrupt
|
||||
);
|
||||
|
||||
// Sector buffer regs
|
||||
|
||||
logic [6:0] n64_sector_address;
|
||||
logic n64_sector_address_valid;
|
||||
logic n64_sector_write;
|
||||
logic [15:0] n64_sector_wdata;
|
||||
|
||||
logic [5:0] cpu_sector_address;
|
||||
logic cpu_sector_address_valid;
|
||||
logic cpu_sector_write;
|
||||
logic [31:0] cpu_sector_wdata;
|
||||
|
||||
logic [31:0] sector_rdata;
|
||||
|
||||
|
||||
// N64 controlled regs
|
||||
|
||||
logic hard_reset;
|
||||
logic cmd_request;
|
||||
logic cmd_ack;
|
||||
logic [7:0] command;
|
||||
logic [15:0] status;
|
||||
logic [15:0] data_input;
|
||||
logic [15:0] data_output;
|
||||
logic bm_request;
|
||||
logic [15:0] bm_control;
|
||||
logic [15:0] bm_status;
|
||||
logic [15:0] data;
|
||||
logic [7:0] cmd;
|
||||
logic cmd_pending;
|
||||
logic cmd_interrupt;
|
||||
logic bm_start_pending;
|
||||
logic bm_stop_pending;
|
||||
logic bm_transfer_mode;
|
||||
logic bm_transfer_blocks;
|
||||
logic bm_pending;
|
||||
logic bm_interrupt;
|
||||
logic bm_interrupt_ack;
|
||||
logic [7:0] sector_num;
|
||||
logic [7:0] sector_size;
|
||||
logic [7:0] sector_size_full;
|
||||
logic [7:0] sectors_in_block;
|
||||
|
||||
modport n64 (
|
||||
|
||||
// CPU controlled regs
|
||||
|
||||
logic hard_reset_clear;
|
||||
logic [15:0] cmd_data;
|
||||
logic cmd_ready;
|
||||
logic bm_start_clear;
|
||||
logic bm_stop_clear;
|
||||
logic bm_transfer_c2;
|
||||
logic bm_transfer_data;
|
||||
logic bm_micro_error;
|
||||
logic bm_clear;
|
||||
logic bm_ready;
|
||||
logic disk_inserted;
|
||||
logic disk_changed;
|
||||
logic index_lock;
|
||||
logic [12:0] head_track;
|
||||
logic [15:0] drive_id;
|
||||
|
||||
|
||||
always_comb begin
|
||||
dd_interrupt = cmd_interrupt || bm_interrupt;
|
||||
end
|
||||
|
||||
|
||||
modport dd (
|
||||
output hard_reset,
|
||||
output cmd_request,
|
||||
input cmd_ack,
|
||||
output command,
|
||||
input status,
|
||||
output data_input,
|
||||
input data_output,
|
||||
output bm_request,
|
||||
output bm_control,
|
||||
input bm_status
|
||||
output data,
|
||||
output cmd,
|
||||
output cmd_pending,
|
||||
output cmd_interrupt,
|
||||
output bm_start_pending,
|
||||
output bm_stop_pending,
|
||||
output bm_transfer_mode,
|
||||
output bm_transfer_blocks,
|
||||
output bm_pending,
|
||||
output bm_interrupt,
|
||||
output bm_interrupt_ack,
|
||||
output sector_num,
|
||||
output sector_size,
|
||||
output sector_size_full,
|
||||
output sectors_in_block,
|
||||
|
||||
input hard_reset_clear,
|
||||
input cmd_data,
|
||||
input cmd_ready,
|
||||
input bm_start_clear,
|
||||
input bm_stop_clear,
|
||||
input bm_transfer_c2,
|
||||
input bm_transfer_data,
|
||||
input bm_micro_error,
|
||||
input bm_clear,
|
||||
input bm_ready,
|
||||
input disk_inserted,
|
||||
input disk_changed,
|
||||
input index_lock,
|
||||
input head_track,
|
||||
input drive_id,
|
||||
|
||||
output .sector_address(n64_sector_address),
|
||||
output .sector_address_valid(n64_sector_address_valid),
|
||||
output .sector_write(n64_sector_write),
|
||||
output .sector_wdata(n64_sector_wdata),
|
||||
input sector_rdata
|
||||
);
|
||||
|
||||
modport cpu (
|
||||
input hard_reset,
|
||||
input cmd_request,
|
||||
output cmd_ack,
|
||||
input command,
|
||||
output status,
|
||||
input data_input,
|
||||
output data_output,
|
||||
input bm_request,
|
||||
input bm_control,
|
||||
output bm_status
|
||||
input data,
|
||||
input cmd,
|
||||
input cmd_pending,
|
||||
input bm_start_pending,
|
||||
input bm_stop_pending,
|
||||
input bm_transfer_mode,
|
||||
input bm_transfer_blocks,
|
||||
input bm_pending,
|
||||
input bm_interrupt_ack,
|
||||
input sector_num,
|
||||
input sector_size,
|
||||
input sector_size_full,
|
||||
input sectors_in_block,
|
||||
|
||||
output hard_reset_clear,
|
||||
output cmd_data,
|
||||
output cmd_ready,
|
||||
output bm_start_clear,
|
||||
output bm_stop_clear,
|
||||
output bm_transfer_c2,
|
||||
output bm_transfer_data,
|
||||
output bm_micro_error,
|
||||
output bm_ready,
|
||||
output bm_clear,
|
||||
output disk_inserted,
|
||||
output disk_changed,
|
||||
output index_lock,
|
||||
output head_track,
|
||||
output drive_id,
|
||||
|
||||
output .sector_address(cpu_sector_address),
|
||||
output .sector_address_valid(cpu_sector_address_valid),
|
||||
output .sector_write(cpu_sector_write),
|
||||
output .sector_wdata(cpu_sector_wdata),
|
||||
input sector_rdata
|
||||
);
|
||||
|
||||
modport sector_buffer (
|
||||
input n64_sector_address,
|
||||
input n64_sector_address_valid,
|
||||
input n64_sector_write,
|
||||
input n64_sector_wdata,
|
||||
|
||||
input cpu_sector_address,
|
||||
input cpu_sector_address_valid,
|
||||
input cpu_sector_write,
|
||||
input cpu_sector_wdata,
|
||||
|
||||
output sector_rdata
|
||||
);
|
||||
|
||||
endinterface
|
||||
@ -42,9 +160,33 @@ endinterface
|
||||
|
||||
module n64_dd (
|
||||
if_system.sys sys,
|
||||
if_n64_bus bus
|
||||
if_n64_bus bus,
|
||||
if_dd.dd dd
|
||||
);
|
||||
|
||||
const bit [31:0] M_BASE = 32'h0500_0000;
|
||||
const bit [31:0] M_C2_BUFFER = M_BASE + 11'h000;
|
||||
const bit [31:0] M_SECTOR_BUFFER = M_BASE + 11'h400;
|
||||
|
||||
typedef enum bit [10:0] {
|
||||
R_DATA = 11'h500,
|
||||
R_CMD_SR = 11'h508,
|
||||
R_TRK_CUR = 11'h50C,
|
||||
R_BM_SCR = 11'h510,
|
||||
R_RESET = 11'h520,
|
||||
R_SEC_SIZ = 11'h528,
|
||||
R_SEC_INFO = 11'h530,
|
||||
R_ID = 11'h540
|
||||
} e_reg_id;
|
||||
|
||||
typedef enum bit [3:0] {
|
||||
BM_CONTROL_START_BUFFER_MANAGER = 4'd15,
|
||||
BM_CONTROL_BUFFER_MANAGER_MODE = 4'd14,
|
||||
BM_CONTROL_BUFFER_MANAGER_RESET = 4'd12,
|
||||
BM_CONTROL_BLOCK_TRANSFER = 4'd9,
|
||||
BM_CONTROL_MECHANIC_INTERRUPT_RESET = 4'd8
|
||||
} e_bm_control_id;
|
||||
|
||||
typedef enum bit [0:0] {
|
||||
S_IDLE,
|
||||
S_WAIT
|
||||
@ -53,23 +195,155 @@ module n64_dd (
|
||||
e_state state;
|
||||
|
||||
always_comb begin
|
||||
bus.rdata = 16'h0000;
|
||||
dd.sector_address = bus.address[7:1];
|
||||
dd.sector_address_valid = bus.request && bus.address[11:8] == M_SECTOR_BUFFER[11:8];
|
||||
dd.sector_write = bus.write && dd.sector_address_valid;
|
||||
dd.sector_wdata = bus.wdata;
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
bus.rdata = 16'd0;
|
||||
if (bus.ack) begin
|
||||
bus.rdata = !bus.address[1] ? 16'h0040 : 16'h0000;
|
||||
if (bus.address[10:8] == M_SECTOR_BUFFER[10:8]) begin
|
||||
if (bus.address[1]) begin
|
||||
bus.rdata = dd.sector_rdata[15:0];
|
||||
end else begin
|
||||
bus.rdata = dd.sector_rdata[31:16];
|
||||
end
|
||||
end else begin
|
||||
case (bus.address[10:0])
|
||||
R_DATA: bus.rdata = dd.data;
|
||||
R_CMD_SR: bus.rdata = {
|
||||
1'b0,
|
||||
dd.bm_transfer_data,
|
||||
1'b0,
|
||||
dd.bm_transfer_c2,
|
||||
1'b0,
|
||||
dd.bm_interrupt,
|
||||
dd.cmd_interrupt,
|
||||
dd.disk_inserted,
|
||||
dd.cmd_pending,
|
||||
dd.hard_reset,
|
||||
1'b0,
|
||||
1'b0,
|
||||
1'b0,
|
||||
1'b0,
|
||||
1'b0,
|
||||
dd.disk_changed
|
||||
};
|
||||
R_TRK_CUR: bus.rdata = {1'd0, {2{dd.index_lock}}, dd.head_track};
|
||||
R_BM_SCR: bus.rdata = {6'd0, dd.bm_micro_error, 9'd0};
|
||||
R_ID: bus.rdata = {dd.drive_id};
|
||||
default: bus.rdata = 16'd0;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge sys.clk) begin
|
||||
bus.ack <= 1'b0;
|
||||
dd.bm_interrupt_ack <= 1'b0;
|
||||
|
||||
if (sys.reset) begin
|
||||
if (dd.hard_reset_clear) begin
|
||||
dd.hard_reset <= 1'b0;
|
||||
end
|
||||
if (dd.cmd_ready) begin
|
||||
dd.data <= dd.cmd_data;
|
||||
dd.cmd_pending <= 1'b0;
|
||||
dd.cmd_interrupt <= 1'b1;
|
||||
end
|
||||
if (dd.bm_start_clear) begin
|
||||
dd.bm_start_pending <= 1'b0;
|
||||
end
|
||||
if (dd.bm_stop_clear) begin
|
||||
dd.bm_stop_pending <= 1'b0;
|
||||
end
|
||||
if (dd.bm_clear) begin
|
||||
dd.bm_pending <= 1'b0;
|
||||
end
|
||||
if (dd.bm_ready) begin
|
||||
dd.bm_interrupt <= 1'b1;
|
||||
end
|
||||
if (bus.real_address == (M_C2_BUFFER + ({dd.sector_size[7:1], 1'b0} * 3'd4)) && bus.read_op) begin
|
||||
dd.bm_pending <= 1'b1;
|
||||
end
|
||||
if (bus.real_address == (M_SECTOR_BUFFER + {dd.sector_size[7:1], 1'b0}) && (bus.read_op || bus.write_op)) begin
|
||||
dd.bm_pending <= 1'b1;
|
||||
end
|
||||
if (bus.real_address == (M_BASE + R_CMD_SR) && bus.read_op) begin
|
||||
dd.bm_interrupt <= 1'b0;
|
||||
dd.bm_interrupt_ack <= 1'b1;
|
||||
end
|
||||
|
||||
if (sys.reset || sys.n64_hard_reset) begin
|
||||
dd.hard_reset <= 1'b1;
|
||||
dd.cmd_pending <= 1'b0;
|
||||
dd.cmd_interrupt <= 1'b0;
|
||||
dd.bm_start_pending <= 1'b0;
|
||||
dd.bm_stop_pending <= 1'b0;
|
||||
dd.bm_pending <= 1'b0;
|
||||
dd.bm_interrupt <= 1'b0;
|
||||
state <= S_IDLE;
|
||||
end else begin
|
||||
end else begin
|
||||
case (state)
|
||||
S_IDLE: begin
|
||||
if (bus.request) begin
|
||||
state <= S_WAIT;
|
||||
bus.ack <= 1'b1;
|
||||
if (bus.write) begin
|
||||
case (bus.address[10:0])
|
||||
R_DATA: begin
|
||||
dd.data <= bus.wdata;
|
||||
end
|
||||
|
||||
R_CMD_SR: begin
|
||||
dd.cmd <= bus.wdata[7:0];
|
||||
dd.cmd_pending <= 1'b1;
|
||||
end
|
||||
|
||||
R_BM_SCR: begin
|
||||
dd.sector_num <= bus.wdata[7:0];
|
||||
if (bus.wdata[BM_CONTROL_START_BUFFER_MANAGER]) begin
|
||||
dd.bm_start_pending <= 1'b1;
|
||||
dd.bm_stop_pending <= 1'b0;
|
||||
dd.bm_transfer_mode <= bus.wdata[BM_CONTROL_BUFFER_MANAGER_MODE];
|
||||
dd.bm_transfer_blocks <= bus.wdata[BM_CONTROL_BLOCK_TRANSFER];
|
||||
end
|
||||
if (bus.wdata[BM_CONTROL_BUFFER_MANAGER_RESET]) begin
|
||||
dd.bm_start_pending <= 1'b0;
|
||||
dd.bm_stop_pending <= 1'b1;
|
||||
dd.bm_transfer_mode <= 1'b0;
|
||||
dd.bm_transfer_blocks <= 1'b0;
|
||||
dd.bm_pending <= 1'b0;
|
||||
dd.bm_interrupt <= 1'b0;
|
||||
end
|
||||
if (bus.wdata[BM_CONTROL_MECHANIC_INTERRUPT_RESET]) begin
|
||||
dd.cmd_interrupt <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
R_RESET: begin
|
||||
if (bus.wdata == 16'hAAAA) begin
|
||||
dd.hard_reset <= 1'b1;
|
||||
dd.cmd_pending <= 1'b0;
|
||||
dd.cmd_interrupt <= 1'b0;
|
||||
dd.bm_start_pending <= 1'b0;
|
||||
dd.bm_stop_pending <= 1'b0;
|
||||
dd.bm_pending <= 1'b0;
|
||||
dd.bm_interrupt <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
R_SEC_SIZ: begin
|
||||
dd.sector_size <= bus.wdata[7:0];
|
||||
end
|
||||
|
||||
R_SEC_INFO: begin
|
||||
dd.sectors_in_block <= bus.wdata[15:8];
|
||||
dd.sector_size_full <= bus.wdata[7:0];
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -81,3 +355,50 @@ module n64_dd (
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
module n64_dd_sector_buffer (
|
||||
if_system.sys sys,
|
||||
if_dd.sector_buffer dd
|
||||
);
|
||||
|
||||
logic [5:0] sector_address;
|
||||
logic [31:0] sector_buffer [0:63];
|
||||
logic [15:0] sector_high_buffer;
|
||||
logic sector_write;
|
||||
logic [31:0] sector_wdata;
|
||||
|
||||
always_comb begin
|
||||
sector_address = 6'd0;
|
||||
sector_write = 1'b0;
|
||||
sector_wdata = 32'd0;
|
||||
|
||||
if (dd.n64_sector_address_valid) begin
|
||||
sector_address = dd.n64_sector_address[6:1];
|
||||
end else if (dd.cpu_sector_address_valid) begin
|
||||
sector_address = dd.cpu_sector_address;
|
||||
end
|
||||
|
||||
if (dd.n64_sector_write && dd.n64_sector_address[0]) begin
|
||||
sector_write = 1'b1;
|
||||
sector_wdata = {sector_high_buffer, dd.n64_sector_wdata};
|
||||
end else if (dd.cpu_sector_write) begin
|
||||
sector_write = 1'b1;
|
||||
sector_wdata = dd.cpu_sector_wdata;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge sys.clk) begin
|
||||
if (dd.n64_sector_write && !dd.n64_sector_address[0]) begin
|
||||
sector_high_buffer <= dd.n64_sector_wdata;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge sys.clk) begin
|
||||
dd.sector_rdata <= sector_buffer[sector_address];
|
||||
if (sector_write) begin
|
||||
sector_buffer[sector_address] <= sector_wdata;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
@ -190,6 +190,23 @@ module n64_pi (
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
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
|
||||
|
||||
@ -253,6 +270,11 @@ module n64_pi (
|
||||
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;
|
||||
|
@ -6,6 +6,7 @@ module n64_soc (
|
||||
if_flashram.flashram flashram,
|
||||
if_si.si si,
|
||||
if_flash.memory flash,
|
||||
if_dd dd,
|
||||
|
||||
input n64_pi_alel,
|
||||
input n64_pi_aleh,
|
||||
@ -77,7 +78,13 @@ module n64_soc (
|
||||
|
||||
n64_dd n64_dd_inst (
|
||||
.sys(sys),
|
||||
.bus(bus.at[sc64::ID_N64_DD].device)
|
||||
.bus(bus.at[sc64::ID_N64_DD].device),
|
||||
.dd(dd)
|
||||
);
|
||||
|
||||
n64_dd_sector_buffer n64_dd_sector_buffer_inst (
|
||||
.sys(sys),
|
||||
.dd(dd)
|
||||
);
|
||||
|
||||
n64_cfg n64_cfg_inst (
|
||||
|
@ -21,6 +21,7 @@ package sc64;
|
||||
ID_CPU_SDRAM,
|
||||
ID_CPU_FLASHRAM,
|
||||
ID_CPU_SI,
|
||||
ID_CPU_DD,
|
||||
__ID_CPU_END
|
||||
} e_cpu_id;
|
||||
|
||||
|
@ -14,13 +14,13 @@ typedef struct {
|
||||
} ipl3_crc32_t;
|
||||
|
||||
static const ipl3_crc32_t ipl3_crc32[] = {
|
||||
{ .crc32 = 0x587BD543, .seed = 0xAC, .version = 0 }, // CIC5101
|
||||
{ .crc32 = 0x6170A4A1, .seed = 0x3F, .version = 1 }, // CIC6101
|
||||
{ .crc32 = 0x009E9EA3, .seed = 0x3F, .version = 1 }, // CIC7102
|
||||
{ .crc32 = 0x90BB6CB5, .seed = 0x3F, .version = 0 }, // CICx102
|
||||
{ .crc32 = 0x0B050EE0, .seed = 0x78, .version = 0 }, // CICx103
|
||||
{ .crc32 = 0x98BC2C86, .seed = 0x91, .version = 0 }, // CICx105
|
||||
{ .crc32 = 0xACC8580A, .seed = 0x85, .version = 0 }, // CICx106
|
||||
{ .crc32 = 0x587BD543, .seed = 0xAC, .version = 0 }, // 5101
|
||||
{ .crc32 = 0x6170A4A1, .seed = 0x3F, .version = 1 }, // 6101
|
||||
{ .crc32 = 0x009E9EA3, .seed = 0x3F, .version = 1 }, // 7102
|
||||
{ .crc32 = 0x90BB6CB5, .seed = 0x3F, .version = 0 }, // x102
|
||||
{ .crc32 = 0x0B050EE0, .seed = 0x78, .version = 0 }, // x103
|
||||
{ .crc32 = 0x98BC2C86, .seed = 0x91, .version = 0 }, // x105
|
||||
{ .crc32 = 0xACC8580A, .seed = 0x85, .version = 0 }, // x106
|
||||
{ .crc32 = 0x10C68B18, .seed = 0xDD, .version = 0 }, // NDXJ0
|
||||
{ .crc32 = 0xBC605D0A, .seed = 0xDD, .version = 0 }, // NDDJ0
|
||||
{ .crc32 = 0x502C4466, .seed = 0xDD, .version = 0 }, // NDDJ1
|
||||
@ -43,26 +43,13 @@ bool boot_get_tv_type (boot_info_t *info) {
|
||||
char region = ((pi_io_read(&base[15]) >> 8) & 0xFF);
|
||||
|
||||
switch (region) {
|
||||
case 'D':
|
||||
case 'F':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'P':
|
||||
case 'S':
|
||||
case 'W':
|
||||
case 'X':
|
||||
case 'Y':
|
||||
case 'U':
|
||||
info->tv_type = BOOT_TV_TYPE_PAL;
|
||||
break;
|
||||
|
||||
case '7':
|
||||
case 'A':
|
||||
case 'C':
|
||||
case 'E':
|
||||
case 'J':
|
||||
case 'K':
|
||||
case 'N':
|
||||
case 'U':
|
||||
info->tv_type = BOOT_TV_TYPE_NTSC;
|
||||
break;
|
||||
|
||||
|
@ -65,7 +65,7 @@ void main (void) {
|
||||
}
|
||||
}
|
||||
|
||||
LOG_I("Booting IPL3\r\n\r\n");
|
||||
LOG_I("Booting IPL3\033[0m\r\n\r\n");
|
||||
|
||||
boot(&boot_info);
|
||||
}
|
||||
|
258
sw/pc/sc64.py
258
sw/pc/sc64.py
@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from io import TextIOWrapper
|
||||
from serial import Serial, SerialException
|
||||
from serial.tools import list_ports
|
||||
import argparse
|
||||
@ -7,6 +8,7 @@ import filecmp
|
||||
import os
|
||||
import progressbar
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
import time
|
||||
|
||||
@ -18,9 +20,6 @@ class SC64Exception(Exception):
|
||||
|
||||
|
||||
class SC64:
|
||||
__CFG_ID_SCR = 0
|
||||
__CFG_ID_SDRAM_SWITCH = 1
|
||||
__CFG_ID_SDRAM_WRITABLE = 2
|
||||
__CFG_ID_DD_ENABLE = 3
|
||||
__CFG_ID_SAVE_TYPE = 4
|
||||
__CFG_ID_CIC_SEED = 5
|
||||
@ -32,6 +31,8 @@ class SC64:
|
||||
__CFG_ID_FLASH_READ = 11
|
||||
__CFG_ID_FLASH_PROGRAM = 12
|
||||
__CFG_ID_RECONFIGURE = 13
|
||||
__CFG_ID_DD_SETTING = 14
|
||||
__CFG_ID_DD_THB_TABLE_OFFSET = 15
|
||||
|
||||
__SC64_VERSION_V2 = 0x53437632
|
||||
|
||||
@ -46,7 +47,14 @@ class SC64:
|
||||
__DEBUG_ID_FSD_READ = 0xF1
|
||||
__DEBUG_ID_FSD_WRITE = 0xF2
|
||||
__DEBUG_ID_FSD_SECTOR = 0xF3
|
||||
__DEBUG_ID_DD_BLOCK = 0xF5
|
||||
|
||||
__DD_SETTING_DISK_EJECTED = 0
|
||||
__DD_SETTING_DISK_INSERTED = 1
|
||||
__DD_SETTING_DISK_CHANGED = 2
|
||||
__DD_SETTING_DRIVE_RETAIL = 3
|
||||
__DD_SETTING_DRIVE_DEVELOPMENT = 4
|
||||
__DD_SETTING_SET_BLOCK_READY = 5
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.__serial = None
|
||||
@ -54,6 +62,8 @@ class SC64:
|
||||
self.__progress_value = None
|
||||
self.__progress_finish = None
|
||||
self.__fsd_file = None
|
||||
self.__disk_file = None
|
||||
self.__disk_lba_table = []
|
||||
self.__find_sc64()
|
||||
|
||||
|
||||
@ -87,8 +97,11 @@ class SC64:
|
||||
return re.sub(b"\x1B", b"\x1B\x1B", data)
|
||||
|
||||
|
||||
def __reset_link(self) -> None:
|
||||
def reset_link(self) -> None:
|
||||
self.__serial.write(b"\x1BR")
|
||||
while (self.__serial.in_waiting):
|
||||
self.__serial.read_all()
|
||||
time.sleep(0.1)
|
||||
|
||||
|
||||
def __read(self, bytes: int) -> bytes:
|
||||
@ -141,10 +154,7 @@ class SC64:
|
||||
try:
|
||||
self.__serial = Serial(p.device, timeout=1.0, write_timeout=1.0)
|
||||
self.__serial.flushOutput()
|
||||
self.__reset_link()
|
||||
while (self.__serial.in_waiting):
|
||||
self.__serial.read_all()
|
||||
time.sleep(0.1)
|
||||
self.reset_link()
|
||||
self.__probe_device()
|
||||
except (SerialException, SC64Exception):
|
||||
if (self.__serial):
|
||||
@ -360,6 +370,174 @@ class SC64:
|
||||
self.__write_file_to_sdram(file, dd_ipl_offset, min_length=self.__DDIPL_ROM_LENGTH)
|
||||
|
||||
|
||||
def set_dd_disk_state(self, state: int) -> None:
|
||||
if (state == "ejected"):
|
||||
self.__change_config(self.__CFG_ID_DD_SETTING, self.__DD_SETTING_DISK_EJECTED)
|
||||
elif (state == "inserted"):
|
||||
self.__change_config(self.__CFG_ID_DD_SETTING, self.__DD_SETTING_DISK_INSERTED)
|
||||
elif (state == "changed"):
|
||||
self.__change_config(self.__CFG_ID_DD_SETTING, self.__DD_SETTING_DISK_CHANGED)
|
||||
else:
|
||||
raise SC64Exception("DD disk state outside of supported values")
|
||||
|
||||
|
||||
def __dd_create_configuration(self, handle: TextIOWrapper) -> tuple[str, int, list[tuple[int, int]]]:
|
||||
DISK_HEADS = 2
|
||||
DISK_TRACKS = 1175
|
||||
DISK_BLOCKS_PER_TRACK = 2
|
||||
DISK_SECTORS_PER_BLOCK = 85
|
||||
DISK_BAD_TRACKS_PER_ZONE = 12
|
||||
DISK_SYSTEM_SECTOR_SIZE = 232
|
||||
|
||||
DISK_ZONES = [
|
||||
(0, 232, 158, 0),
|
||||
(0, 216, 158, 158),
|
||||
(0, 208, 149, 316),
|
||||
(0, 192, 149, 465),
|
||||
(0, 176, 149, 614),
|
||||
(0, 160, 149, 763),
|
||||
(0, 144, 149, 912),
|
||||
(0, 128, 114, 1061),
|
||||
(1, 216, 158, 157),
|
||||
(1, 208, 158, 315),
|
||||
(1, 192, 149, 464),
|
||||
(1, 176, 149, 613),
|
||||
(1, 160, 149, 762),
|
||||
(1, 144, 149, 911),
|
||||
(1, 128, 149, 1060),
|
||||
(1, 112, 114, 1174),
|
||||
]
|
||||
|
||||
DISK_VZONE_TO_PZONE = [
|
||||
[0, 1, 2, 9, 8, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10],
|
||||
[0, 1, 2, 3, 10, 9, 8, 4, 5, 6, 7, 15, 14, 13, 12, 11],
|
||||
[0, 1, 2, 3, 4, 11, 10, 9, 8, 5, 6, 7, 15, 14, 13, 12],
|
||||
[0, 1, 2, 3, 4, 5, 12, 11, 10, 9, 8, 6, 7, 15, 14, 13],
|
||||
[0, 1, 2, 3, 4, 5, 6, 13, 12, 11, 10, 9, 8, 7, 15, 14],
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8, 15],
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8],
|
||||
]
|
||||
|
||||
DISK_DRIVE_TYPES = [(
|
||||
"development",
|
||||
192,
|
||||
[11, 10, 3, 2],
|
||||
[0, 1, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23],
|
||||
), (
|
||||
"retail",
|
||||
232,
|
||||
[9, 8, 1, 0],
|
||||
[2, 3, 10, 11, 12, 16, 17, 18, 19, 20, 21, 22, 23],
|
||||
)]
|
||||
|
||||
def __check_system_block(lba: int, sector_size: int, check_disk_type: bool) -> tuple[bool, bytes]:
|
||||
handle.seek(lba * DISK_SYSTEM_SECTOR_SIZE * DISK_SECTORS_PER_BLOCK)
|
||||
system_block_data = handle.read(sector_size * DISK_SECTORS_PER_BLOCK)
|
||||
system_data = system_block_data[:sector_size]
|
||||
for sector in range(1, DISK_SECTORS_PER_BLOCK):
|
||||
sector_data = system_block_data[(sector * sector_size):][:sector_size]
|
||||
if (system_data != sector_data):
|
||||
return (False, None)
|
||||
if (check_disk_type):
|
||||
if (system_data[4] != 0x10):
|
||||
return (False, None)
|
||||
if ((system_data[5] & 0xF0) != 0x10):
|
||||
return (False, None)
|
||||
return (True, system_data)
|
||||
|
||||
disk_drive_type = None
|
||||
disk_system_data = None
|
||||
disk_id_data = None
|
||||
disk_bad_lbas = []
|
||||
|
||||
drive_index = 0
|
||||
while (disk_system_data == None) and (drive_index < len(DISK_DRIVE_TYPES)):
|
||||
(drive_type, system_sector_size, system_data_lbas, bad_lbas) = DISK_DRIVE_TYPES[drive_index]
|
||||
disk_bad_lbas.clear()
|
||||
disk_bad_lbas.extend(bad_lbas)
|
||||
for system_lba in system_data_lbas:
|
||||
(valid, system_data) = __check_system_block(system_lba, system_sector_size, check_disk_type=True)
|
||||
if (valid):
|
||||
disk_drive_type = drive_type
|
||||
disk_system_data = system_data
|
||||
else:
|
||||
disk_bad_lbas.append(system_lba)
|
||||
drive_index += 1
|
||||
|
||||
for id_lba in [15, 14]:
|
||||
(valid, id_data) = __check_system_block(id_lba, DISK_SYSTEM_SECTOR_SIZE, check_disk_type=False)
|
||||
if (valid):
|
||||
disk_id_data = id_data
|
||||
else:
|
||||
disk_bad_lbas.append(id_lba)
|
||||
|
||||
if not (disk_system_data and disk_id_data):
|
||||
raise SC64Exception("Provided 64DD disk file is not valid")
|
||||
|
||||
disk_zone_bad_tracks = []
|
||||
|
||||
for zone in range(len(DISK_ZONES)):
|
||||
zone_bad_tracks = []
|
||||
start = 0 if zone == 0 else system_data[0x07 + zone]
|
||||
stop = system_data[0x07 + zone + 1]
|
||||
for offset in range(start, stop):
|
||||
zone_bad_tracks.append(system_data[0x20 + offset])
|
||||
for ignored_track in range(DISK_BAD_TRACKS_PER_ZONE - len(zone_bad_tracks)):
|
||||
zone_bad_tracks.append(DISK_ZONES[zone][2] - ignored_track - 1)
|
||||
disk_zone_bad_tracks.append(zone_bad_tracks)
|
||||
|
||||
thb_lba_table = [(0xFFFFFFFF, -1)] * (DISK_HEADS * DISK_TRACKS * DISK_BLOCKS_PER_TRACK)
|
||||
|
||||
disk_type = disk_system_data[5] & 0x0F
|
||||
|
||||
current_lba = 0
|
||||
starting_block = 0
|
||||
disk_file_offset = 0
|
||||
|
||||
for zone in DISK_VZONE_TO_PZONE[disk_type]:
|
||||
(head, sector_size, tracks, track) = DISK_ZONES[zone]
|
||||
|
||||
for zone_track in range(tracks):
|
||||
current_zone_track = ((tracks - 1) - zone_track) if head else zone_track
|
||||
|
||||
if (current_zone_track in disk_zone_bad_tracks[zone]):
|
||||
track += (-1) if head else 1
|
||||
continue
|
||||
|
||||
for block in range(DISK_BLOCKS_PER_TRACK):
|
||||
if (current_lba not in disk_bad_lbas):
|
||||
index = (track << 2) | (head << 1) | (starting_block ^ block)
|
||||
thb_lba_table[index] = (disk_file_offset, current_lba)
|
||||
disk_file_offset += sector_size * DISK_SECTORS_PER_BLOCK
|
||||
current_lba += 1
|
||||
|
||||
track += (-1) if head else 1
|
||||
starting_block ^= 1
|
||||
|
||||
return (disk_drive_type, thb_lba_table)
|
||||
|
||||
|
||||
def set_dd_configuration_for_disk(self, file: str = None) -> None:
|
||||
if (file):
|
||||
with open(file, "rb+") as handle:
|
||||
(disk_drive_type, thb_lba_table) = self.__dd_create_configuration(handle)
|
||||
thb_table_offset = self.__query_config(self.__CFG_ID_DD_THB_TABLE_OFFSET)
|
||||
data = bytearray()
|
||||
self.__disk_lba_table = [0xFFFFFFFF] * len(thb_lba_table)
|
||||
for (offset, lba) in thb_lba_table:
|
||||
data += struct.pack(">I", offset)
|
||||
self.__disk_lba_table[lba] = offset
|
||||
self.__write_cmd("W", thb_table_offset, len(data))
|
||||
self.__write(data)
|
||||
self.__read_cmd_status("W")
|
||||
if (disk_drive_type == "retail"):
|
||||
self.__change_config(self.__CFG_ID_DD_SETTING, self.__DD_SETTING_DRIVE_RETAIL)
|
||||
elif (disk_drive_type == "development"):
|
||||
self.__change_config(self.__CFG_ID_DD_SETTING, self.__DD_SETTING_DRIVE_DEVELOPMENT)
|
||||
else:
|
||||
raise SC64Exception("No DD disk file provided for disk info creation")
|
||||
|
||||
|
||||
def __debug_process_fsd_set_sector(self, data: bytes) -> None:
|
||||
sector = int.from_bytes(data[0:4], byteorder='big')
|
||||
if (self.__fsd_file):
|
||||
@ -379,14 +557,36 @@ class SC64:
|
||||
self.__fsd_file.write(data)
|
||||
|
||||
|
||||
def debug_loop(self, file: str = None) -> None:
|
||||
def __debug_process_dd_block(self, data: bytes) -> None:
|
||||
transfer_mode = int.from_bytes(data[0:4], byteorder='big')
|
||||
sdram_offset = int.from_bytes(data[4:8], byteorder='big')
|
||||
disk_file_offset = int.from_bytes(data[8:12], byteorder='big')
|
||||
block_length = int.from_bytes(data[12:16], byteorder='big')
|
||||
|
||||
print(f"64DD Block {'R' if transfer_mode else 'W'} - LBA: {self.__disk_lba_table.index(disk_file_offset):4}, Offset: 0x{disk_file_offset:08X}")
|
||||
|
||||
if (self.__disk_file):
|
||||
self.__disk_file.seek(disk_file_offset)
|
||||
if (transfer_mode):
|
||||
self.__write_cmd("W", sdram_offset, block_length)
|
||||
self.__write(self.__disk_file.read(block_length))
|
||||
self.__read_cmd_status("W")
|
||||
else:
|
||||
self.__write_cmd("R", sdram_offset, block_length)
|
||||
self.__disk_file.write(self.__read_long(block_length))
|
||||
self.__read_cmd_status("R")
|
||||
|
||||
self.__change_config(self.__CFG_ID_DD_SETTING, self.__DD_SETTING_SET_BLOCK_READY)
|
||||
|
||||
|
||||
def debug_loop(self, fsd_file: str = None, disk_file: str = None) -> None:
|
||||
print("\r\n\033[34m --- Debug server started --- \033[0m\r\n")
|
||||
|
||||
self.__serial.timeout = 0.01
|
||||
self.__serial.write_timeout = 1
|
||||
if (fsd_file):
|
||||
self.__fsd_file = open(fsd_file, "rb+")
|
||||
|
||||
if (file):
|
||||
self.__fsd_file = open(file, "rb+")
|
||||
if (disk_file):
|
||||
self.__disk_file = open(disk_file, "rb+")
|
||||
|
||||
start_indicator = bytearray()
|
||||
dropped_bytes = 0
|
||||
@ -406,10 +606,13 @@ class SC64:
|
||||
header = self.__read_long(4)
|
||||
id = int(header[0])
|
||||
length = int.from_bytes(header[1:4], byteorder="big")
|
||||
data = self.__read_long(length)
|
||||
self.__read_long(self.__align(length, 4) - length)
|
||||
end_indicator = self.__read_long(4)
|
||||
|
||||
if (length > 0):
|
||||
data = self.__read_long(length)
|
||||
|
||||
if (end_indicator != b"CMPH"):
|
||||
print(f"\033[35mGot unknown end indicator: {end_indicator.decode(encoding='ascii', errors='backslashreplace')}\033[0m", file=sys.stderr)
|
||||
else:
|
||||
if (id == self.__DEBUG_ID_TEXT):
|
||||
print(data.decode(encoding="ascii", errors="backslashreplace"), end="")
|
||||
elif (id == self.__DEBUG_ID_FSD_READ):
|
||||
@ -418,14 +621,11 @@ class SC64:
|
||||
self.__debug_process_fsd_write(data)
|
||||
elif (id == self.__DEBUG_ID_FSD_SECTOR):
|
||||
self.__debug_process_fsd_set_sector(data)
|
||||
elif (id == self.__DEBUG_ID_DD_BLOCK):
|
||||
self.__debug_process_dd_block(data)
|
||||
else:
|
||||
print(f"\033[35mGot unknown id: {id}, length: {length}\033[0m", file=sys.stderr)
|
||||
|
||||
self.__read_long(self.__align(length, 4) - length)
|
||||
end_indicator = self.__read_long(4)
|
||||
if (end_indicator != b"CMPH"):
|
||||
print(f"\033[35mGot unknown end indicator: {end_indicator.decode(encoding='ascii', errors='backslashreplace')}\033[0m", file=sys.stderr)
|
||||
|
||||
|
||||
|
||||
class SC64ProgressBar:
|
||||
@ -499,6 +699,7 @@ if __name__ == "__main__":
|
||||
parser.add_argument("-i", metavar="ddipl_path", default=None, required=False, help="path to DDIPL file")
|
||||
parser.add_argument("-q", default=None, action="store_true", required=False, help="start debug server")
|
||||
parser.add_argument("-f", metavar="sd_path", default=None, required=False, help="path to disk or file for fake SD card emulation")
|
||||
parser.add_argument("-k", metavar="disk_path", default=None, required=False, help="path to 64DD disk file")
|
||||
parser.add_argument("rom", metavar="rom_path", default=None, help="path to ROM file", nargs="?")
|
||||
|
||||
if (len(sys.argv) <= 1):
|
||||
@ -523,6 +724,7 @@ if __name__ == "__main__":
|
||||
rom_file = args.rom
|
||||
debug_server = args.q
|
||||
sd_file = args.f
|
||||
disk_file = args.k
|
||||
|
||||
firmware_backup_file = "sc64firmware.bin.bak"
|
||||
|
||||
@ -582,7 +784,15 @@ if __name__ == "__main__":
|
||||
sc64.upload_save(save_file)
|
||||
|
||||
if (debug_server):
|
||||
sc64.debug_loop(sd_file)
|
||||
if (sd_file):
|
||||
print(f"Using fake SD emulation file [{sd_file}]")
|
||||
if (disk_file):
|
||||
print(f"Using 64DD disk image file [{disk_file}]")
|
||||
sc64.set_dd_configuration_for_disk(disk_file)
|
||||
if (disk_file):
|
||||
print(f"Setting 64DD disk state to [Changed]")
|
||||
sc64.set_dd_disk_state("changed" if disk_file else "ejected")
|
||||
sc64.debug_loop(sd_file, disk_file)
|
||||
|
||||
except SC64Exception as e:
|
||||
print(f"Error: {e}")
|
||||
@ -590,4 +800,8 @@ if __name__ == "__main__":
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
sc64.reset_link()
|
||||
if (disk_file):
|
||||
print(f"Setting 64DD disk state to [Ejected]")
|
||||
sc64.set_dd_disk_state("ejected")
|
||||
sys.stdout.write("\033[0m")
|
||||
|
@ -12,7 +12,7 @@ LDFLAGS = -nostartfiles -Wl,--gc-sections
|
||||
SRC_DIR = src
|
||||
BUILD_DIR = build
|
||||
|
||||
SRC_FILES = startup.S process.c usb.c cfg.c dma.c joybus.c rtc.c i2c.c flashram.c uart.c flash.c
|
||||
SRC_FILES = startup.S process.c usb.c cfg.c dma.c joybus.c rtc.c i2c.c flashram.c uart.c flash.c dd.c
|
||||
|
||||
SRCS = $(addprefix $(SRC_DIR)/, $(SRC_FILES))
|
||||
OBJS = $(addprefix $(BUILD_DIR)/, $(notdir $(patsubst %,%.o,$(SRCS))))
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "cfg.h"
|
||||
#include "dd.h"
|
||||
#include "flash.h"
|
||||
#include "joybus.h"
|
||||
#include "usb.h"
|
||||
@ -31,6 +32,8 @@ enum cfg_id {
|
||||
CFG_ID_FLASH_READ,
|
||||
CFG_ID_FLASH_PROGRAM,
|
||||
CFG_ID_RECONFIGURE,
|
||||
CFG_ID_DD_SETTING,
|
||||
CFG_ID_DD_THB_TABLE_OFFSET,
|
||||
};
|
||||
|
||||
enum save_type {
|
||||
@ -50,6 +53,15 @@ enum boot_mode {
|
||||
BOOT_MODE_DIRECT = 3,
|
||||
};
|
||||
|
||||
enum dd_setting {
|
||||
DD_SETTING_DISK_EJECTED = 0,
|
||||
DD_SETTING_DISK_INSERTED = 1,
|
||||
DD_SETTING_DISK_CHANGED = 2,
|
||||
DD_SETTING_DRIVE_RETAIL = 3,
|
||||
DD_SETTING_DRIVE_DEVELOPMENT = 4,
|
||||
DD_SETTING_SET_BLOCK_READY = 5,
|
||||
};
|
||||
|
||||
|
||||
struct process {
|
||||
enum save_type save_type;
|
||||
@ -112,6 +124,29 @@ static void set_save_type (enum save_type save_type) {
|
||||
CFG->SAVE_OFFSET = save_offset;
|
||||
}
|
||||
|
||||
static void set_dd_setting (enum dd_setting setting) {
|
||||
switch (setting) {
|
||||
case DD_SETTING_DISK_EJECTED:
|
||||
dd_set_disk_state(DD_DISK_EJECTED);
|
||||
break;
|
||||
case DD_SETTING_DISK_INSERTED:
|
||||
dd_set_disk_state(DD_DISK_INSERTED);
|
||||
break;
|
||||
case DD_SETTING_DISK_CHANGED:
|
||||
dd_set_disk_state(DD_DISK_CHANGED);
|
||||
break;
|
||||
case DD_SETTING_DRIVE_RETAIL:
|
||||
dd_set_drive_type_development(false);
|
||||
break;
|
||||
case DD_SETTING_DRIVE_DEVELOPMENT:
|
||||
dd_set_drive_type_development(true);
|
||||
break;
|
||||
case DD_SETTING_SET_BLOCK_READY:
|
||||
dd_set_block_ready(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t cfg_get_version (void) {
|
||||
return CFG->VERSION;
|
||||
@ -159,11 +194,14 @@ void cfg_update (uint32_t *args) {
|
||||
case CFG_ID_RECONFIGURE:
|
||||
if (args[1] == CFG->RECONFIGURE) {
|
||||
CFG->RECONFIGURE = args[1];
|
||||
__asm__ volatile (
|
||||
asm volatile (
|
||||
"ebreak \n"
|
||||
);
|
||||
}
|
||||
break;
|
||||
case CFG_ID_DD_SETTING:
|
||||
set_dd_setting(args[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,6 +243,9 @@ void cfg_query (uint32_t *args) {
|
||||
case CFG_ID_RECONFIGURE:
|
||||
args[1] = CFG->RECONFIGURE;
|
||||
break;
|
||||
case CFG_ID_DD_THB_TABLE_OFFSET:
|
||||
args[1] = dd_get_thb_table_offset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
440
sw/riscv/src/dd.c
Normal file
440
sw/riscv/src/dd.c
Normal file
@ -0,0 +1,440 @@
|
||||
#include "dd.h"
|
||||
#include "rtc.h"
|
||||
#include "usb.h"
|
||||
|
||||
|
||||
#define DD_USER_SECTORS_PER_BLOCK (85)
|
||||
|
||||
#define DD_BUFFERS_OFFSET (SDRAM_BASE + 0x03BD0000UL)
|
||||
#define DD_THB_TABLE_OFFSET (DD_BUFFERS_OFFSET + 0x0000)
|
||||
#define DD_USB_BUFFER_OFFSET (DD_BUFFERS_OFFSET + 0x5000)
|
||||
#define DD_BLOCK_BUFFER_OFFSET (DD_BUFFERS_OFFSET + 0x6000)
|
||||
|
||||
#define USB_DEBUG_ID_DD_BLOCK (0xF5)
|
||||
|
||||
#define DD_DRIVE_ID_RETAIL (0x0003)
|
||||
#define DD_DRIVE_ID_DEVELOPMENT (0x0004)
|
||||
#define DD_VERSION_RETAIL (0x0114)
|
||||
|
||||
#define DD_POWER_UP_DELAY_TICKS (200000000UL) // 2 s
|
||||
#define DD_TRACK_SEEK_TIME_TICKS (10000) // 0.1 ms
|
||||
|
||||
|
||||
typedef enum {
|
||||
DD_CMD_SEEK_READ = 0x01,
|
||||
DD_CMD_SEEK_WRITE = 0x02,
|
||||
DD_CMD_CLEAR_DISK_CHANGE = 0x08,
|
||||
DD_CMD_CLEAR_RESET_STATE = 0x09,
|
||||
DD_CMD_READ_VERSION = 0x0A,
|
||||
DD_CMD_SET_DISK_TYPE = 0x0B,
|
||||
DD_CMD_REQUEST_STATUS = 0x0C,
|
||||
DD_CMD_SET_RTC_YEAR_MONTH = 0x0F,
|
||||
DD_CMD_SET_RTC_DAY_HOUR = 0x10,
|
||||
DD_CMD_SET_RTC_MINUTE_SECOND = 0x11,
|
||||
DD_CMD_GET_RTC_YEAR_MONTH = 0x12,
|
||||
DD_CMD_GET_RTC_DAY_HOUR = 0x13,
|
||||
DD_CMD_GET_RTC_MINUTE_SECOND = 0x14,
|
||||
DD_CMD_READ_PROGRAM_VERSION = 0x1B,
|
||||
} dd_cmd_t;
|
||||
|
||||
|
||||
enum state {
|
||||
STATE_IDLE,
|
||||
STATE_START,
|
||||
STATE_BLOCK_READ,
|
||||
STATE_BLOCK_READ_WAIT,
|
||||
STATE_SECTOR_READ,
|
||||
STATE_SECTOR_WRITE,
|
||||
STATE_BLOCK_WRITE,
|
||||
STATE_BLOCK_WRITE_WAIT,
|
||||
STATE_NEXT_BLOCK,
|
||||
STATE_STOP,
|
||||
};
|
||||
|
||||
struct process {
|
||||
enum state state;
|
||||
uint32_t track_seek_time;
|
||||
uint32_t next_seek_time;
|
||||
bool power_up_delay;
|
||||
bool deffered_cmd_ready;
|
||||
bool bm_running;
|
||||
bool transfer_mode;
|
||||
bool full_track_transfer;
|
||||
bool starting_block;
|
||||
uint8_t current_sector;
|
||||
bool is_dev_disk;
|
||||
rtc_time_t time;
|
||||
io32_t *thb_table;
|
||||
io32_t *usb_buffer;
|
||||
io32_t *block_buffer;
|
||||
bool block_ready;
|
||||
};
|
||||
|
||||
static struct process p;
|
||||
|
||||
|
||||
static uint16_t dd_track_head_block (void) {
|
||||
uint32_t head_track = DD->HEAD_TRACK;
|
||||
uint16_t track = ((head_track & DD_TRACK_MASK) << 2);
|
||||
uint16_t head = (((head_track & DD_HEAD_MASK) ? 1 : 0) << 1);
|
||||
uint16_t block = (p.starting_block ? 1 : 0);
|
||||
|
||||
return (track | head | block);
|
||||
}
|
||||
|
||||
static bool dd_block_valid (void) {
|
||||
return (p.thb_table[dd_track_head_block()] != 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static bool dd_block_request (void) {
|
||||
if (!usb_debug_tx_ready()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(DD->SCR & DD_SCR_DISK_INSERTED)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *dma = "DMA@";
|
||||
const char *cmp = "CMPH";
|
||||
|
||||
io32_t offset = p.thb_table[dd_track_head_block()];
|
||||
uint32_t length = ((DD->SECTOR_SIZE + 1) * DD_USER_SECTORS_PER_BLOCK);
|
||||
|
||||
io32_t *dst = p.usb_buffer;
|
||||
|
||||
*dst++ = *((uint32_t *) (dma));
|
||||
*dst++ = swap32((USB_DEBUG_ID_DD_BLOCK << 24) | 16);
|
||||
*dst++ = swap32(p.transfer_mode);
|
||||
*dst++ = swap32((uint32_t) (p.block_buffer));
|
||||
*dst++ = offset;
|
||||
*dst++ = swap32(length);
|
||||
*dst++ = *((uint32_t *) (cmp));
|
||||
|
||||
usb_debug_tx_data((uint32_t) (p.usb_buffer), 28);
|
||||
|
||||
p.block_ready = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool dd_block_ready (void) {
|
||||
return p.block_ready || (!(DD->SCR & DD_SCR_DISK_INSERTED));
|
||||
}
|
||||
|
||||
static void dd_sector_read (void) {
|
||||
io32_t *src = p.block_buffer;
|
||||
io32_t *dst = DD->SECTOR_BUFFER;
|
||||
|
||||
uint8_t sector_size = ((DD->SECTOR_SIZE + 1) / sizeof(io32_t));
|
||||
|
||||
src += (sector_size * p.current_sector);
|
||||
|
||||
for (int i = 0; i < sector_size; i++) {
|
||||
*dst++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
static void dd_sector_write (void) {
|
||||
io32_t *src = DD->SECTOR_BUFFER;
|
||||
io32_t *dst = p.block_buffer;
|
||||
|
||||
uint8_t sector_size = ((DD->SECTOR_SIZE + 1) / sizeof(io32_t));
|
||||
|
||||
dst += (sector_size * p.current_sector);
|
||||
|
||||
for (int i = 0; i < sector_size; i++) {
|
||||
*dst++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dd_set_disk_state (disk_state_t disk_state) {
|
||||
uint32_t scr = (DD->SCR & (~(DD_SCR_DISK_CHANGED | DD_SCR_DISK_INSERTED)));
|
||||
|
||||
switch (disk_state) {
|
||||
case DD_DISK_EJECTED:
|
||||
break;
|
||||
case DD_DISK_INSERTED:
|
||||
scr |= DD_SCR_DISK_INSERTED;
|
||||
break;
|
||||
case DD_DISK_CHANGED:
|
||||
scr |= (DD_SCR_DISK_CHANGED | DD_SCR_DISK_INSERTED);
|
||||
break;
|
||||
}
|
||||
|
||||
DD->SCR = scr;
|
||||
}
|
||||
|
||||
void dd_set_drive_type_development (bool value) {
|
||||
if (value) {
|
||||
DD->DRIVE_ID = DD_DRIVE_ID_DEVELOPMENT;
|
||||
p.is_dev_disk = true;
|
||||
} else {
|
||||
DD->DRIVE_ID = DD_DRIVE_ID_RETAIL;
|
||||
p.is_dev_disk = false;
|
||||
}
|
||||
}
|
||||
|
||||
void dd_set_block_ready (bool value) {
|
||||
p.block_ready = value;
|
||||
}
|
||||
|
||||
uint32_t dd_get_thb_table_offset (void) {
|
||||
return (((uint32_t) (p.thb_table)) & 0x0FFFFFFF);
|
||||
}
|
||||
|
||||
|
||||
void dd_init (void) {
|
||||
DD->SCR = 0;
|
||||
DD->HEAD_TRACK = 0;
|
||||
DD->DRIVE_ID = DD_DRIVE_ID_RETAIL;
|
||||
p.state = STATE_IDLE;
|
||||
p.track_seek_time = DD_TRACK_SEEK_TIME_TICKS;
|
||||
p.power_up_delay = true;
|
||||
p.deffered_cmd_ready = false;
|
||||
p.bm_running = false;
|
||||
p.is_dev_disk = false;
|
||||
p.thb_table = (io32_t *) (DD_THB_TABLE_OFFSET);
|
||||
p.usb_buffer = (io32_t *) (DD_USB_BUFFER_OFFSET);
|
||||
p.block_buffer = (io32_t *) (DD_BLOCK_BUFFER_OFFSET);
|
||||
}
|
||||
|
||||
|
||||
void process_dd (void) {
|
||||
uint32_t scr = DD->SCR;
|
||||
|
||||
if (scr & DD_SCR_HARD_RESET) {
|
||||
DD->SCR &= ~(DD_SCR_DISK_CHANGED);
|
||||
DD->HEAD_TRACK = 0;
|
||||
p.state = STATE_IDLE;
|
||||
p.power_up_delay = true;
|
||||
p.deffered_cmd_ready = false;
|
||||
p.bm_running = false;
|
||||
}
|
||||
|
||||
if (scr & DD_SCR_CMD_PENDING) {
|
||||
dd_cmd_t cmd = DD->CMD;
|
||||
uint16_t data = DD->DATA;
|
||||
|
||||
DD->DATA = data;
|
||||
|
||||
if (p.deffered_cmd_ready) {
|
||||
if (DD->SEEK_TIMER >= p.next_seek_time) {
|
||||
p.deffered_cmd_ready = false;
|
||||
DD->HEAD_TRACK = DD_HEAD_TRACK_INDEX_LOCK | data;
|
||||
DD->SCR |= DD_SCR_CMD_READY;
|
||||
}
|
||||
} else if ((cmd == DD_CMD_SEEK_READ) || (cmd == DD_CMD_SEEK_WRITE)) {
|
||||
int track_distance = abs((DD->HEAD_TRACK & DD_TRACK_MASK) - (data & DD_TRACK_MASK));
|
||||
if (p.power_up_delay) {
|
||||
p.power_up_delay = false;
|
||||
p.next_seek_time = DD_POWER_UP_DELAY_TICKS;
|
||||
} else {
|
||||
p.next_seek_time = (track_distance * p.track_seek_time);
|
||||
}
|
||||
p.deffered_cmd_ready = true;
|
||||
DD->HEAD_TRACK &= ~(DD_HEAD_TRACK_INDEX_LOCK);
|
||||
DD->SCR |= DD_SCR_SEEK_TIMER_RESET;
|
||||
} else {
|
||||
switch (cmd) {
|
||||
case DD_CMD_CLEAR_DISK_CHANGE:
|
||||
DD->SCR &= ~(DD_SCR_DISK_CHANGED);
|
||||
break;
|
||||
|
||||
case DD_CMD_CLEAR_RESET_STATE:
|
||||
DD->SCR &= ~(DD_SCR_DISK_CHANGED);
|
||||
DD->SCR |= DD_SCR_HARD_RESET_CLEAR;
|
||||
break;
|
||||
|
||||
case DD_CMD_READ_VERSION:
|
||||
DD->DATA = DD_VERSION_RETAIL;
|
||||
break;
|
||||
|
||||
case DD_CMD_SET_DISK_TYPE:
|
||||
break;
|
||||
|
||||
case DD_CMD_REQUEST_STATUS:
|
||||
DD->DATA = 0;
|
||||
break;
|
||||
|
||||
case DD_CMD_SET_RTC_YEAR_MONTH:
|
||||
p.time.year = ((data >> 8) & 0xFF);
|
||||
p.time.month = (data & 0xFF);
|
||||
break;
|
||||
|
||||
case DD_CMD_SET_RTC_DAY_HOUR:
|
||||
p.time.day = ((data >> 8) & 0xFF);
|
||||
p.time.hour = (data & 0xFF);
|
||||
break;
|
||||
|
||||
case DD_CMD_SET_RTC_MINUTE_SECOND:
|
||||
p.time.minute = ((data >> 8) & 0xFF);
|
||||
p.time.second = (data & 0xFF);
|
||||
rtc_set_time(&p.time);
|
||||
break;
|
||||
|
||||
case DD_CMD_GET_RTC_YEAR_MONTH:
|
||||
DD->DATA = ((p.time.year << 8) | p.time.month);
|
||||
break;
|
||||
|
||||
case DD_CMD_GET_RTC_DAY_HOUR:
|
||||
DD->DATA = ((p.time.day << 8) | p.time.hour);
|
||||
break;
|
||||
|
||||
case DD_CMD_GET_RTC_MINUTE_SECOND:
|
||||
p.time = *rtc_get_time();
|
||||
DD->DATA = ((p.time.minute << 8) | p.time.second);
|
||||
break;
|
||||
|
||||
case DD_CMD_READ_PROGRAM_VERSION:
|
||||
DD->DATA = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DD->SCR |= DD_SCR_CMD_READY;
|
||||
}
|
||||
} else {
|
||||
if (scr & DD_SCR_BM_STOP) {
|
||||
DD->SCR |= DD_SCR_BM_STOP_CLEAR;
|
||||
DD->SCR &= ~(DD_SCR_BM_MICRO_ERROR | DD_SCR_BM_TRANSFER_C2 | DD_SCR_BM_TRANSFER_DATA);
|
||||
p.state = STATE_STOP;
|
||||
} else if (scr & DD_SCR_BM_START) {
|
||||
DD->SCR |= DD_SCR_BM_CLEAR | DD_SCR_BM_ACK_CLEAR | DD_SCR_BM_START_CLEAR;
|
||||
DD->SCR &= ~(DD_SCR_BM_MICRO_ERROR | DD_SCR_BM_TRANSFER_C2 | DD_SCR_BM_TRANSFER_DATA);
|
||||
p.state = STATE_START;
|
||||
p.transfer_mode = (scr & DD_SCR_BM_TRANSFER_MODE);
|
||||
p.full_track_transfer = (scr & DD_SCR_BM_TRANSFER_BLOCKS);
|
||||
p.starting_block = (DD->SECTOR_NUM == (DD->SECTORS_IN_BLOCK + 1));
|
||||
} else if (p.bm_running) {
|
||||
if (scr & DD_SCR_BM_PENDING) {
|
||||
DD->SCR |= DD_SCR_BM_CLEAR;
|
||||
if (p.transfer_mode) {
|
||||
if (p.current_sector < (DD->SECTORS_IN_BLOCK - 4)) {
|
||||
p.state = STATE_SECTOR_READ;
|
||||
} else if (p.current_sector == (DD->SECTORS_IN_BLOCK - 4)) {
|
||||
p.current_sector += 1;
|
||||
DD->SCR &= ~(DD_SCR_BM_TRANSFER_DATA);
|
||||
DD->SCR |= DD_SCR_BM_READY;
|
||||
} else if (p.current_sector == DD->SECTORS_IN_BLOCK) {
|
||||
p.state = STATE_NEXT_BLOCK;
|
||||
}
|
||||
} else {
|
||||
if (p.current_sector < (DD->SECTORS_IN_BLOCK - 4)) {
|
||||
p.state = STATE_SECTOR_WRITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scr & DD_SCR_BM_ACK) {
|
||||
DD->SCR |= DD_SCR_BM_ACK_CLEAR;
|
||||
if (p.transfer_mode) {
|
||||
if ((p.current_sector <= (DD->SECTORS_IN_BLOCK - 4))) {
|
||||
} else if (p.current_sector < (DD->SECTORS_IN_BLOCK - 1)) {
|
||||
p.current_sector += 1;
|
||||
DD->SCR |= DD_SCR_BM_READY;
|
||||
} else if (p.current_sector < DD->SECTORS_IN_BLOCK) {
|
||||
p.current_sector += 1;
|
||||
DD->SCR |= DD_SCR_BM_TRANSFER_C2 | DD_SCR_BM_READY;
|
||||
}
|
||||
} else {
|
||||
if (p.current_sector == (DD->SECTORS_IN_BLOCK - 4)) {
|
||||
p.state = STATE_STOP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (p.state) {
|
||||
case STATE_IDLE:
|
||||
break;
|
||||
|
||||
case STATE_START:
|
||||
p.bm_running = true;
|
||||
p.current_sector = 0;
|
||||
if (p.transfer_mode) {
|
||||
if (dd_block_valid()) {
|
||||
p.state = STATE_BLOCK_READ;
|
||||
DD->SCR |= DD_SCR_BM_TRANSFER_DATA;
|
||||
} else {
|
||||
p.state = STATE_SECTOR_READ;
|
||||
DD->SCR |= DD_SCR_BM_MICRO_ERROR;
|
||||
}
|
||||
} else {
|
||||
p.state = STATE_IDLE;
|
||||
if (dd_block_valid()) {
|
||||
DD->SCR |= DD_SCR_BM_TRANSFER_DATA | DD_SCR_BM_READY;
|
||||
} else {
|
||||
DD->SCR |= DD_SCR_BM_MICRO_ERROR | DD_SCR_BM_READY;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_BLOCK_READ:
|
||||
if (dd_block_request()) {
|
||||
p.state = STATE_BLOCK_READ_WAIT;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_BLOCK_READ_WAIT:
|
||||
if (dd_block_ready()) {
|
||||
p.state = STATE_SECTOR_READ;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_SECTOR_READ:
|
||||
dd_sector_read();
|
||||
p.state = STATE_IDLE;
|
||||
p.current_sector += 1;
|
||||
DD->SCR |= DD_SCR_BM_READY;
|
||||
break;
|
||||
|
||||
case STATE_SECTOR_WRITE:
|
||||
dd_sector_write();
|
||||
p.current_sector += 1;
|
||||
if (p.current_sector < (DD->SECTORS_IN_BLOCK - 4)) {
|
||||
p.state = STATE_IDLE;
|
||||
DD->SCR |= DD_SCR_BM_READY;
|
||||
} else {
|
||||
p.state = STATE_BLOCK_WRITE;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_BLOCK_WRITE:
|
||||
if (dd_block_request()) {
|
||||
p.state = STATE_BLOCK_WRITE_WAIT;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_BLOCK_WRITE_WAIT:
|
||||
if (dd_block_ready()) {
|
||||
p.state = STATE_NEXT_BLOCK;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_NEXT_BLOCK:
|
||||
if (p.full_track_transfer) {
|
||||
p.state = STATE_START;
|
||||
p.full_track_transfer = false;
|
||||
p.starting_block = !p.starting_block;
|
||||
DD->SCR &= ~(DD_SCR_BM_TRANSFER_C2);
|
||||
} else {
|
||||
if (p.transfer_mode) {
|
||||
p.state = STATE_STOP;
|
||||
} else {
|
||||
p.state = STATE_IDLE;
|
||||
DD->SCR &= ~(DD_SCR_BM_TRANSFER_C2 | DD_SCR_BM_TRANSFER_DATA);
|
||||
DD->SCR |= DD_SCR_BM_READY;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_STOP:
|
||||
p.state = STATE_IDLE;
|
||||
p.bm_running = false;
|
||||
break;
|
||||
}
|
||||
}
|
23
sw/riscv/src/dd.h
Normal file
23
sw/riscv/src/dd.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef DD_H__
|
||||
#define DD_H__
|
||||
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
|
||||
typedef enum {
|
||||
DD_DISK_EJECTED,
|
||||
DD_DISK_INSERTED,
|
||||
DD_DISK_CHANGED,
|
||||
} disk_state_t;
|
||||
|
||||
|
||||
void dd_set_disk_state (disk_state_t disk_state);
|
||||
void dd_set_drive_type_development (bool value);
|
||||
void dd_set_block_ready (bool value);
|
||||
uint32_t dd_get_thb_table_offset (void);
|
||||
void dd_init (void);
|
||||
void process_dd (void);
|
||||
|
||||
|
||||
#endif
|
@ -6,6 +6,7 @@
|
||||
#include "rtc.h"
|
||||
#include "i2c.h"
|
||||
#include "flashram.h"
|
||||
#include "dd.h"
|
||||
#include "uart.h"
|
||||
|
||||
|
||||
@ -15,6 +16,7 @@ static const void (*process_table[])(void) = {
|
||||
process_rtc,
|
||||
process_i2c,
|
||||
process_flashram,
|
||||
process_dd,
|
||||
process_uart,
|
||||
NULL,
|
||||
};
|
||||
@ -30,6 +32,7 @@ __attribute__((naked)) void process_loop (void) {
|
||||
rtc_init();
|
||||
i2c_init();
|
||||
flashram_init();
|
||||
dd_init();
|
||||
uart_init();
|
||||
|
||||
while (1) {
|
||||
|
@ -4,10 +4,17 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
#define swap32(x) ((((x) & 0xFF000000UL) >> 24) | \
|
||||
(((x) & 0x00FF0000UL) >> 8) | \
|
||||
(((x) & 0x0000FF00UL) << 8) | \
|
||||
(((x) & 0x000000FFUL) << 24))
|
||||
|
||||
typedef volatile uint8_t io8_t;
|
||||
typedef volatile uint16_t io16_t;
|
||||
typedef volatile uint32_t io32_t;
|
||||
|
||||
|
||||
@ -189,6 +196,55 @@ typedef volatile struct joybus_regs {
|
||||
#define JOYBUS_SCR_TX_LENGTH_BIT (16)
|
||||
|
||||
|
||||
typedef volatile struct dd_regs {
|
||||
io32_t SCR;
|
||||
io16_t DATA;
|
||||
io8_t CMD;
|
||||
io8_t __padding_1;
|
||||
io16_t HEAD_TRACK;
|
||||
io16_t __padding_2;
|
||||
io8_t SECTOR_NUM;
|
||||
io8_t SECTOR_SIZE;
|
||||
io8_t SECTOR_SIZE_FULL;
|
||||
io8_t SECTORS_IN_BLOCK;
|
||||
io16_t DRIVE_ID;
|
||||
io16_t __padding_3;
|
||||
io32_t SEEK_TIMER;
|
||||
io32_t __padding_4[58];
|
||||
io32_t SECTOR_BUFFER[64];
|
||||
} dd_regs_t;
|
||||
|
||||
#define DD_BASE (0xB0000000UL)
|
||||
#define DD ((dd_regs_t *) DD_BASE)
|
||||
|
||||
#define DD_SCR_HARD_RESET (1 << 0)
|
||||
#define DD_SCR_HARD_RESET_CLEAR (1 << 1)
|
||||
#define DD_SCR_CMD_PENDING (1 << 2)
|
||||
#define DD_SCR_CMD_READY (1 << 3)
|
||||
#define DD_SCR_BM_PENDING (1 << 4)
|
||||
#define DD_SCR_BM_READY (1 << 5)
|
||||
#define DD_SCR_DISK_INSERTED (1 << 6)
|
||||
#define DD_SCR_DISK_CHANGED (1 << 7)
|
||||
#define DD_SCR_BM_START (1 << 8)
|
||||
#define DD_SCR_BM_START_CLEAR (1 << 9)
|
||||
#define DD_SCR_BM_STOP (1 << 10)
|
||||
#define DD_SCR_BM_STOP_CLEAR (1 << 11)
|
||||
#define DD_SCR_BM_TRANSFER_MODE (1 << 12)
|
||||
#define DD_SCR_BM_TRANSFER_BLOCKS (1 << 13)
|
||||
#define DD_SCR_BM_TRANSFER_DATA (1 << 14)
|
||||
#define DD_SCR_BM_TRANSFER_C2 (1 << 15)
|
||||
#define DD_SCR_BM_MICRO_ERROR (1 << 16)
|
||||
#define DD_SCR_BM_ACK (1 << 17)
|
||||
#define DD_SCR_BM_ACK_CLEAR (1 << 18)
|
||||
#define DD_SCR_BM_CLEAR (1 << 19)
|
||||
#define DD_SCR_SEEK_TIMER_RESET (1 << 20)
|
||||
|
||||
#define DD_TRACK_MASK (0x0FFF)
|
||||
#define DD_HEAD_MASK (0x1000)
|
||||
#define DD_HEAD_TRACK_MASK (DD_HEAD_MASK | DD_TRACK_MASK)
|
||||
#define DD_HEAD_TRACK_INDEX_LOCK (1 << 13)
|
||||
|
||||
|
||||
void reset_handler(void);
|
||||
|
||||
|
||||
|
@ -151,7 +151,7 @@ void usb_debug_reset (void) {
|
||||
p.debug_rx_busy = false;
|
||||
p.debug_tx_busy = false;
|
||||
|
||||
USB->SCR = USB_SCR_FLUSH_TX | USB_SCR_FLUSH_RX;
|
||||
USB->SCR = USB_SCR_ENABLED | USB_SCR_FLUSH_TX | USB_SCR_FLUSH_RX;
|
||||
}
|
||||
|
||||
static uint8_t rx_cmd_current_byte = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user