diff --git a/fw/rtl/cpu/cpu_dd.sv b/fw/rtl/cpu/cpu_dd.sv index 014c31c..f4227d2 100644 --- a/fw/rtl/cpu/cpu_dd.sv +++ b/fw/rtl/cpu/cpu_dd.sv @@ -29,7 +29,12 @@ module cpu_dd ( bus.rdata = 32'd0; if (bus.ack) begin if (bus.address[8] == M_SECTOR_BUFFER[8]) begin - bus.rdata = dd.sector_rdata; + 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 = { diff --git a/sw/pc/sc64.py b/sw/pc/sc64.py index 7f873b5..039df97 100644 --- a/sw/pc/sc64.py +++ b/sw/pc/sc64.py @@ -48,6 +48,8 @@ class SC64: __DEBUG_ID_FSD_SECTOR = 0xF3 __DEBUG_ID_DD_BLOCK = 0xF5 + __DD_USER_SECTORS_IN_BLOCK = 85 + def __init__(self) -> None: self.__serial = None @@ -381,7 +383,8 @@ class SC64: self.__fsd_file.write(data) - def __dd_track_offset(self, head_track: int) -> int: + def __dd_track_offset(self, head_track: int, sector_size: int) -> int: + # shamelessly stolen from MAME implementation, to be rewritten head = (head_track & 0x1000) >> 9 track = head_track & 0xFFF dd_zone = 0 @@ -412,43 +415,52 @@ class SC64: dd_zone = 0 + head tr_off = track - ddStartOffset = [0x0,0x5F15E0,0xB79D00,0x10801A0,0x1523720,0x1963D80,0x1D414C0,0x20BBCE0, - 0x23196E0,0x28A1E00,0x2DF5DC0,0x3299340,0x36D99A0,0x3AB70E0,0x3E31900,0x4149200] - ddZoneSecSize = [232,216,208,192,176,160,144,128, - 216,208,192,176,160,144,128,112] + ddStartOffset = [ + 0x0000000, + 0x05F15E0, + 0x0B79D00, + 0x10801A0, + 0x1523720, + 0x1963D80, + 0x1D414C0, + 0x20BBCE0, + 0x23196E0, + 0x28A1E00, + 0x2DF5DC0, + 0x3299340, + 0x36D99A0, + 0x3AB70E0, + 0x3E31900, + 0x4149200 + ] - return (dd_zone, ddStartOffset[dd_zone] + tr_off * ddZoneSecSize[dd_zone] * 85 * 2) + return ddStartOffset[dd_zone] + tr_off * sector_size * self.__DD_USER_SECTORS_IN_BLOCK * 2 - # def __dd_zone_track_size(self, i) -> int: - # # ddZoneTrackSize = [158,158,149,149,149,149,149,114,158,158,149,149,149,149,149,114] - # ddZoneSecSize = [232,216,208,192,176,160,144,128, - # 216,208,192,176,160,144,128,112] - # return ddZoneSecSize[i] + def __dd_calculate_file_offset(self, head_track: int, starting_block: int, sector_size: int) -> int: + offset = self.__dd_track_offset(head_track, sector_size) + offset += starting_block * self.__DD_USER_SECTORS_IN_BLOCK * sector_size + return offset def __debug_process_dd_block(self, data: bytes) -> None: - # scr = int.from_bytes(data[0:4], byteorder='big') - current_sector = int.from_bytes(data[4:8], byteorder='little') - head_track = int.from_bytes(data[8:12], byteorder='little') - sector_num = int.from_bytes(data[12:16], byteorder='little') - sector_size = int.from_bytes(data[16:20], byteorder='little') - # sector_size_full = int.from_bytes(data[20:24], byteorder='little') - # sectors_in_block = int.from_bytes(data[24:28], byteorder='little') - # print(f"info: {hex(scr)}, {current_sector}, {head_track}, {sector_num}, {sector_size}, {sector_size_full}, {sectors_in_block}") + transfer_mode = int.from_bytes(data[0:4], byteorder='little') + head_track = int.from_bytes(data[4:6], byteorder='little') + starting_block = int.from_bytes(data[6:7], byteorder='little') + sector_size = int.from_bytes(data[7:8], byteorder='little') + if (self.__disk_file): - (zone, track_offset) = self.__dd_track_offset(head_track) - sector = 0 - sector += track_offset - sector += (int(sector_num / 90) * 85 * (sector_size + 1)) # self.__dd_zone_track_size(zone) - sector += ((current_sector) * (sector_size + 1)) - self.__disk_file.seek(sector) - data_dd = self.__disk_file.read(0x100 * 85) - if (current_sector == 0x00 or current_sector == 0x5A): - print(f"getting sect {hex(sector)}, {hex(int.from_bytes(data_dd[0:4], byteorder='big'))}") - self.__debug_write(self.__DEBUG_ID_DD_BLOCK, data_dd) + file_offset = self.__dd_calculate_file_offset(head_track, starting_block, sector_size) + self.__disk_file.seek(file_offset) + if (transfer_mode): + block_data = self.__disk_file.read(sector_size * self.__DD_USER_SECTORS_IN_BLOCK) + self.__debug_write(self.__DEBUG_ID_DD_BLOCK, block_data) + else: + block_data = self.__read_long(sector_size * self.__DD_USER_SECTORS_IN_BLOCK) + self.__disk_file.write(block_data) else: - self.__debug_write(self.__DEBUG_ID_DD_BLOCK, bytes(0x100)) + if (transfer_mode): + self.__debug_write(self.__DEBUG_ID_DD_BLOCK, bytes(4)) def debug_loop(self, file: str = None, disk_file: str = None) -> None: diff --git a/sw/riscv/src/dd.c b/sw/riscv/src/dd.c index d950cb8..4d4fc5b 100644 --- a/sw/riscv/src/dd.c +++ b/sw/riscv/src/dd.c @@ -1,5 +1,4 @@ #include "dd.h" -#include "uart.h" #include "rtc.h" #include "usb.h" @@ -7,7 +6,10 @@ #define DD_DRIVE_ID_RETAIL (0x0003) #define DD_DRIVE_ID_DEVELOPMENT (0x0004) #define DD_VERSION_RETAIL (0x0114) -#define DD_TRACK_SEEK_TIME_TICKS (10000) +#define DD_POWER_UP_DELAY_TICKS (320000000UL) // 3.2 s +#define DD_TRACK_SEEK_TIME_TICKS (10000) // 0.1 ms +#define DEFAULT_DD_BUFFER_OFFSET (0x03BD8000UL) +#define USB_DEBUG_ID_DD_BLOCK (0xF5) typedef enum { DD_CMD_SEEK_READ = 0x01, @@ -44,6 +46,7 @@ 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; @@ -52,37 +55,32 @@ struct process { uint8_t current_sector; bool is_dev_disk; rtc_time_t time; + io32_t *buffer; }; static struct process p; + enum { READ_PHASE_IDLE, READ_PHASE_STARTED, READ_PHASE_WAIT, } read_phase = READ_PHASE_IDLE; -io32_t *sdram = (io32_t *) (SDRAM_BASE + (32 * 1024 * 1024)); - static void dd_block_read (void) { read_phase = READ_PHASE_STARTED; - io32_t *dst = sdram; + io32_t *dst = p.buffer; + const char *dma = "DMA@"; const char *cmp = "CMPH"; - if (usb_debug_tx_ready()) { - *dst++ = *((uint32_t *) (dma)); - *dst++ = 0xF5 | (7 * 4) << 24; - *dst++ = (uint32_t) DD->SCR; - *dst++ = (uint32_t) p.current_sector; - *dst++ = (uint32_t) DD->HEAD_TRACK; - *dst++ = p.starting_block ? (DD->SECTORS_IN_BLOCK + 1) : 0; - *dst++ = (uint32_t) DD->SECTOR_SIZE; - *dst++ = (uint32_t) DD->SECTOR_SIZE_FULL; - *dst++ = (uint32_t) DD->SECTORS_IN_BLOCK; - *dst++ = *((uint32_t *) (cmp)); - usb_debug_tx_data((uint32_t) (sdram), 10 * 4); - } + *dst++ = *((uint32_t *) (dma)); + *dst++ = (((2 * 4) << 24) | USB_DEBUG_ID_DD_BLOCK); + *dst++ = p.transfer_mode; + *dst++ = (((DD->SECTOR_SIZE + 1) << 24) | (p.starting_block << 16) | DD->HEAD_TRACK); + *dst++ = *((uint32_t *) (cmp)); + + usb_debug_tx_data((uint32_t) (p.buffer), (5 * 4)); } static bool dd_block_read_done (void) { @@ -91,7 +89,7 @@ static bool dd_block_read_done (void) { if (read_phase == READ_PHASE_STARTED) { if (usb_debug_rx_ready(&type, &length)) { - usb_debug_rx_data((uint32_t) (sdram), length); + usb_debug_rx_data((uint32_t) (p.buffer), length); read_phase = READ_PHASE_WAIT; } return false; @@ -107,39 +105,64 @@ static bool dd_block_read_done (void) { } static void dd_sector_read (void) { - io32_t *buf = DD->SEC_BUF; - io32_t *dst = sdram; - uint8_t sector_size = DD->SECTOR_SIZE + 1; + io32_t *src = p.buffer; + io32_t *dst = DD->SECTOR_BUFFER; - dst += ((sector_size * p.current_sector) / sizeof(io32_t)); - for (int i = 0; i < 0x100; i += 4) { - *buf++ = *dst++; + 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.buffer + 4; + + 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++; } } static void dd_block_write (void) { - uart_print("Requesting block write 0x"); - uart_print_08hex(DD->HEAD_TRACK & DD_HEAD_TRACK_MASK); - uart_print("\r\n"); + io32_t *dst = p.buffer; + + const char *dma = "DMA@"; + const char *cmp = "CMPH"; + + uint32_t block_length = ((DD->SECTOR_SIZE + 1) * 85); + + *dst++ = *((uint32_t *) (dma)); + *dst++ = (((2 * 4) << 24) | USB_DEBUG_ID_DD_BLOCK); + *dst++ = p.transfer_mode; + *dst++ = (((DD->SECTOR_SIZE + 1) << 24) | (p.starting_block << 16) | DD->HEAD_TRACK); + dst += block_length / 4; + *dst++ = *((uint32_t *) (cmp)); + usb_debug_tx_data((uint32_t) (p.buffer), ((5 * 4) + block_length)); } static bool dd_block_write_done (void) { - return true; -} - -static void dd_sector_write (void) { + return usb_debug_tx_ready(); } void dd_init (void) { - DD->SCR = 0; + DD->SCR = DD_SCR_DISK_INSERTED; 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.buffer = (io32_t *) (SDRAM_BASE + DEFAULT_DD_BUFFER_OFFSET); } @@ -148,7 +171,9 @@ void process_dd (void) { 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; } @@ -167,7 +192,12 @@ void process_dd (void) { } } 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)); - p.next_seek_time = track_distance * p.track_seek_time; + 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; diff --git a/sw/riscv/src/sys.h b/sw/riscv/src/sys.h index 4945243..d0e23b2 100644 --- a/sw/riscv/src/sys.h +++ b/sw/riscv/src/sys.h @@ -8,9 +8,6 @@ #include -#define CPU_FREQ (100000000UL) - - typedef volatile uint8_t io8_t; typedef volatile uint16_t io16_t; typedef volatile uint32_t io32_t; @@ -209,7 +206,7 @@ typedef volatile struct dd_regs { io16_t __padding_3; io32_t SEEK_TIMER; io32_t __padding_4[58]; - io32_t SEC_BUF[64]; + io32_t SECTOR_BUFFER[64]; } dd_regs_t; #define DD_BASE (0xB0000000UL)