diff options
Diffstat (limited to 'src/pico1541.c')
-rw-r--r-- | src/pico1541.c | 203 |
1 files changed, 197 insertions, 6 deletions
diff --git a/src/pico1541.c b/src/pico1541.c index fec76a3..e46c4b9 100644 --- a/src/pico1541.c +++ b/src/pico1541.c @@ -1,8 +1,17 @@ +#include <stdint.h> + #include <hardware/clocks.h> +#include <hardware/flash.h> #include <hardware/gpio.h> #include <hardware/timer.h> #include <pico/multicore.h> +#include <bsp/board_api.h> +#include <tusb.h> + +#include "ff/ff.h" +#include "ff/diskio.h" + #include "6502.h" #include "6522.h" #include "drive.h" @@ -15,10 +24,14 @@ const uint32_t GPIO_LED = 25; const uint8_t DEVICE = 8; +#define FS_BYTES 1572864 +static uint8_t __in_flash("fs") __attribute__((aligned(4096))) FS[FS_BYTES]; + +static FATFS FAT_FS; + static uint8_t ram[2048]; -extern uint8_t _binary__Users_max_Documents_c64_roms_dos1541_start[16384]; -// extern uint8_t _binary__Users_max_Downloads_blackbird_1_2_Blackbird_1_2_d64_start[174848]; -extern uint8_t _binary__Users_max_Downloads_MementoMori_GP_MementoMori_GP_Disk1_d64_start[174848]; +static uint8_t dos1541[16384]; +static uint8_t disk[174848]; uint32_t ts; cpu_t cpu; @@ -83,14 +96,14 @@ void via_pb_write(via_t *via, uint8_t cycle) { drive.spinning = ((via->ddrb & via->orb) & 4) > 0; gpio_put(GPIO_LED, (via->orb & 0b00001000) > 0 && (via->ddrb & 0b00001000) > 0); - } + } } uint8_t bus_read(uint16_t addr, uint8_t cycle) { if (addr < 2048) { return ram[addr]; } else if (addr >= 0xc000) { - return _binary__Users_max_Documents_c64_roms_dos1541_start[addr - 0xc000]; + return dos1541[addr - 0xc000]; } else if (addr >= 0x1800 && addr < 0x1810) { uint8_t v = 0; via_read(&via1, addr - 0x1800, &v, cycle); @@ -136,9 +149,131 @@ void atn_irq_callback(uint pin, uint32_t flags) { } } +static bool ejected = false; + +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vid[8], uint8_t pid[16], uint8_t rev[4]) { + const char v[] = "TinyUSB"; + const char p[] = "pico1541"; + const char r[] = "1.0"; + + memcpy(vid, v, strlen(v)); + memcpy(pid, p, strlen(p)); + memcpy(rev, r, strlen(r)); +} + +bool tud_msc_test_unit_ready_cb(uint8_t lun) { + if (ejected) { + tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00); + return false; + } + return true; +} + +void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) { + *block_count = FS_BYTES / 512; + *block_size = 512; +} + +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) { + if (load_eject && !start) { + ejected = true; + } + return true; +} + +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) { + if (lba >= FS_BYTES / 512) { + return -1; + } + + uint8_t *addr = FS + 512 * lba + offset; + memcpy(buffer, addr, bufsize); + + return (int32_t)bufsize; +} + +// FIXME This is pretty naive.... +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) { + if (lba >= FS_BYTES / 512) { + return -1; + } + + uint32_t flash_sect = ((lba * 512 + offset) / 4096) * 4096; + uint32_t sect_ofs = lba * 512 + offset - flash_sect; + for (uint32_t i = 0; i < bufsize; i += 4096) { + uint8_t flash_buf[4096]; + memcpy(flash_buf, FS + flash_sect + i, 4096); + + if (i == 0) { + if (bufsize < 4096 - sect_ofs) { + memcpy(flash_buf + sect_ofs, buffer, bufsize); + } else { + memcpy(flash_buf + sect_ofs, buffer, 4096 - sect_ofs); + } + } else if (bufsize - i < 4096) { + memcpy(flash_buf, buffer + i - sect_ofs, bufsize - i); + } else { + memcpy(flash_buf, buffer + i - sect_ofs, 4096); + } + + flash_range_erase((uint32_t)FS + flash_sect - 0x10000000, 4096); + flash_range_program((uint32_t)FS + flash_sect - 0x10000000, flash_buf, 4096); + } + + return (int32_t)bufsize; +} + +bool tud_msc_is_writable_cb(uint8_t lun) { + return true; +} + +int32_t tud_msc_scsi_cb(uint8_t lun, const uint8_t *scsi_cmd, void *buffer, uint16_t bufsize) { + tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + return -1; +} + +DSTATUS disk_status(BYTE pdrv) { + return 0; +} + +DSTATUS disk_initialize(BYTE pdrv) { + return 0; +} + +DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { + memcpy(buff, FS + 512 * sector, 512 * count); + return RES_OK; +} + +DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count) { + // FIXME implement + return RES_ERROR; +} + +DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) { + switch (cmd) { + case CTRL_SYNC: + return RES_OK; + case GET_SECTOR_COUNT: + *(LBA_t *)buff = (FS_BYTES / 512); + return RES_OK; + case GET_SECTOR_SIZE: + *(WORD *)buff = 512; + return RES_OK; + case GET_BLOCK_SIZE: + *(DWORD *)buff = 4096; + return RES_OK; + case CTRL_TRIM: + return RES_OK; + } + + return RES_PARERR; +} + void drive_thread() { drive_init(&drive); - drive.image = _binary__Users_max_Downloads_MementoMori_GP_MementoMori_GP_Disk1_d64_start; + drive.image = disk; + multicore_fifo_push_blocking(1); while (multicore_fifo_pop_blocking_inline()) { @@ -147,6 +282,62 @@ void drive_thread() { } int main() { + board_init(); + tud_init(BOARD_TUD_RHPORT); + if (board_init_after_tusb) { + board_init_after_tusb(); + } + + while (!ejected) { + tud_task(); + } + tud_disconnect(); + + f_mount(&FAT_FS, "0:", 0); + + FIL file; + FRESULT res; + uint32_t btr; + uint32_t br; + + res = f_open(&file, "0:dos1541.bin", FA_READ); + if (res) { + return 0; + } + btr = 16384; + br = 0; + while (btr > 0) { + UINT brr; + if (btr < 4096) { + f_read(&file, dos1541 + br, btr, &brr); + } else { + f_read(&file, dos1541 + br, 4096, &brr); + } + br += brr; + btr -= brr; + } + f_close(&file); + + res = f_open(&file, "0:image.d64", FA_READ); + if (res) { + return 0; + } + btr = 174848; + br = 0; + while (btr > 0) { + UINT brr; + if (btr < 4096) { + f_read(&file, disk + br, btr, &brr); + } else { + f_read(&file, disk + br, 4096, &brr); + } + br += brr; + btr -= brr; + } + f_close(&file); + + f_unmount("0:"); + set_sys_clock_khz(250000, true); multicore_launch_core1(drive_thread); |