From 7544b3834b1b6c195d974185ad59dd2d17dd8073 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Fri, 17 Apr 2020 19:10:22 -0400 Subject: [PATCH] emul/hw/rc2014: implement blkread in sdc I now get to "fls" in recipes/rc2014/sdcard! --- emul/hw/rc2014/classic.c | 11 ++++++++-- emul/hw/rc2014/sdc.c | 45 +++++++++++++++++++++++++++++++++++++--- emul/hw/rc2014/sdc.h | 6 ++++++ 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/emul/hw/rc2014/classic.c b/emul/hw/rc2014/classic.c index 1791dfd..f04003d 100644 --- a/emul/hw/rc2014/classic.c +++ b/emul/hw/rc2014/classic.c @@ -68,8 +68,8 @@ static void iowr_sdc_cslow(uint8_t val) int main(int argc, char *argv[]) { - if (argc != 2) { - fprintf(stderr, "Usage: ./classic /path/to/rom\n"); + if (argc < 2) { + fprintf(stderr, "Usage: ./classic /path/to/rom [sdcard.img]\n"); return 1; } FILE *fp = fopen(argv[1], "r"); @@ -107,6 +107,10 @@ int main(int argc, char *argv[]) acia_init(&acia); sdc_init(&sdc); + if (argc == 3) { + fprintf(stderr, "Setting up SD card image\n"); + sdc.fp = fopen(argv[2], "r+"); + } m->iord[ACIA_CTL_PORT] = iord_acia_ctl; m->iord[ACIA_DATA_PORT] = iord_acia_data; m->iowr[ACIA_CTL_PORT] = iowr_acia_ctl; @@ -152,5 +156,8 @@ int main(int argc, char *argv[]) tcsetattr(0, TCSADRAIN, &saved_term); emul_printdebug(); } + if (sdc.fp) { + fclose(sdc.fp); + } return 0; } diff --git a/emul/hw/rc2014/sdc.c b/emul/hw/rc2014/sdc.c index f863038..9560698 100644 --- a/emul/hw/rc2014/sdc.c +++ b/emul/hw/rc2014/sdc.c @@ -1,6 +1,16 @@ #include #include "sdc.h" +// Add data to crc with polynomial 0x1021 +// https://stackoverflow.com/a/23726131 +static uint16_t crc16(uint16_t crc, uint8_t data) +{ + uint8_t x = crc >> 8 ^ data; + x ^= x>>4; + crc = (crc << 8) ^ ((uint16_t)(x << 12)) ^ ((uint16_t)(x <<5)) ^ ((uint16_t)x); + return crc; +} + void sdc_init(SDC *sdc) { sdc->selected = false; @@ -8,6 +18,8 @@ void sdc_init(SDC *sdc) sdc->recvidx = 0; sdc->sendidx = -1; sdc->resp = 0xff; + sdc->fp = NULL; + sdc->cmd17bytes = -1; } void sdc_cslow(SDC *sdc) @@ -38,6 +50,20 @@ void sdc_spi_wr(SDC *sdc, uint8_t val) } return; } + if (sdc->cmd17bytes >= 0) { + if (sdc->fp) { + sdc->resp = getc(sdc->fp); + } + sdc->crc16 = crc16(sdc->crc16, sdc->resp); + sdc->cmd17bytes++; + if (sdc->cmd17bytes == 512) { + sdc->sendbuf[3] = sdc->crc16 >> 8; + sdc->sendbuf[4] = sdc->crc16 & 0xff; + sdc->sendidx = 3; + sdc->cmd17bytes = -1; + } + return; + } if ((sdc->recvidx == 0) && ((val > 0x7f) || (val < 0x40))) { // not a command return; @@ -51,8 +77,9 @@ void sdc_spi_wr(SDC *sdc, uint8_t val) val &= 0x3f; sdc->recvidx = 0; uint8_t *b = sdc->recvbuf; - fprintf(stderr, "cmd %02x %02x %02x %02x %02x\n", b[0], b[1], b[2], b[3], b[4]); uint8_t cmd = b[0] & 0x3f; + uint16_t arg1 = (b[1] << 8) | b[2]; + uint16_t arg2 = (b[3] << 8) | b[4]; if (sdc->initstat == 8) { // At this stage, we're expecting CMD0 if (cmd == 0) { @@ -64,7 +91,7 @@ void sdc_spi_wr(SDC *sdc, uint8_t val) } if (sdc->initstat == 9) { // At this stage, we're expecting CMD8 with 0x1aa arg2 - if ((cmd == 8) && (b[3] == 0x01) && (b[4] == 0xaa)) { + if ((cmd == 8) && (arg2 == 0x01aa)) { sdc->initstat++; sdc->sendbuf[0] = 0x01; sdc->sendbuf[1] = 0; @@ -90,7 +117,7 @@ void sdc_spi_wr(SDC *sdc, uint8_t val) } if (sdc->initstat == 11) { // At this stage, we're expecting CMD41 - if ((cmd == 41) && (b[1] == 0x40) && (b[2] == 0x00)) { + if ((cmd == 41) && (arg1 == 0x4000)) { sdc->initstat++; sdc->sendbuf[4] = 0x00; sdc->sendidx = 4; @@ -100,6 +127,18 @@ void sdc_spi_wr(SDC *sdc, uint8_t val) return; } // We have a fully initialized card. + if (cmd == 17) { + if (sdc->fp) { + fseek(sdc->fp, arg2*512, SEEK_SET); + } + sdc->sendbuf[3] = 0x00; + // data token + sdc->sendbuf[4] = 0xfe; + sdc->sendidx = 3; + sdc->cmd17bytes = 0; + sdc->crc16 = 0; + return; + } // Simulate success for any unknown command. sdc->sendbuf[4] = 0x00; sdc->sendidx = 4; diff --git a/emul/hw/rc2014/sdc.h b/emul/hw/rc2014/sdc.h index 22748cd..0d5aa19 100644 --- a/emul/hw/rc2014/sdc.h +++ b/emul/hw/rc2014/sdc.h @@ -19,6 +19,12 @@ typedef struct { // One byte response. When all other response buffers are empty, return // this. uint8_t resp; + // File used for contents read/write + FILE *fp; + // number of bytes read into the current CMD17. -1 means no CMD17 active. + int cmd17bytes; + // running crc16 during read and write operations. + uint16_t crc16; } SDC; void sdc_init(SDC *sdc);