From 1c9fd2303fadc5c30e85b17b5d764dbae83504f6 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Wed, 18 Jan 2023 18:08:50 +0000 Subject: [PATCH 01/18] Add simple CI and make the source buildable --- .github/workflows/ci.yml | 35 +++++++++++++++++++++++++++++++++++ ds1202_1302/ds1202_1302.c | 2 +- fdc/86box.h | 2 +- ins8250/ins8250.h | 2 +- z180/z180.c | 2 ++ z180/z80common.h | 2 +- 6 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..56b47da --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +--- +name: CI + +# yamllint disable-line rule:truthy +on: + push: + pull_request: + schedule: + - cron: "0 0 22 * *" + +jobs: + build: + name: Build and test + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Fix Checkout + run: | + git fetch --force --tags + + - name: Run minimal test build + run: | + make all + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: z180emu + path: | + p112 + markiv + makedisk diff --git a/ds1202_1302/ds1202_1302.c b/ds1202_1302/ds1202_1302.c index 93e5b2d..5240dd5 100644 --- a/ds1202_1302/ds1202_1302.c +++ b/ds1202_1302/ds1202_1302.c @@ -42,7 +42,7 @@ #define lib_calloc calloc #define lib_free free -int VERBOSE; +extern int VERBOSE; #define mon_out(x) if (VERBOSE) printf x /* The DS1202 and DS1302 are serial line based RTCs, they have the following features: diff --git a/fdc/86box.h b/fdc/86box.h index 37c65d8..0b7b9b3 100644 --- a/fdc/86box.h +++ b/fdc/86box.h @@ -26,7 +26,7 @@ #define wcscasecmp strcasecmp #define wcslen strlen -int VERBOSE; +extern int VERBOSE; #define LOG(...) do { if (VERBOSE) printf (__VA_ARGS__); } while (0) char *plat_get_extension(char *s); diff --git a/ins8250/ins8250.h b/ins8250/ins8250.h index 34019d2..d6049bb 100644 --- a/ins8250/ins8250.h +++ b/ins8250/ins8250.h @@ -11,7 +11,7 @@ #pragma once -int VERBOSE; +extern int VERBOSE; #include #ifndef LOG #define LOG(...) do { if (VERBOSE) printf (__VA_ARGS__); } while (0) diff --git a/z180/z180.c b/z180/z180.c index 1553150..362a4a2 100644 --- a/z180/z180.c +++ b/z180/z180.c @@ -23,6 +23,8 @@ * *****************************************************************************/ +int VERBOSE; + /* Revision: 2019-01-26 Michal Tomek z180emu */ /***************************************************************************** diff --git a/z180/z80common.h b/z180/z80common.h index 23c3129..a859d0b 100644 --- a/z180/z80common.h +++ b/z180/z80common.h @@ -13,7 +13,7 @@ #ifndef __Z80COMMON_H__ #define __Z80COMMON_H__ -int VERBOSE; +extern int VERBOSE; #include #define logerror printf #define LOG(...) do { if (VERBOSE) logerror (__VA_ARGS__); } while (0) From 68fab3513b93cd31b1c1738e9074a5153e30f9ad Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Wed, 18 Jan 2023 19:30:11 +0000 Subject: [PATCH 02/18] Ignore some files --- .gitignore | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8404162 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ + +# Intermediate objects generated during compile +*.o + +# Compiled output +makedisk +markiv +p112 +sc126 + +# Binary ROMs needed for the emulators +markivrom.bin +p112rom.bin +sc126rom.bin From 3c976e33ffc28ecf51c2b78aeea1c338a953fdbe Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Wed, 18 Jan 2023 19:21:16 +0000 Subject: [PATCH 03/18] Add a callback for SCI data --- markiv.c | 2 +- p112.c | 2 +- z180/z180.c | 17 ++++++++++++++--- z180/z180.h | 3 +++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/markiv.c b/markiv.c index 87cf306..bf27b6e 100644 --- a/markiv.c +++ b/markiv.c @@ -301,7 +301,7 @@ int main(int argc, char** argv) atexit(destroy_rtc); cpu = cpu_create_z180("Z180",Z180_TYPE_Z180,18432000,&ram,NULL,&iospace,irq0ackcallback,NULL/*daisychain*/, - asci_rx,asci_tx,NULL,NULL,NULL,NULL); + asci_rx,asci_tx,NULL,NULL,NULL,NULL,NULL,NULL); //printf("1\n");fflush(stdout); cpu_reset_z180(cpu); //printf("2\n");fflush(stdout); diff --git a/p112.c b/p112.c index 8478977..860445e 100644 --- a/p112.c +++ b/p112.c @@ -406,7 +406,7 @@ int main(int argc, char** argv) fdd_load(BOOT_FDD,"p112-fdd1.img"); cpu = cpu_create_z180("Z182",Z180_TYPE_Z182,16000000,&ram,&rom,&iospace,irq0ackcallback,NULL/*daisychain*/, - NULL,NULL,escc_rx,escc_tx,parport_read,parport_write); + NULL,NULL,NULL,NULL,escc_rx,escc_tx,parport_read,parport_write); //printf("1\n");fflush(stdout); cpu_reset_z180(cpu); //printf("2\n");fflush(stdout); diff --git a/z180/z180.c b/z180/z180.c index 362a4a2..702cf93 100644 --- a/z180/z180.c +++ b/z180/z180.c @@ -1103,8 +1103,12 @@ UINT8 z180_readcontrol(struct z180_state *cpustate, offs_t port) break; case Z180_TRDR: - data = cpustate->IO_TRDR & Z180_TRDR_RMASK; - logerror("Z180 '%s' TRDR rd $%02x ($%02x)\n", cpustate->device->m_tag, data, cpustate->io[port]); + if (cpustate->device->z180csi_rx_cb) + data = cpustate->device->z180csi_rx_cb(cpustate->device,0); + else { + logerror("Z180 '%s' TRDR rd $%02x ($%02x)\n", cpustate->device->m_tag, data, cpustate->io[port]); + data = cpustate->IO_TRDR & Z180_TRDR_RMASK; + } break; case Z180_TMDR0L: @@ -1666,8 +1670,11 @@ void z180_writecontrol(struct z180_state *cpustate, offs_t port, UINT8 data) break; case Z180_TRDR: - LOG("Z180 '%s' TRDR wr $%02x ($%02x)\n", cpustate->device->m_tag, data, data & Z180_TRDR_WMASK); cpustate->IO_TRDR = (cpustate->IO_TRDR & ~Z180_TRDR_WMASK) | (data & Z180_TRDR_WMASK); + if (cpustate->device->z180csi_tx_cb) + cpustate->device->z180csi_tx_cb(cpustate->device,0,data); + else + LOG("Z180 '%s' TRDR wr $%02x ($%02x)\n", cpustate->device->m_tag, data, data & Z180_TRDR_WMASK); break; case Z180_TMDR0L: @@ -2424,6 +2431,7 @@ struct z180_device *cpu_create_z180(char *tag, UINT32 type, UINT32 clock, struct address_space *ram, struct address_space *rom /* only on Z182 */, struct address_space *iospace, device_irq_acknowledge_callback irqcallback, struct z80daisy_interface *daisy_init, rx_callback_t z180asci_rx_cb,tx_callback_t z180asci_tx_cb, + rx_callback_t z180csi_rx_cb, tx_callback_t z180csi_tx_cb, rx_callback_t z80scc_rx_cb,tx_callback_t z80scc_tx_cb /* only on Z182 */, parport_read_callback_t parport_read_cb, parport_write_callback_t parport_write_cb /* only on Z182 */) { @@ -2469,6 +2477,9 @@ struct z180_device *cpu_create_z180(char *tag, UINT32 type, UINT32 clock, d->z180asci = z180asci_device_create(d,d->z180asci_tag,clock, z180asci_rx_cb, z180asci_tx_cb); + d->z180csi_rx_cb = z180csi_rx_cb; + d->z180csi_tx_cb = z180csi_tx_cb; + SZHVC_add = malloc(2*256*256); SZHVC_sub = malloc(2*256*256); diff --git a/z180/z180.h b/z180/z180.h index aec76cf..600dde2 100644 --- a/z180/z180.h +++ b/z180/z180.h @@ -185,6 +185,8 @@ struct z180_device { struct z180asci_device *z180asci; parport_read_callback_t m_parport_read_cb; parport_write_callback_t m_parport_write_cb; + rx_callback_t z180csi_rx_cb; + tx_callback_t z180csi_tx_cb; }; //void cpu_get_info_z180(device_t *device, UINT32 state, cpuinfo *info); @@ -202,6 +204,7 @@ struct z180_device *cpu_create_z180(char *tag, UINT32 type, UINT32 clock, struct address_space *ram, struct address_space *rom /* only on Z182 */, struct address_space *iospace, device_irq_acknowledge_callback irqcallback, struct z80daisy_interface *daisy_init, rx_callback_t z180asci_rx_cb,tx_callback_t z180asci_tx_cb, + rx_callback_t z180csi_rx_cb, tx_callback_t z180csi_tx_cb, rx_callback_t z80scc_rx_cb,tx_callback_t z80scc_tx_cb /* only on Z182 */, parport_read_callback_t parport_read_cb, parport_write_callback_t parport_write_cb /* only on Z182 */); void cpu_reset_z180(device_t *device); From 3f623ce6ff0a3f975416d5b3da11aed2bbb046cb Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Wed, 18 Jan 2023 19:30:02 +0000 Subject: [PATCH 04/18] Initial SC126 support --- Makefile | 11 +- sc126.c | 368 ++++++++++++++++++++++++++++++++++++++++++++++++++++ z180/z180.c | 1 + 3 files changed, 379 insertions(+), 1 deletion(-) create mode 100644 sc126.c diff --git a/Makefile b/Makefile index 5efeade..4758190 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,16 @@ endif CCOPTS ?= -O3 -DSOCKETCONSOLE -std=gnu89 -all: p112 markiv makedisk +all: sc126 p112 markiv makedisk + +sc126: z180.o z180dasm.o z80daisy.o z80scc.o z180asci.o sc126.o rtc_sc126.o ds1202_1302.o + $(CC) $(CCOPTS) -s -o $@ $^ $(SOCKLIB) + +sc126.o: sc126.c sconsole.h z180dbg.h z180/z180.h z180/z80daisy.h z180/z80common.h ds1202_1302/ds1202_1302.h + $(CC) $(CCOPTS) -c $< -o $@ + +rtc_sc126.o: ds1202_1302/rtc.c ds1202_1302/rtc.h + cd ds1202_1302 ; $(CC) $(CCOPTS) -Dmachine_name=\"sc126\" -DHAVE_SYS_TIME_H -DHAVE_GETTIMEOFDAY -o ../rtc_sc126.o -c rtc.c markiv: ide.o z180.o z180dasm.o z80daisy.o z80scc.o z180asci.o markiv.o rtc_markiv.o ds1202_1302.o $(CC) $(CCOPTS) -s -o markiv $^ $(SOCKLIB) diff --git a/sc126.c b/sc126.c new file mode 100644 index 0000000..4357b01 --- /dev/null +++ b/sc126.c @@ -0,0 +1,368 @@ +/* + * markiv.c - Mark IV emulation. + * + * Copyright (c) Michal Tomek 2018-2019 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include +#include +#include +#include +#include + +#ifdef SOCKETCONSOLE +#define BASE_PORT 10180 +#define MAX_SOCKET_PORTS 1 +#include "sconsole.h" +#endif + +#ifdef _WIN32 +#include +#include +#include +#define fileno _fileno +#else +#include +#endif + +#include "z180/z180.h" +#include "ds1202_1302/ds1202_1302.h" + +// so far only 512k EEPROM+512k RAM is supported +UINT8 _ram[1048576]; // lo 512k is ROM + +#define RAMARRAY _ram +#define ROMARRAY NULL +#include "z180dbg.h" + +unsigned int asci_clock = 16; + +rtc_ds1202_1302_t *rtc; + +UINT8 xmem_bank; + +struct z180_device *cpu; + +UINT8 ram_read(offs_t A) { + return _ram[A]; +} + +void ram_write(offs_t A,UINT8 V) { + if (A >= 524288) _ram[A]=V; // low 512k is eprom +} + +int char_available() { +#ifdef SOCKETCONSOLE + return char_available_socket_port(0); +#else + return _kbhit(); +#endif +} + +void asci_tx(device_t *device, int channel, UINT8 Value) { + if (channel==0) { + //printf("TX: %c", Value); +#ifdef SOCKETCONSOLE + tx_socket_port(0, Value); +#else + fputc(Value,stdout); +#endif + //printf("\n"); + } +} + +int asci_rx(device_t *device, int channel) { + int ioData; + if (channel==0) { + //ioData = 0xFF; + if(char_available()) { +#ifdef SOCKETCONSOLE + ioData = rx_socket_port(0); +#else + //printf("RX\n"); + ioData = getch(); +#endif + return ioData; + } + } + return -1; +} + +int irq0ackcallback(device_t *device,int irqnum) { +} + +void print_bin_u8(UINT8 v) { + int bits = 8; + while(bits) { + if (v & 0x80) { + printf("1"); + } else { + printf("0"); + } + v <<= 1; + bits--; + } +} + +UINT8 rtc_latch; + +// The serial port on the Z180 is backwards for SPI sdcards, +// so here is a quick table to bitswap a byte +UINT8 mirtab[256] = { + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, + 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, + 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, + 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, + 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, + 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, + 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, + 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, + 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, + 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, + 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, + 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, + 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, + 0x3F, 0xBF, 0x7F, 0xFF, +}; + +void sci_write(device_t *device, int channel, UINT8 data) { + if ((rtc_latch & 0x04) == 0) { + // The /CS0 is active + // sdcard_write(&sd0, mirtab[data]); + } else { + printf("IO:CSI: TRDR = 0x%02x (latch=", data); + print_bin_u8(rtc_latch); + printf(")\n"); + } +} + +int sci_read(device_t *device, int channel) { + int result = 0xff; + if ((rtc_latch & 0x04) == 0) { + // The /CS0 is active + // result = mirtab[sdcard_read(&sd0, 0xff)]; + } else { + printf("IO:CSI: TRDR (latch="); + print_bin_u8(rtc_latch); + printf(")\n"); + } +} + +UINT8 io_read (offs_t Port) { + Port &= 0xff; + uint8_t ioData = 0; + switch (Port) { + case 0x0c: + ioData |= ds1202_1302_read_data_line(rtc); + // D7 = I2C SDA read TODO + break; + // case 0x0d: LED port, but doesnt support read + + default: + printf("IO:READ: 0x%04x\n",Port); + break; + } + return ioData; +} + +void io_write (offs_t Port,UINT8 Value) { + Port &= 0xff; + switch (Port) { + case 0x0c: + // D0 = I2C SCL + // D1 = Flash Select + // D2 = /SD_CS1 + // D3 = /SD_CS2 + + ds1202_1302_set_lines( + rtc, + Value&0x10?1:0, // D4 = /CE + Value&0x40?1:0, // D6 = SCLK + Value&0x20?0:(Value&0x80?1:0) // D5 = /WE, D7 = Input + ); + + rtc_latch = Value; + + // Try to avoid printing all RTC accesses + if ((Value & 0x10) && (Value & 0xf)!=0) { + printf("IO:CTRL: "); + print_bin_u8(Value); + printf("\n"); + } + + break; + + case 0x0d: + //printf("IO:LED: "); + //print_bin_u8(Value); + //printf("\n"); + break; + + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + // IDE IO=0x10 + break; + + case 0x20: + case 0x22: + case 0x23: + // PPIDE IO=0x20 + break; + + default: + printf("IO:WRITE: 0x%04x = 0x%02x\n",Port,Value); + break; + } +} + +void do_timers() { + //16X clock for ASCI + //printf("asci_clk:%d\n",asci_clock); + if (!--asci_clock) { + z180asci_channel_device_timer(cpu->z180asci->m_chan0); + z180asci_channel_device_timer(cpu->z180asci->m_chan1); + asci_clock = 16; + } +} + +void boot1dma () { + FILE* f; + if (!(f=fopen("sc126rom.bin","rb"))) { + printf("No ROM found.\n"); + g_quit = 1; + } else { + fread(&_ram[0],1,524288,f); + fclose(f); + } +} + +void io_device_update() { +#ifdef SOCKETCONSOLE + // check socket open and optionally reopen it + if (!is_connected_socket_port(0)) open_socket_port(0); +#endif +} + +#ifndef _WIN32 +void sigint_handler(int s) { + // POSIX SIGINT handler + // do nothing +} + +void sigquit_handler(int s) { + // POSIX SIGQUIT handler + // make sure atexit is called + printf("\nExiting emulation.\n"); + shutdown_socket_ports(); // close sockets to prevent waiting for a connection + g_quit = 1; // make sure atexit is called +} +#endif + +void disableCTRLC() { +#ifdef _WIN32 + HANDLE consoleHandle = GetStdHandle(STD_INPUT_HANDLE); + DWORD consoleMode; + GetConsoleMode(consoleHandle,&consoleMode); + SetConsoleMode(consoleHandle,consoleMode&~ENABLE_PROCESSED_INPUT); +#else + signal(SIGINT, sigint_handler); +#endif +} + +struct address_space ram = {ram_read,ram_write,ram_read}; +//struct address_space rom = {rom_read,NULL,rom_read}; +struct address_space iospace = {io_read,io_write,NULL}; + +void destroy_rtc() +{ + ds1202_1302_destroy(rtc,1); +} + +int main(int argc, char** argv) +{ + printf("z180emu v1.0 sc126\n"); + + disableCTRLC(); +#ifndef _WIN32 + // on POSIX, route SIGQUIT (CTRL+\) to graceful shutdown + signal(SIGQUIT, sigquit_handler); +#endif + // on MINGW, keep CTRL+Break (and window close button) enabled + // MINGW always calls atexit in these cases + +#ifdef SOCKETCONSOLE + init_TCPIP(); + init_socket_port(0); // ASCI Console + atexit(shutdown_socket_ports); +#endif + io_device_update(); // wait for serial socket connections + + if (argc > 1 && !strcmp(argv[1],"d")) { + if (argc == 3) { + starttrace = atoll(argv[2]); + } else { + starttrace = 0; + } + } + VERBOSE = starttrace==0?1:0; + +#ifdef _WIN32 + setmode(fileno(stdout), O_BINARY); +#endif + + boot1dma(); + + rtc = ds1202_1302_init("RTC",1302); + ds1202_1302_reset(rtc); + atexit(destroy_rtc); + + cpu = cpu_create_z180("Z180",Z180_TYPE_Z180,18432000,&ram,NULL,&iospace,irq0ackcallback,NULL/*daisychain*/, + asci_rx,asci_tx,sci_read,sci_write,NULL,NULL,NULL,NULL); + //printf("1\n");fflush(stdout); + cpu_reset_z180(cpu); + //printf("2\n");fflush(stdout); + + struct timeval t0; + struct timeval t1; + gettimeofday(&t0, 0); + int runtime=50000; + + //g_quit = 0; + while(!g_quit) { + if(instrcnt>=starttrace) VERBOSE=1; + cpu_execute_z180(cpu,10000); + //printf("3\n");fflush(stdout); + io_device_update(); + /*if (!(--runtime)) + g_quit=1;*/ + } + gettimeofday(&t1, 0); + printf("instrs:%llu, time:%g\n",instrcnt, (t1.tv_sec - t0.tv_sec) * 1000.0f + (t1.tv_usec - t0.tv_usec) / 1000.0f); +} diff --git a/z180/z180.c b/z180/z180.c index 702cf93..2cb556e 100644 --- a/z180/z180.c +++ b/z180/z180.c @@ -1099,6 +1099,7 @@ UINT8 z180_readcontrol(struct z180_state *cpustate, offs_t port) case Z180_CNTR: data = cpustate->IO_CNTR & Z180_CNTR_RMASK; data &= ~0x10; // Super Famicom Box sets the TE bit then wants it to be toggled after 8 bits transmitted + data &= ~0x20; // Clear the RE LOG("Z180 '%s' CNTR rd $%02x ($%02x)\n", cpustate->device->m_tag, data, cpustate->io[port]); break; From 86a70e17de4099970282808ba48a11d9123393f4 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 21 Jan 2023 18:37:59 +0000 Subject: [PATCH 05/18] fuzix manages to cause addresses outside the possible range --- sc126.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sc126.c b/sc126.c index 4357b01..32b6b58 100644 --- a/sc126.c +++ b/sc126.c @@ -60,11 +60,17 @@ UINT8 xmem_bank; struct z180_device *cpu; UINT8 ram_read(offs_t A) { - return _ram[A]; + A &= 0xfffff; + return _ram[A]; } void ram_write(offs_t A,UINT8 V) { - if (A >= 524288) _ram[A]=V; // low 512k is eprom + A &= 0xfffff; + + // low 512k is eprom + if (A >= 524288) { + _ram[A]=V; + } } int char_available() { From c9062ad62dbb081cecbd1630b47102e508b6d0d7 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 21 Jan 2023 17:16:18 +0000 Subject: [PATCH 06/18] Add sdcard driver --- Makefile | 6 +- sc126.c | 12 +- sdcard/sdcard.c | 298 ++++++++++++++++++++++++++++++++++++++++++++++++ sdcard/sdcard.h | 33 ++++++ 4 files changed, 342 insertions(+), 7 deletions(-) create mode 100644 sdcard/sdcard.c create mode 100644 sdcard/sdcard.h diff --git a/Makefile b/Makefile index 4758190..bdf9c0f 100644 --- a/Makefile +++ b/Makefile @@ -6,11 +6,11 @@ CCOPTS ?= -O3 -DSOCKETCONSOLE -std=gnu89 all: sc126 p112 markiv makedisk -sc126: z180.o z180dasm.o z80daisy.o z80scc.o z180asci.o sc126.o rtc_sc126.o ds1202_1302.o - $(CC) $(CCOPTS) -s -o $@ $^ $(SOCKLIB) +sc126: z180.o z180dasm.o z80daisy.o z80scc.o z180asci.o sc126.o rtc_sc126.o ds1202_1302.o sdcard/sdcard.o + $(CC) $(CCOPTS) -g -o $@ $^ $(SOCKLIB) sc126.o: sc126.c sconsole.h z180dbg.h z180/z180.h z180/z80daisy.h z180/z80common.h ds1202_1302/ds1202_1302.h - $(CC) $(CCOPTS) -c $< -o $@ + $(CC) $(CCOPTS) -g -c $< -o $@ rtc_sc126.o: ds1202_1302/rtc.c ds1202_1302/rtc.h cd ds1202_1302 ; $(CC) $(CCOPTS) -Dmachine_name=\"sc126\" -DHAVE_SYS_TIME_H -DHAVE_GETTIMEOFDAY -o ../rtc_sc126.o -c rtc.c diff --git a/sc126.c b/sc126.c index 32b6b58..f768011 100644 --- a/sc126.c +++ b/sc126.c @@ -43,6 +43,7 @@ #include "z180/z180.h" #include "ds1202_1302/ds1202_1302.h" +#include "sdcard/sdcard.h" // so far only 512k EEPROM+512k RAM is supported UINT8 _ram[1048576]; // lo 512k is ROM @@ -126,8 +127,6 @@ void print_bin_u8(UINT8 v) { } } -UINT8 rtc_latch; - // The serial port on the Z180 is backwards for SPI sdcards, // so here is a quick table to bitswap a byte UINT8 mirtab[256] = { @@ -155,10 +154,13 @@ UINT8 mirtab[256] = { 0x3F, 0xBF, 0x7F, 0xFF, }; +UINT8 rtc_latch; +struct sdcard_device sd0; + void sci_write(device_t *device, int channel, UINT8 data) { if ((rtc_latch & 0x04) == 0) { // The /CS0 is active - // sdcard_write(&sd0, mirtab[data]); + sdcard_write(&sd0, mirtab[data]); } else { printf("IO:CSI: TRDR = 0x%02x (latch=", data); print_bin_u8(rtc_latch); @@ -170,12 +172,13 @@ int sci_read(device_t *device, int channel) { int result = 0xff; if ((rtc_latch & 0x04) == 0) { // The /CS0 is active - // result = mirtab[sdcard_read(&sd0, 0xff)]; + result = mirtab[sdcard_read(&sd0, 0xff)]; } else { printf("IO:CSI: TRDR (latch="); print_bin_u8(rtc_latch); printf(")\n"); } + return result; } UINT8 io_read (offs_t Port) { @@ -344,6 +347,7 @@ int main(int argc, char** argv) #endif boot1dma(); + sdcard_reset(&sd0); rtc = ds1202_1302_init("RTC",1302); ds1202_1302_reset(rtc); diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c new file mode 100644 index 0000000..f721cd6 --- /dev/null +++ b/sdcard/sdcard.c @@ -0,0 +1,298 @@ +/* + * Simple sdcard in SPI mode emulation + * (c)2023 Hamish Coleman + * + * TODO: + * - actually provide a backing file! + */ + +#include +#include +#include + + +typedef uint8_t UINT8; + +#include "sdcard.h" + +int sdcard_trace = 1; + +void sdcard_reset(struct sdcard_device *sd) { + memset((void *)sd, 0, sizeof(*sd)); +} + +void sdcard_dump(struct sdcard_device *sd) { + printf("SD:DUMP: s%i,t%x,r%x, ", + sd->state, + sd->cmd_ptr, + sd->resp_ptr + ); + + int i; + for (i=0; icmd); i++) { + printf("%02x", sd->cmd[i]); + } + printf("-"); + for (i=0; i<20; i++) { + printf("%02x", sd->resp[i]); + } + printf("\n"); + +} + +int sdcard_write(struct sdcard_device *sd, UINT8 data) { + if (sdcard_trace) { + sdcard_dump(sd); + printf("SD:WR: d=0x%02x\n", data); + } + + if (sd->state == TX_RESP) { + // got a write when we thought we needed a read + sdcard_reset(sd); + } + if (sd->state == IDLE) { + sdcard_reset(sd); + if (data &0x80) { + // if the first byte of a cmd doesnt have b7=0, b6=1 + // this is probably a dummy write, stay in IDLE + return 0xff; // in write state, return is ignored + } + sd->state = RX_CMD; + } else if (sd->state == WRITE_BLOCK) { + // FIXME - implement a buffer! + return 0xff; // in write state, return is ignored + } + // else bad state? + + sd->cmd[sd->cmd_ptr] = data; + sd->cmd_ptr = (sd->cmd_ptr & 0x07) + 1; + + if (sd->cmd_ptr != 6) { + return 0xff; // in write state, return is ignored + } + + UINT8 cmd = sd->cmd[0]; + + // we have a whole cmd + // should start with 0b01xxxxxx (x = cmd) + // should end with 0bccccccc1 (c = crc) + + // TODO: check cmd[5] CRC + + int rp = 0; + switch (cmd) { + case 0x40: // CMD0 GO_IDLE_STATE + case 0x77: // CMD55 APP_CMD + sdcard_reset(sd); + sd->resp[0] = 0xff; + sd->resp[1] = 0x01; + sd->state = TX_RESP; + break; + case 0x48: // CMD8 SEND_IF_COND + // TODO: check arg 00 00 01 aa + sdcard_reset(sd); + sd->resp[0] = 0xff; + sd->resp[1] = 0x01; + sd->resp[2] = 0x00; + sd->resp[3] = 0x00; + sd->resp[4] = 0x01; + sd->resp[5] = 0xaa; + sd->state = TX_RESP; + break; + case 0x49: // CMD9 SEND_CSD + sdcard_reset(sd); + sd->resp[rp++] = 0xff; + sd->resp[rp++] = 0x01; + sd->resp[rp++] = 0xfe; // data token + + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; // LBA + sd->resp[rp++] = 0x08; // . + sd->resp[rp++] = 0x00; // . + sd->resp[rp++] = 0x00; // Approx 1Gig + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + // TODO: use real sizes + + sd->resp[rp++] = 0x05; // CRC1 + sd->resp[rp++] = 0x0a; // CRC2 + sd->state = TX_RESP; + break; + case 0x4a: // CMD10 SEND_CID + sdcard_reset(sd); + sd->resp[rp++] = 0xff; + sd->resp[rp++] = 0x01; + sd->resp[rp++] = 0xfe; // data token + + sd->resp[rp++] = 0x01; // Manuf + sd->resp[rp++] = 'A'; // App + sd->resp[rp++] = 'A'; + sd->resp[rp++] = 'B'; // Name + sd->resp[rp++] = 'B'; + sd->resp[rp++] = 'B'; + sd->resp[rp++] = 'B'; + sd->resp[rp++] = 'B'; + sd->resp[rp++] = 0x10; // Rev + sd->resp[rp++] = 0x12; // Serial + sd->resp[rp++] = 0x34; + sd->resp[rp++] = 0x56; + sd->resp[rp++] = 0x78; + sd->resp[rp++] = 0x00; // 2YY + sd->resp[rp++] = 0x01; // YM + sd->resp[rp++] = 0x00; + + sd->resp[rp++] = 0x05; // CRC1 + sd->resp[rp++] = 0x0a; // CRC2 + sd->state = TX_RESP; + break; + case 0x50: // CMD16 SET_BLOCKLEN + // TODO: do a real check of the value + if (sd->cmd[3] != 2) { + goto error; + } + sdcard_reset(sd); + sd->resp[0] = 0xff; + sd->resp[1] = 0x01; + sd->state = TX_RESP; + break; + case 0x51: { // CMD17 READ_SINGLE_BLOCK + int block = ( + sd->cmd[1]<<24 | + sd->cmd[2]<<16 | + sd->cmd[3]<<8 | + sd->cmd[4] + ); + printf("SD:READ: 0x%04x\n", block); + + sdcard_reset(sd); + sd->resp[rp++] = 0xff; + sd->resp[rp++] = 0x01; + sd->resp[rp++] = 0xfe; // data token + + int *p = (int*)&sd->resp[8]; + *p = block; + + sd->resp[512+3+0] = 0x05; // CRC + sd->resp[512+3+1] = 0x0a; + sd->state = TX_RESP; + break; + } + case 0x58: { // CMD24 WRITE_BLOCK + int block = ( + sd->cmd[1]<<24 | + sd->cmd[2]<<16 | + sd->cmd[3]<<8 | + sd->cmd[4] + ); + printf("SD:WRITE: 0x%04x\n", block); + + sdcard_reset(sd); + sd->resp[rp++] = 0xff; + sd->resp[rp++] = 0x01; + + sd->state = PRE_WRITE_STAT; + break; + } + + case 0x7a: // CMD58 READ_OCR + sdcard_reset(sd); + sd->resp[0] = 0xff; + sd->resp[1] = 0x01; + sd->resp[2] = 0x40; // bit30 == HCS + sd->resp[3] = 0x00; + sd->resp[4] = 0x00; + sd->resp[5] = 0x00; + sd->state = TX_RESP; + break; + + // TODO: gate ACMD values on a previous CMD55 APP_CMD + case 0x69: // ACMD41 SEND_OP_COND + sdcard_reset(sd); + sd->resp[0] = 0xff; + sd->resp[1] = 0x00; + sd->state = TX_RESP; + break; + case 0x73: // ACMD51 SEND_SCR + sdcard_reset(sd); + sd->resp[rp++] = 0xff; + sd->resp[rp++] = 0x01; + sd->resp[rp++] = 0xfe; // data token + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x30; // SD_SEC_2 == SDHC + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x05; // CRC1 + sd->resp[rp++] = 0x0a; // CRC2 + sd->state = TX_RESP; + break; + +error: + default: + sdcard_reset(sd); + sd->resp[0] = 0xff; + sd->resp[1] = 0x05; // illegal command + sd->state = TX_RESP; + + printf("unknown\n"); + printf("SD:CMD: cmd=0x%02x\n",cmd); + + sdcard_reset(sd); + return 0xff; // in write state, return is ignored + } + if (sdcard_trace) { + printf("\n"); + } +} + +int sdcard_read(struct sdcard_device *sd, UINT8 data) { + UINT8 result; + if (sdcard_trace) { + sdcard_dump(sd); + } + + if (sd->state == RX_CMD) { + // got a read when we expected more writes + sdcard_reset(sd); + } + if (sd->state == WRITE_BLOCK) { + // got the read after the end of a write block + sd->state = TX_RESP; + result = 0x05; // Data accepted + goto out; + } + if (sd->state == IDLE) { + // in idle mode, the card just outputs ones? + result = 0xff; + goto out; + } + + result = sd->resp[sd->resp_ptr]; + sd->resp_ptr = sd->resp_ptr + 1; + if (sd->resp_ptr >= sizeof(sd->resp)) { + sd->resp_ptr = 0; + } + + if (sd->state == PRE_WRITE_STAT && sd->resp_ptr == 2) { + sd->state = WRITE_BLOCK; + } + +out: + if (sdcard_trace) { + printf("SD:RD: r=0x%02x\n", result); + } + return result; +} + diff --git a/sdcard/sdcard.h b/sdcard/sdcard.h new file mode 100644 index 0000000..1cc20a9 --- /dev/null +++ b/sdcard/sdcard.h @@ -0,0 +1,33 @@ +/* + * Simple sdcard in SPI mode emulation + * (c)2023 Hamish Coleman + * + * Public interface definitions + */ +#ifndef SDCARD_H +#define SDCARD_H + +enum sdcard_state { + IDLE = 0, + RX_CMD, + TX_RESP, + PRE_WRITE_STAT, + WRITE_BLOCK, +}; + +struct sdcard_device { + enum sdcard_state state; + int cmd_ptr; + int resp_ptr; + UINT8 cmd[8]; + UINT8 resp[512+6]; +}; + +extern int sdcard_trace; + +// TODO: technically, SPI is simultaneous readwrite +int sdcard_read(struct sdcard_device *device, UINT8 data); +int sdcard_write(struct sdcard_device *device, UINT8 data); +void sdcard_reset(struct sdcard_device *sd); + +#endif From 32283fff62fa69265650d3cfa93db61be54fabd5 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 21 Jan 2023 18:07:34 +0000 Subject: [PATCH 07/18] Reduce partial compile issues and debugsymbol paths by using well described dependancies --- Makefile | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index bdf9c0f..5f3901c 100644 --- a/Makefile +++ b/Makefile @@ -4,16 +4,19 @@ endif CCOPTS ?= -O3 -DSOCKETCONSOLE -std=gnu89 -all: sc126 p112 markiv makedisk +CFLAGS ?= $(CCOPTS) -g +LDFLAGS ?= $(SOCKLIB) -sc126: z180.o z180dasm.o z80daisy.o z80scc.o z180asci.o sc126.o rtc_sc126.o ds1202_1302.o sdcard/sdcard.o - $(CC) $(CCOPTS) -g -o $@ $^ $(SOCKLIB) +all: sc126 p112 markiv makedisk -sc126.o: sc126.c sconsole.h z180dbg.h z180/z180.h z180/z80daisy.h z180/z80common.h ds1202_1302/ds1202_1302.h - $(CC) $(CCOPTS) -g -c $< -o $@ +sc126.c: sconsole.h z180dbg.h z180/z180.h z180/z80daisy.h z180/z80common.h ds1202_1302/ds1202_1302.h sdcard/sdcard.h +sc126: sc126.o +sc126: z180/z180.o z180/z180dasm.o z180/z80daisy.o z180/z80scc.o z180/z180asci.o +sc126: ds1202_1302/rtc_sc126.o ds1202_1302/ds1202_1302.o +sc126: sdcard/sdcard.o -rtc_sc126.o: ds1202_1302/rtc.c ds1202_1302/rtc.h - cd ds1202_1302 ; $(CC) $(CCOPTS) -Dmachine_name=\"sc126\" -DHAVE_SYS_TIME_H -DHAVE_GETTIMEOFDAY -o ../rtc_sc126.o -c rtc.c +ds1202_1302/rtc_sc126.o: ds1202_1302/rtc.c ds1202_1302/rtc.h + $(CC) $(CFLAGS) -Dmachine_name=\"sc126\" -DHAVE_SYS_TIME_H -DHAVE_GETTIMEOFDAY -o $@ -c $< markiv: ide.o z180.o z180dasm.o z80daisy.o z80scc.o z180asci.o markiv.o rtc_markiv.o ds1202_1302.o $(CC) $(CCOPTS) -s -o markiv $^ $(SOCKLIB) From cdeb69e84a585955cdac7647256dc3da963a4dc0 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Mon, 23 Jan 2023 20:08:56 +0000 Subject: [PATCH 08/18] fix deps --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5f3901c..c9de2eb 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,8 @@ LDFLAGS ?= $(SOCKLIB) all: sc126 p112 markiv makedisk -sc126.c: sconsole.h z180dbg.h z180/z180.h z180/z80daisy.h z180/z80common.h ds1202_1302/ds1202_1302.h sdcard/sdcard.h + +sc126.o: sc126.c sconsole.h z180dbg.h z180/z180.h z180/z80daisy.h z180/z80common.h ds1202_1302/ds1202_1302.h sdcard/sdcard.h sc126: sc126.o sc126: z180/z180.o z180/z180dasm.o z180/z80daisy.o z180/z80scc.o z180/z180asci.o sc126: ds1202_1302/rtc_sc126.o ds1202_1302/ds1202_1302.o From e3185507d661b918f43f76df800ae281301e029f Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 21 Jan 2023 18:37:22 +0000 Subject: [PATCH 09/18] Turn off optimisation for easier debugging --- Makefile | 2 +- sc126.c | 2 +- sdcard/sdcard.c | 30 +++++++++++++++++++++++------- sdcard/sdcard.h | 2 ++ 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index c9de2eb..e39cb23 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ endif CCOPTS ?= -O3 -DSOCKETCONSOLE -std=gnu89 -CFLAGS ?= $(CCOPTS) -g +CFLAGS ?= -DSOCKETCONSOLE -g LDFLAGS ?= $(SOCKLIB) all: sc126 p112 markiv makedisk diff --git a/sc126.c b/sc126.c index f768011..ffef091 100644 --- a/sc126.c +++ b/sc126.c @@ -347,7 +347,7 @@ int main(int argc, char** argv) #endif boot1dma(); - sdcard_reset(&sd0); + sdcard_init(&sd0,"sd00.img"); rtc = ds1202_1302_init("RTC",1302); ds1202_1302_reset(rtc); diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index f721cd6..5666e32 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -3,13 +3,15 @@ * (c)2023 Hamish Coleman * * TODO: - * - actually provide a backing file! + * - hook up writes + * - improve the CSD to reflect the actual size of the backing file */ #include #include #include - +#include +#include typedef uint8_t UINT8; @@ -18,7 +20,19 @@ typedef uint8_t UINT8; int sdcard_trace = 1; void sdcard_reset(struct sdcard_device *sd) { + sd->state = IDLE; + sd->cmd_ptr = 0; + sd->resp_ptr = 0; +} + +int sdcard_init(struct sdcard_device *sd, char *filename) { memset((void *)sd, 0, sizeof(*sd)); + sdcard_reset(sd); + + if ((sd->fd = open(filename, O_RDWR))==-1) { + return -1; + } + return 1; } void sdcard_dump(struct sdcard_device *sd) { @@ -174,12 +188,13 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { printf("SD:READ: 0x%04x\n", block); sdcard_reset(sd); - sd->resp[rp++] = 0xff; - sd->resp[rp++] = 0x01; - sd->resp[rp++] = 0xfe; // data token + sd->resp[0] = 0xff; + sd->resp[1] = 0x01; + sd->resp[2] = 0xfe; // data token - int *p = (int*)&sd->resp[8]; - *p = block; + if (lseek(sd->fd, block*0x200, SEEK_SET) != -1) { + read(sd->fd, &sd->resp[3], 0x200); + } sd->resp[512+3+0] = 0x05; // CRC sd->resp[512+3+1] = 0x0a; @@ -270,6 +285,7 @@ int sdcard_read(struct sdcard_device *sd, UINT8 data) { if (sd->state == WRITE_BLOCK) { // got the read after the end of a write block sd->state = TX_RESP; + result = 0x05; // Data accepted goto out; } diff --git a/sdcard/sdcard.h b/sdcard/sdcard.h index 1cc20a9..78695d1 100644 --- a/sdcard/sdcard.h +++ b/sdcard/sdcard.h @@ -16,6 +16,7 @@ enum sdcard_state { }; struct sdcard_device { + int fd; enum sdcard_state state; int cmd_ptr; int resp_ptr; @@ -29,5 +30,6 @@ extern int sdcard_trace; int sdcard_read(struct sdcard_device *device, UINT8 data); int sdcard_write(struct sdcard_device *device, UINT8 data); void sdcard_reset(struct sdcard_device *sd); +int sdcard_init(struct sdcard_device *sd, char *filename); #endif From f797de2b5a5e6f24241efd52ab6a8f9b717d8966 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Mon, 23 Jan 2023 19:56:48 +0000 Subject: [PATCH 10/18] Add more logging --- sdcard/sdcard.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 5666e32..cf7c077 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -17,6 +17,10 @@ typedef uint8_t UINT8; #include "sdcard.h" +#define dprint(level, ...) do { \ + if (sdcard_trace >= level) printf (__VA_ARGS__); \ +} while(0) + int sdcard_trace = 1; void sdcard_reset(struct sdcard_device *sd) { @@ -63,12 +67,14 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { if (sd->state == TX_RESP) { // got a write when we thought we needed a read sdcard_reset(sd); + dprint(1,"SD: got write, expected read\n"); } if (sd->state == IDLE) { sdcard_reset(sd); if (data &0x80) { // if the first byte of a cmd doesnt have b7=0, b6=1 // this is probably a dummy write, stay in IDLE + dprint(1,"SD: got dummy write?\n"); return 0xff; // in write state, return is ignored } sd->state = RX_CMD; @@ -96,6 +102,7 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { int rp = 0; switch (cmd) { case 0x40: // CMD0 GO_IDLE_STATE + dprint(1,"SD: CMD0 GO_IDLE_STATE\n"); case 0x77: // CMD55 APP_CMD sdcard_reset(sd); sd->resp[0] = 0xff; @@ -103,6 +110,7 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { sd->state = TX_RESP; break; case 0x48: // CMD8 SEND_IF_COND + dprint(1,"SD: CMD8 SEND_IF_COND\n"); // TODO: check arg 00 00 01 aa sdcard_reset(sd); sd->resp[0] = 0xff; @@ -114,6 +122,7 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { sd->state = TX_RESP; break; case 0x49: // CMD9 SEND_CSD + dprint(1,"SD: CMD9 SEND_CSD\n"); sdcard_reset(sd); sd->resp[rp++] = 0xff; sd->resp[rp++] = 0x01; @@ -142,6 +151,7 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { sd->state = TX_RESP; break; case 0x4a: // CMD10 SEND_CID + dprint(1,"SD: CMD10 SEND_CID\n"); sdcard_reset(sd); sd->resp[rp++] = 0xff; sd->resp[rp++] = 0x01; @@ -169,8 +179,10 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { sd->state = TX_RESP; break; case 0x50: // CMD16 SET_BLOCKLEN + dprint(1,"SD: CMD16 SET_BLOCKLEN\n"); // TODO: do a real check of the value if (sd->cmd[3] != 2) { + dprint(1,"SD: unexpected blocklen\n"); goto error; } sdcard_reset(sd); @@ -179,13 +191,14 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { sd->state = TX_RESP; break; case 0x51: { // CMD17 READ_SINGLE_BLOCK + dprint(1,"SD: CMD17 READ_SINGLE_BLOCK\n"); int block = ( sd->cmd[1]<<24 | sd->cmd[2]<<16 | sd->cmd[3]<<8 | sd->cmd[4] ); - printf("SD:READ: 0x%04x\n", block); + dprint(1,"SD:READ: 0x%04x\n", block); sdcard_reset(sd); sd->resp[0] = 0xff; @@ -202,13 +215,14 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { break; } case 0x58: { // CMD24 WRITE_BLOCK + dprint(1,"SD: CMD24 WRITE_BLOCK\n"); int block = ( sd->cmd[1]<<24 | sd->cmd[2]<<16 | sd->cmd[3]<<8 | sd->cmd[4] ); - printf("SD:WRITE: 0x%04x\n", block); + dprint(1,"SD:WRITE: 0x%04x\n", block); sdcard_reset(sd); sd->resp[rp++] = 0xff; @@ -219,6 +233,7 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { } case 0x7a: // CMD58 READ_OCR + dprint(1,"SD: CMD58 READ_OCR\n"); sdcard_reset(sd); sd->resp[0] = 0xff; sd->resp[1] = 0x01; @@ -231,12 +246,14 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { // TODO: gate ACMD values on a previous CMD55 APP_CMD case 0x69: // ACMD41 SEND_OP_COND + dprint(1,"SD: ACMD41 SEND_OP_COND\n"); sdcard_reset(sd); sd->resp[0] = 0xff; sd->resp[1] = 0x00; sd->state = TX_RESP; break; case 0x73: // ACMD51 SEND_SCR + dprint(1,"SD: ACMD51 SEND_SCR\n"); sdcard_reset(sd); sd->resp[rp++] = 0xff; sd->resp[rp++] = 0x01; @@ -261,8 +278,8 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { sd->resp[1] = 0x05; // illegal command sd->state = TX_RESP; - printf("unknown\n"); - printf("SD:CMD: cmd=0x%02x\n",cmd); + dprint(1,"unknown\n"); + dprint(1,"SD:CMD: cmd=0x%02x\n",cmd); sdcard_reset(sd); return 0xff; // in write state, return is ignored @@ -281,16 +298,19 @@ int sdcard_read(struct sdcard_device *sd, UINT8 data) { if (sd->state == RX_CMD) { // got a read when we expected more writes sdcard_reset(sd); + dprint(1,"SD: read when RX_CMD\n"); } if (sd->state == WRITE_BLOCK) { // got the read after the end of a write block sd->state = TX_RESP; + dprint(1,"SD: FIXME write data accepted\n"); result = 0x05; // Data accepted goto out; } if (sd->state == IDLE) { // in idle mode, the card just outputs ones? + dprint(1,"SD: read while IDLE\n"); result = 0xff; goto out; } From ebfe150fee98b2e70c7efd13b20a5fcc860928a5 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Mon, 23 Jan 2023 19:58:17 +0000 Subject: [PATCH 11/18] Clarify state transitions and structure resets --- sdcard/sdcard.c | 70 ++++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index cf7c077..f754a02 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -23,15 +23,26 @@ typedef uint8_t UINT8; int sdcard_trace = 1; -void sdcard_reset(struct sdcard_device *sd) { - sd->state = IDLE; +void sdcard_setstate(struct sdcard_device *sd, enum sdcard_state newstate) { + if (sd->state != newstate) { + dprint(1,"SD: old=%i, new=%i\n", sd->state, newstate); + } + sd->state = newstate; +} + +void sdcard_reset_ptr(struct sdcard_device *sd) { sd->cmd_ptr = 0; sd->resp_ptr = 0; } +void sdcard_reset(struct sdcard_device *sd) { + sdcard_setstate(sd, IDLE); + sdcard_reset_ptr(sd); +} + int sdcard_init(struct sdcard_device *sd, char *filename) { memset((void *)sd, 0, sizeof(*sd)); - sdcard_reset(sd); + sdcard_reset_ptr(sd); if ((sd->fd = open(filename, O_RDWR))==-1) { return -1; @@ -70,14 +81,14 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { dprint(1,"SD: got write, expected read\n"); } if (sd->state == IDLE) { - sdcard_reset(sd); if (data &0x80) { // if the first byte of a cmd doesnt have b7=0, b6=1 // this is probably a dummy write, stay in IDLE dprint(1,"SD: got dummy write?\n"); return 0xff; // in write state, return is ignored } - sd->state = RX_CMD; + sdcard_setstate(sd, RX_CMD); + sdcard_reset_ptr(sd); } else if (sd->state == WRITE_BLOCK) { // FIXME - implement a buffer! return 0xff; // in write state, return is ignored @@ -104,26 +115,25 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { case 0x40: // CMD0 GO_IDLE_STATE dprint(1,"SD: CMD0 GO_IDLE_STATE\n"); case 0x77: // CMD55 APP_CMD - sdcard_reset(sd); sd->resp[0] = 0xff; sd->resp[1] = 0x01; - sd->state = TX_RESP; + sdcard_setstate(sd, TX_RESP); + sdcard_reset_ptr(sd); break; case 0x48: // CMD8 SEND_IF_COND dprint(1,"SD: CMD8 SEND_IF_COND\n"); // TODO: check arg 00 00 01 aa - sdcard_reset(sd); sd->resp[0] = 0xff; sd->resp[1] = 0x01; sd->resp[2] = 0x00; sd->resp[3] = 0x00; sd->resp[4] = 0x01; sd->resp[5] = 0xaa; - sd->state = TX_RESP; + sdcard_setstate(sd, TX_RESP); + sdcard_reset_ptr(sd); break; case 0x49: // CMD9 SEND_CSD dprint(1,"SD: CMD9 SEND_CSD\n"); - sdcard_reset(sd); sd->resp[rp++] = 0xff; sd->resp[rp++] = 0x01; sd->resp[rp++] = 0xfe; // data token @@ -148,11 +158,11 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { sd->resp[rp++] = 0x05; // CRC1 sd->resp[rp++] = 0x0a; // CRC2 - sd->state = TX_RESP; + sdcard_setstate(sd, TX_RESP); + sdcard_reset_ptr(sd); break; case 0x4a: // CMD10 SEND_CID dprint(1,"SD: CMD10 SEND_CID\n"); - sdcard_reset(sd); sd->resp[rp++] = 0xff; sd->resp[rp++] = 0x01; sd->resp[rp++] = 0xfe; // data token @@ -176,7 +186,8 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { sd->resp[rp++] = 0x05; // CRC1 sd->resp[rp++] = 0x0a; // CRC2 - sd->state = TX_RESP; + sdcard_setstate(sd, TX_RESP); + sdcard_reset_ptr(sd); break; case 0x50: // CMD16 SET_BLOCKLEN dprint(1,"SD: CMD16 SET_BLOCKLEN\n"); @@ -185,10 +196,10 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { dprint(1,"SD: unexpected blocklen\n"); goto error; } - sdcard_reset(sd); sd->resp[0] = 0xff; sd->resp[1] = 0x01; - sd->state = TX_RESP; + sdcard_setstate(sd, TX_RESP); + sdcard_reset_ptr(sd); break; case 0x51: { // CMD17 READ_SINGLE_BLOCK dprint(1,"SD: CMD17 READ_SINGLE_BLOCK\n"); @@ -200,7 +211,6 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { ); dprint(1,"SD:READ: 0x%04x\n", block); - sdcard_reset(sd); sd->resp[0] = 0xff; sd->resp[1] = 0x01; sd->resp[2] = 0xfe; // data token @@ -211,7 +221,8 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { sd->resp[512+3+0] = 0x05; // CRC sd->resp[512+3+1] = 0x0a; - sd->state = TX_RESP; + sdcard_setstate(sd, TX_RESP); + sdcard_reset_ptr(sd); break; } case 0x58: { // CMD24 WRITE_BLOCK @@ -224,37 +235,36 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { ); dprint(1,"SD:WRITE: 0x%04x\n", block); - sdcard_reset(sd); sd->resp[rp++] = 0xff; sd->resp[rp++] = 0x01; - sd->state = PRE_WRITE_STAT; + sdcard_setstate(sd, PRE_WRITE_STAT); + sdcard_reset_ptr(sd); break; } case 0x7a: // CMD58 READ_OCR dprint(1,"SD: CMD58 READ_OCR\n"); - sdcard_reset(sd); sd->resp[0] = 0xff; sd->resp[1] = 0x01; sd->resp[2] = 0x40; // bit30 == HCS sd->resp[3] = 0x00; sd->resp[4] = 0x00; sd->resp[5] = 0x00; - sd->state = TX_RESP; + sdcard_setstate(sd, TX_RESP); + sdcard_reset_ptr(sd); break; // TODO: gate ACMD values on a previous CMD55 APP_CMD case 0x69: // ACMD41 SEND_OP_COND dprint(1,"SD: ACMD41 SEND_OP_COND\n"); - sdcard_reset(sd); sd->resp[0] = 0xff; sd->resp[1] = 0x00; - sd->state = TX_RESP; + sdcard_setstate(sd, TX_RESP); + sdcard_reset_ptr(sd); break; case 0x73: // ACMD51 SEND_SCR dprint(1,"SD: ACMD51 SEND_SCR\n"); - sdcard_reset(sd); sd->resp[rp++] = 0xff; sd->resp[rp++] = 0x01; sd->resp[rp++] = 0xfe; // data token @@ -268,20 +278,20 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { sd->resp[rp++] = 0x00; sd->resp[rp++] = 0x05; // CRC1 sd->resp[rp++] = 0x0a; // CRC2 - sd->state = TX_RESP; + sdcard_setstate(sd, TX_RESP); + sdcard_reset_ptr(sd); break; error: default: - sdcard_reset(sd); sd->resp[0] = 0xff; sd->resp[1] = 0x05; // illegal command - sd->state = TX_RESP; + sdcard_setstate(sd, TX_RESP); + sdcard_reset_ptr(sd); dprint(1,"unknown\n"); dprint(1,"SD:CMD: cmd=0x%02x\n",cmd); - sdcard_reset(sd); return 0xff; // in write state, return is ignored } if (sdcard_trace) { @@ -302,7 +312,7 @@ int sdcard_read(struct sdcard_device *sd, UINT8 data) { } if (sd->state == WRITE_BLOCK) { // got the read after the end of a write block - sd->state = TX_RESP; + sdcard_setstate(sd, TX_RESP); dprint(1,"SD: FIXME write data accepted\n"); result = 0x05; // Data accepted @@ -322,7 +332,7 @@ int sdcard_read(struct sdcard_device *sd, UINT8 data) { } if (sd->state == PRE_WRITE_STAT && sd->resp_ptr == 2) { - sd->state = WRITE_BLOCK; + sdcard_setstate(sd, WRITE_BLOCK); } out: From 04279f7bf1c3e082c66ed5e442e3f74926b0a0d4 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Mon, 23 Jan 2023 19:59:37 +0000 Subject: [PATCH 12/18] Pass the chipselect value into the device, allowing better simulation --- sc126.c | 22 ++++++---------------- sdcard/sdcard.c | 23 +++++++++++++++++------ sdcard/sdcard.h | 5 ++--- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/sc126.c b/sc126.c index ffef091..677e75b 100644 --- a/sc126.c +++ b/sc126.c @@ -158,26 +158,16 @@ UINT8 rtc_latch; struct sdcard_device sd0; void sci_write(device_t *device, int channel, UINT8 data) { - if ((rtc_latch & 0x04) == 0) { - // The /CS0 is active - sdcard_write(&sd0, mirtab[data]); - } else { - printf("IO:CSI: TRDR = 0x%02x (latch=", data); - print_bin_u8(rtc_latch); - printf(")\n"); - } + int cs0 = (rtc_latch & 0x04) == 0; + sdcard_write(&sd0, cs0, mirtab[data]); } int sci_read(device_t *device, int channel) { + int cs0 = (rtc_latch & 0x04) == 0; int result = 0xff; - if ((rtc_latch & 0x04) == 0) { - // The /CS0 is active - result = mirtab[sdcard_read(&sd0, 0xff)]; - } else { - printf("IO:CSI: TRDR (latch="); - print_bin_u8(rtc_latch); - printf(")\n"); - } + result = mirtab[sdcard_read(&sd0, cs0, 0xff)]; + // TODO: multiple cards requires knowing if DO was driven + return result; } diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index f754a02..1657138 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -69,8 +69,14 @@ void sdcard_dump(struct sdcard_device *sd) { } -int sdcard_write(struct sdcard_device *sd, UINT8 data) { - if (sdcard_trace) { +int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { + if (!cs) { + // Not for us, dont drive any bits in reply + return 0; + // TODO: detect init sequence + } + + if (sdcard_trace>1) { sdcard_dump(sd); printf("SD:WR: d=0x%02x\n", data); } @@ -294,14 +300,19 @@ int sdcard_write(struct sdcard_device *sd, UINT8 data) { return 0xff; // in write state, return is ignored } - if (sdcard_trace) { + if (sdcard_trace>1) { printf("\n"); } } -int sdcard_read(struct sdcard_device *sd, UINT8 data) { +int sdcard_read(struct sdcard_device *sd, int cs, UINT8 data) { + if (!cs) { + // Not for us, dont drive any bits in reply + return 0; + } + UINT8 result; - if (sdcard_trace) { + if (sdcard_trace>1) { sdcard_dump(sd); } @@ -336,7 +347,7 @@ int sdcard_read(struct sdcard_device *sd, UINT8 data) { } out: - if (sdcard_trace) { + if (sdcard_trace>1) { printf("SD:RD: r=0x%02x\n", result); } return result; diff --git a/sdcard/sdcard.h b/sdcard/sdcard.h index 78695d1..5cfabdb 100644 --- a/sdcard/sdcard.h +++ b/sdcard/sdcard.h @@ -27,9 +27,8 @@ struct sdcard_device { extern int sdcard_trace; // TODO: technically, SPI is simultaneous readwrite -int sdcard_read(struct sdcard_device *device, UINT8 data); -int sdcard_write(struct sdcard_device *device, UINT8 data); -void sdcard_reset(struct sdcard_device *sd); +int sdcard_read(struct sdcard_device *device, int cs, UINT8 data); +int sdcard_write(struct sdcard_device *device, int cs, UINT8 data); int sdcard_init(struct sdcard_device *sd, char *filename); #endif From a2cef89c073fcb3cd327de51b0aaa715c8ec5d86 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Mon, 23 Jan 2023 23:47:51 +0000 Subject: [PATCH 13/18] Switch to a much clearer state machine for sdcards --- sdcard/sdcard.c | 464 +++++++++++++++++++++++++++++++----------------- sdcard/sdcard.h | 13 +- 2 files changed, 310 insertions(+), 167 deletions(-) diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 1657138..2fd8309 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -23,9 +23,24 @@ typedef uint8_t UINT8; int sdcard_trace = 1; +char *sdcard_state_names[] = { + [IDLE] = "IDLE", + [RX_CMD] = "RX_CMD", + [TX_R1] = "TX_R1", + [TX_R3] = "TX_R3", + [TX_R7] = "TX_R7", + [TX_R1_TX_BLOCK] = "TX_R1_TX_BLOCK", + [TX_R1_RX_BLOCK] = "TX_R1_RX_BLOCK", + [RX_BLOCK] = "RX_BLOCK", + [TX_RX_BLOCK_STAT] = "TX_RX_BLOCK_STAT", +}; + void sdcard_setstate(struct sdcard_device *sd, enum sdcard_state newstate) { if (sd->state != newstate) { - dprint(1,"SD: old=%i, new=%i\n", sd->state, newstate); + dprint(1,"SD: %s -> %s\n", + sdcard_state_names[sd->state], + sdcard_state_names[newstate] + ); } sd->state = newstate; } @@ -33,6 +48,7 @@ void sdcard_setstate(struct sdcard_device *sd, enum sdcard_state newstate) { void sdcard_reset_ptr(struct sdcard_device *sd) { sd->cmd_ptr = 0; sd->resp_ptr = 0; + sd->tx_len = 0; } void sdcard_reset(struct sdcard_device *sd) { @@ -69,6 +85,49 @@ void sdcard_dump(struct sdcard_device *sd) { } +#define R1_0 0x00 +#define R1_OK 0x01 +#define R1_ILL_CMD 0x05 +void sdcard_resp_r1(struct sdcard_device *sd, UINT8 r1) { + sd->resp_ptr = 0; + // TODO: sd->tx_len = 0; + sd->r1 = r1; + sdcard_setstate(sd, TX_R1); +} + +void sdcard_resp_reply32(struct sdcard_device *sd, int reply) { + sd->resp[0] = (reply >> 24) & 0xff; + sd->resp[1] = (reply >> 16) & 0xff; + sd->resp[2] = (reply >> 8) & 0xff; + sd->resp[3] = reply & 0xff; +} + +void sdcard_resp_r3(struct sdcard_device *sd, int reply) { + sd->resp_ptr = 0; + // TODO: sd->tx_len = 4; + sdcard_resp_reply32(sd, reply); + sdcard_setstate(sd, TX_R3); +} + +void sdcard_resp_r7(struct sdcard_device *sd, int reply) { + sd->resp_ptr = 0; + // TODO: sd->tx_len = 4; + sdcard_resp_reply32(sd, reply); + sdcard_setstate(sd, TX_R7); +} + +void sdcard_resp_tx_block(struct sdcard_device *sd, int tx_len) { + sd->resp_ptr = 0; + sd->tx_len = tx_len; + sdcard_setstate(sd, TX_R1_TX_BLOCK); +} + +void sdcard_resp_rx_block(struct sdcard_device *sd) { + sd->resp_ptr = 0; + sd->tx_len = 0; // We are overwriting it, so it must be zero + sdcard_setstate(sd, TX_R1_RX_BLOCK); +} + int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { if (!cs) { // Not for us, dont drive any bits in reply @@ -81,36 +140,76 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { printf("SD:WR: d=0x%02x\n", data); } - if (sd->state == TX_RESP) { - // got a write when we thought we needed a read - sdcard_reset(sd); - dprint(1,"SD: got write, expected read\n"); - } - if (sd->state == IDLE) { - if (data &0x80) { - // if the first byte of a cmd doesnt have b7=0, b6=1 - // this is probably a dummy write, stay in IDLE - dprint(1,"SD: got dummy write?\n"); - return 0xff; // in write state, return is ignored - } - sdcard_setstate(sd, RX_CMD); - sdcard_reset_ptr(sd); - } else if (sd->state == WRITE_BLOCK) { - // FIXME - implement a buffer! - return 0xff; // in write state, return is ignored - } - // else bad state? + switch (sd->state) { + case TX_R1: + case TX_R3: + case TX_R7: + case TX_R1_TX_BLOCK: + case TX_R1_RX_BLOCK: + case TX_RX_BLOCK_STAT: + // got a write when we thought we needed a read + dprint(2,"SD: got write, expected read (data=0x%02x)\n", data); + /* FALL THROUGH */ + + case IDLE: + if ((data & 0xc0) != 0x40) { + // The first two bits of a command must be 0,1 + // otherwise, we stay in IDLE + dprint(2,"SD: got dummy write?\n"); + return 0xff; // TODO: signal that we didnt drive DO + } - sd->cmd[sd->cmd_ptr] = data; - sd->cmd_ptr = (sd->cmd_ptr & 0x07) + 1; + sdcard_setstate(sd, RX_CMD); + sdcard_reset_ptr(sd); + /* FALL THROUGH */ - if (sd->cmd_ptr != 6) { - return 0xff; // in write state, return is ignored + case RX_CMD: + sd->cmd[sd->cmd_ptr++] = data; + if (sd->cmd_ptr < 6) { + return 0xff; // in write state, return is ignored + } + break; + + case RX_BLOCK: + if (sd->resp_ptr == 0) { + // data token + if (data != 0xfe) { + dprint(1,"SD: unexpected data token 0x%02x\n", data); + sdcard_reset(sd); + } + } else if (sd->resp_ptr < 514) { + int index = sd->resp_ptr-1; + sd->resp[index] = data; + } else if (sd->resp_ptr == 515) { + // ignore CRC1 + } else { + // ignore CRC2 + + // process entire block + int block = ( + sd->cmd[1]<<24 | + sd->cmd[2]<<16 | + sd->cmd[3]<<8 | + sd->cmd[4] + ); + dprint(1,"SD:WRITE: 0x%04x RX_BUFFER\n", block); + + // TODO: wire up write command here + + sdcard_setstate(sd, TX_RX_BLOCK_STAT); + } + sd->resp_ptr++; + return 0xff; + + default: + dprint(1,"SD: unexpected state %i\n", sd->state); + return 0xff; } + // If we got here, we have an entire command packet + UINT8 cmd = sd->cmd[0]; - // we have a whole cmd // should start with 0b01xxxxxx (x = cmd) // should end with 0bccccccc1 (c = crc) @@ -118,60 +217,52 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { int rp = 0; switch (cmd) { - case 0x40: // CMD0 GO_IDLE_STATE - dprint(1,"SD: CMD0 GO_IDLE_STATE\n"); - case 0x77: // CMD55 APP_CMD - sd->resp[0] = 0xff; - sd->resp[1] = 0x01; - sdcard_setstate(sd, TX_RESP); - sdcard_reset_ptr(sd); + case 0x40: + dprint(1,"SD:CMD0 GO_IDLE_STATE\n"); + sdcard_resp_r1(sd, R1_OK); break; - case 0x48: // CMD8 SEND_IF_COND - dprint(1,"SD: CMD8 SEND_IF_COND\n"); - // TODO: check arg 00 00 01 aa - sd->resp[0] = 0xff; - sd->resp[1] = 0x01; - sd->resp[2] = 0x00; - sd->resp[3] = 0x00; - sd->resp[4] = 0x01; - sd->resp[5] = 0xaa; - sdcard_setstate(sd, TX_RESP); - sdcard_reset_ptr(sd); + + case 0x48: + dprint(1,"SD:CMD8 SEND_IF_COND\n"); + + // We accept any conditions (cmd[1],cmd[2],cmd[3]) + // And echo the check byte back (cmd[4]) + // Should check CRC (eg, 48000001aa87 is valid) + int reply; + reply = sd->cmd[1] << 24; + reply |= sd->cmd[2] << 16; + reply |= sd->cmd[3] << 8; + reply |= sd->cmd[4]; + + sdcard_resp_r7(sd, reply); break; - case 0x49: // CMD9 SEND_CSD - dprint(1,"SD: CMD9 SEND_CSD\n"); - sd->resp[rp++] = 0xff; - sd->resp[rp++] = 0x01; - sd->resp[rp++] = 0xfe; // data token - sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x00; // LBA + case 0x49: + dprint(1,"SD:CMD9 SEND_CSD\n"); + + sd->resp[rp++] = 0x40; // CSD_STRUCT and reserved bits + sd->resp[rp++] = 0x0e; // TAAC + sd->resp[rp++] = 0x00; // NSAC + sd->resp[rp++] = 0x32; // TRAN_SPEED 24MHz + sd->resp[rp++] = 0x5b; // CCC - guess + sd->resp[rp++] = 0x59; // CCC, READ_BL_LEN + sd->resp[rp++] = 0x00; // 4 bits flags, 4 bits reserved + sd->resp[rp++] = 0x00; // 2 bits reserved, 6 bits LBA sd->resp[rp++] = 0x08; // . - sd->resp[rp++] = 0x00; // . sd->resp[rp++] = 0x00; // Approx 1Gig + sd->resp[rp++] = 0x7f; + sd->resp[rp++] = 0x80; + sd->resp[rp++] = 0x0a; + sd->resp[rp++] = 0x40; sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x00; - // TODO: use real sizes + sd->resp[rp++] = 0x01; // last bit is stop bit + // TODO: use real backing store for size - sd->resp[rp++] = 0x05; // CRC1 - sd->resp[rp++] = 0x0a; // CRC2 - sdcard_setstate(sd, TX_RESP); - sdcard_reset_ptr(sd); + sdcard_resp_tx_block(sd, 16); break; - case 0x4a: // CMD10 SEND_CID - dprint(1,"SD: CMD10 SEND_CID\n"); - sd->resp[rp++] = 0xff; - sd->resp[rp++] = 0x01; - sd->resp[rp++] = 0xfe; // data token + + case 0x4a: + dprint(1,"SD:CMD10 SEND_CID\n"); sd->resp[rp++] = 0x01; // Manuf sd->resp[rp++] = 'A'; // App @@ -186,29 +277,26 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { sd->resp[rp++] = 0x34; sd->resp[rp++] = 0x56; sd->resp[rp++] = 0x78; - sd->resp[rp++] = 0x00; // 2YY - sd->resp[rp++] = 0x01; // YM - sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x01; // m=1 + sd->resp[rp++] = 0x01; // y=2001 + sd->resp[rp++] = 0x01; // last bit is stop bit - sd->resp[rp++] = 0x05; // CRC1 - sd->resp[rp++] = 0x0a; // CRC2 - sdcard_setstate(sd, TX_RESP); - sdcard_reset_ptr(sd); + sdcard_resp_tx_block(sd, 16); break; - case 0x50: // CMD16 SET_BLOCKLEN - dprint(1,"SD: CMD16 SET_BLOCKLEN\n"); + + case 0x50: + dprint(1,"SD:CMD16 SET_BLOCKLEN\n"); // TODO: do a real check of the value if (sd->cmd[3] != 2) { dprint(1,"SD: unexpected blocklen\n"); - goto error; + sdcard_resp_r1(sd, R1_ILL_CMD); + break; } - sd->resp[0] = 0xff; - sd->resp[1] = 0x01; - sdcard_setstate(sd, TX_RESP); - sdcard_reset_ptr(sd); + sdcard_resp_r1(sd, R1_OK); break; - case 0x51: { // CMD17 READ_SINGLE_BLOCK - dprint(1,"SD: CMD17 READ_SINGLE_BLOCK\n"); + + case 0x51: { + dprint(1,"SD:CMD17 READ_SINGLE_BLOCK\n"); int block = ( sd->cmd[1]<<24 | sd->cmd[2]<<16 | @@ -217,22 +305,16 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { ); dprint(1,"SD:READ: 0x%04x\n", block); - sd->resp[0] = 0xff; - sd->resp[1] = 0x01; - sd->resp[2] = 0xfe; // data token - if (lseek(sd->fd, block*0x200, SEEK_SET) != -1) { - read(sd->fd, &sd->resp[3], 0x200); + read(sd->fd, &sd->resp, 0x200); } - sd->resp[512+3+0] = 0x05; // CRC - sd->resp[512+3+1] = 0x0a; - sdcard_setstate(sd, TX_RESP); - sdcard_reset_ptr(sd); + sdcard_resp_tx_block(sd, 512); break; } - case 0x58: { // CMD24 WRITE_BLOCK - dprint(1,"SD: CMD24 WRITE_BLOCK\n"); + + case 0x58: { + dprint(1,"SD:CMD24 WRITE_BLOCK\n"); int block = ( sd->cmd[1]<<24 | sd->cmd[2]<<16 | @@ -241,68 +323,50 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { ); dprint(1,"SD:WRITE: 0x%04x\n", block); - sd->resp[rp++] = 0xff; - sd->resp[rp++] = 0x01; - - sdcard_setstate(sd, PRE_WRITE_STAT); - sdcard_reset_ptr(sd); + sdcard_resp_rx_block(sd); break; } - case 0x7a: // CMD58 READ_OCR - dprint(1,"SD: CMD58 READ_OCR\n"); - sd->resp[0] = 0xff; - sd->resp[1] = 0x01; - sd->resp[2] = 0x40; // bit30 == HCS - sd->resp[3] = 0x00; - sd->resp[4] = 0x00; - sd->resp[5] = 0x00; - sdcard_setstate(sd, TX_RESP); - sdcard_reset_ptr(sd); + case 0x77: + dprint(1,"SD:CMD55 APP_CMD\n"); + sdcard_resp_r1(sd, R1_OK); + break; + + case 0x7a: + dprint(1,"SD:CMD58 READ_OCR\n"); + sdcard_resp_r3(sd, 0x40000000); break; // TODO: gate ACMD values on a previous CMD55 APP_CMD - case 0x69: // ACMD41 SEND_OP_COND - dprint(1,"SD: ACMD41 SEND_OP_COND\n"); - sd->resp[0] = 0xff; - sd->resp[1] = 0x00; - sdcard_setstate(sd, TX_RESP); - sdcard_reset_ptr(sd); + case 0x69: + dprint(1,"SD:ACMD41 SEND_OP_COND\n"); + sdcard_resp_r1(sd, R1_0); break; - case 0x73: // ACMD51 SEND_SCR - dprint(1,"SD: ACMD51 SEND_SCR\n"); - sd->resp[rp++] = 0xff; - sd->resp[rp++] = 0x01; - sd->resp[rp++] = 0xfe; // data token - sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x30; // SD_SEC_2 == SDHC + + case 0x73: + dprint(1,"SD:ACMD51 SEND_SCR\n"); + sd->resp[rp++] = 0x01; // SD_SPEC v1.10 + sd->resp[rp++] = 0xB1; // SD_SEC == SDHC, 1bit width sd->resp[rp++] = 0x00; sd->resp[rp++] = 0x00; + sd->resp[rp++] = 0x0c; // CMD_SUPPORT 58,59 + 48/49 sd->resp[rp++] = 0x00; sd->resp[rp++] = 0x00; sd->resp[rp++] = 0x00; - sd->resp[rp++] = 0x05; // CRC1 - sd->resp[rp++] = 0x0a; // CRC2 - sdcard_setstate(sd, TX_RESP); - sdcard_reset_ptr(sd); + sdcard_resp_tx_block(sd, 8); break; -error: default: - sd->resp[0] = 0xff; - sd->resp[1] = 0x05; // illegal command - sdcard_setstate(sd, TX_RESP); - sdcard_reset_ptr(sd); + sdcard_resp_r1(sd, R1_ILL_CMD); dprint(1,"unknown\n"); dprint(1,"SD:CMD: cmd=0x%02x\n",cmd); - - return 0xff; // in write state, return is ignored + break; } if (sdcard_trace>1) { printf("\n"); } + return 0xff; } int sdcard_read(struct sdcard_device *sd, int cs, UINT8 data) { @@ -316,37 +380,109 @@ int sdcard_read(struct sdcard_device *sd, int cs, UINT8 data) { sdcard_dump(sd); } - if (sd->state == RX_CMD) { - // got a read when we expected more writes - sdcard_reset(sd); - dprint(1,"SD: read when RX_CMD\n"); - } - if (sd->state == WRITE_BLOCK) { - // got the read after the end of a write block - sdcard_setstate(sd, TX_RESP); + switch (sd->state) { + case IDLE: + // in idle mode, the card just outputs ones? + dprint(1,"SD: read while IDLE\n"); + result = 0xff; + break; - dprint(1,"SD: FIXME write data accepted\n"); - result = 0x05; // Data accepted - goto out; - } - if (sd->state == IDLE) { - // in idle mode, the card just outputs ones? - dprint(1,"SD: read while IDLE\n"); - result = 0xff; - goto out; - } + case RX_CMD: + // got a read when we expected more writes + sdcard_reset(sd); + dprint(1,"SD: read when RX_CMD\n"); + break; - result = sd->resp[sd->resp_ptr]; - sd->resp_ptr = sd->resp_ptr + 1; - if (sd->resp_ptr >= sizeof(sd->resp)) { - sd->resp_ptr = 0; - } + case TX_R1: + switch (sd->resp_ptr) { + case 0: + result = 0xff; // first resp, indicate busy + break; + case 1: + result = sd->r1; // second, return response code + sdcard_setstate(sd, IDLE); + break; + } + sd->resp_ptr++; + break; + + case TX_R3: + case TX_R7: + switch (sd->resp_ptr) { + case 0: + result = 0xff; // first resp, indicate busy + break; + case 1: + result = 0x01; // second, indicate idle mode + break; + case 2: + case 3: + case 4: + result = sd->resp[sd->resp_ptr-2]; + break; + case 5: + result = sd->resp[3]; + sdcard_setstate(sd, IDLE); + break; + } + sd->resp_ptr++; + break; + + case TX_R1_TX_BLOCK: + switch (sd->resp_ptr) { + case 0: + result = 0xff; // first resp, indicate busy + break; + case 1: + result = 0x01; // second, send R1 + break; + case 2: + result = 0xfe; // finally, data token + break; + + default: { + int index = sd->resp_ptr-3; + + if (index < sd->tx_len) { + // Send the actual data + result = sd->resp[index]; + } else if (index == sd->tx_len) { + result = 0; // CRC1; + } else if (index == sd->tx_len+1) { + result = 0; // CRC2; + sdcard_setstate(sd, IDLE); + } + break; + } + } + sd->resp_ptr++; + break; - if (sd->state == PRE_WRITE_STAT && sd->resp_ptr == 2) { - sdcard_setstate(sd, WRITE_BLOCK); + case TX_R1_RX_BLOCK: + switch (sd->resp_ptr) { + case 0: + result = 0xff; // first resp, indicate busy + sd->resp_ptr++; + break; + case 1: + result = 0x01; // second, return idle state + sdcard_reset_ptr(sd); + sdcard_setstate(sd, RX_BLOCK); + break; + } + break; + + case TX_RX_BLOCK_STAT: + result = 0x05; // Data accepted + sdcard_setstate(sd, IDLE); + break; + + default: + dprint(1,"SD: unexpected state %i\n", sd->state); + result = 0xff; + break; } -out: if (sdcard_trace>1) { printf("SD:RD: r=0x%02x\n", result); } diff --git a/sdcard/sdcard.h b/sdcard/sdcard.h index 5cfabdb..2d52be3 100644 --- a/sdcard/sdcard.h +++ b/sdcard/sdcard.h @@ -7,12 +7,17 @@ #ifndef SDCARD_H #define SDCARD_H +// Remember to update sdcard_state_names too enum sdcard_state { IDLE = 0, RX_CMD, - TX_RESP, - PRE_WRITE_STAT, - WRITE_BLOCK, + TX_R1, + TX_R3, + TX_R7, + TX_R1_TX_BLOCK, + TX_R1_RX_BLOCK, + RX_BLOCK, + TX_RX_BLOCK_STAT, }; struct sdcard_device { @@ -20,6 +25,8 @@ struct sdcard_device { enum sdcard_state state; int cmd_ptr; int resp_ptr; + int tx_len; // size of valid data in resp to TX + UINT8 r1; // result code to send with R1 UINT8 cmd[8]; UINT8 resp[512+6]; }; From fe74752104bcd61e378c2065239074d40d08f766 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Tue, 24 Jan 2023 00:15:36 +0000 Subject: [PATCH 14/18] Minor tweaks get fuzix closer to using our fake sdcard --- sdcard/sdcard.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 2fd8309..1fc5f74 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -102,17 +102,19 @@ void sdcard_resp_reply32(struct sdcard_device *sd, int reply) { sd->resp[3] = reply & 0xff; } -void sdcard_resp_r3(struct sdcard_device *sd, int reply) { +void sdcard_resp_r3(struct sdcard_device *sd, UINT8 r1, int value) { sd->resp_ptr = 0; + sd->r1 = r1; // TODO: sd->tx_len = 4; - sdcard_resp_reply32(sd, reply); + sdcard_resp_reply32(sd, value); sdcard_setstate(sd, TX_R3); } -void sdcard_resp_r7(struct sdcard_device *sd, int reply) { +void sdcard_resp_r7(struct sdcard_device *sd, int value) { sd->resp_ptr = 0; + sd->r1 = R1_OK; // TODO: sd->tx_len = 4; - sdcard_resp_reply32(sd, reply); + sdcard_resp_reply32(sd, value); sdcard_setstate(sd, TX_R7); } @@ -334,7 +336,7 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { case 0x7a: dprint(1,"SD:CMD58 READ_OCR\n"); - sdcard_resp_r3(sd, 0x40000000); + sdcard_resp_r3(sd, R1_0, 0x40000000); break; // TODO: gate ACMD values on a previous CMD55 APP_CMD @@ -413,7 +415,7 @@ int sdcard_read(struct sdcard_device *sd, int cs, UINT8 data) { result = 0xff; // first resp, indicate busy break; case 1: - result = 0x01; // second, indicate idle mode + result = sd->r1; // second, return response code break; case 2: case 3: @@ -434,7 +436,7 @@ int sdcard_read(struct sdcard_device *sd, int cs, UINT8 data) { result = 0xff; // first resp, indicate busy break; case 1: - result = 0x01; // second, send R1 + result = 0x00; // second, send R1 break; case 2: result = 0xfe; // finally, data token From 97cd5e8dae80daf306051b34ad93176d47bcfc19 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Tue, 24 Jan 2023 09:26:04 +0000 Subject: [PATCH 15/18] Flatten the internal state logic by providing a NEXT state to go to --- sdcard/sdcard.c | 70 +++++++++++++++++++++++-------------------------- sdcard/sdcard.h | 7 +++++ 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 1fc5f74..1ea1077 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -26,6 +26,7 @@ int sdcard_trace = 1; char *sdcard_state_names[] = { [IDLE] = "IDLE", [RX_CMD] = "RX_CMD", + [TX_BUSY] = "TX_BUSY", [TX_R1] = "TX_R1", [TX_R3] = "TX_R3", [TX_R7] = "TX_R7", @@ -33,9 +34,15 @@ char *sdcard_state_names[] = { [TX_R1_RX_BLOCK] = "TX_R1_RX_BLOCK", [RX_BLOCK] = "RX_BLOCK", [TX_RX_BLOCK_STAT] = "TX_RX_BLOCK_STAT", + + [NEXT] = "next", }; void sdcard_setstate(struct sdcard_device *sd, enum sdcard_state newstate) { + if (newstate == NEXT) { + newstate = sd->state_next; + sd->state_next = IDLE; + } if (sd->state != newstate) { dprint(1,"SD: %s -> %s\n", sdcard_state_names[sd->state], @@ -92,7 +99,8 @@ void sdcard_resp_r1(struct sdcard_device *sd, UINT8 r1) { sd->resp_ptr = 0; // TODO: sd->tx_len = 0; sd->r1 = r1; - sdcard_setstate(sd, TX_R1); + sd->state_next = TX_R1; + sdcard_setstate(sd, TX_BUSY); } void sdcard_resp_reply32(struct sdcard_device *sd, int reply) { @@ -107,27 +115,32 @@ void sdcard_resp_r3(struct sdcard_device *sd, UINT8 r1, int value) { sd->r1 = r1; // TODO: sd->tx_len = 4; sdcard_resp_reply32(sd, value); - sdcard_setstate(sd, TX_R3); + sd->state_next = TX_R3; + sdcard_setstate(sd, TX_BUSY); } +// TODO: r7 is almost identical to r3, coalesce them void sdcard_resp_r7(struct sdcard_device *sd, int value) { sd->resp_ptr = 0; sd->r1 = R1_OK; // TODO: sd->tx_len = 4; sdcard_resp_reply32(sd, value); - sdcard_setstate(sd, TX_R7); + sd->state_next = TX_R7; + sdcard_setstate(sd, TX_BUSY); } void sdcard_resp_tx_block(struct sdcard_device *sd, int tx_len) { sd->resp_ptr = 0; sd->tx_len = tx_len; - sdcard_setstate(sd, TX_R1_TX_BLOCK); + sd->state_next = TX_R1_TX_BLOCK; + sdcard_setstate(sd, TX_BUSY); } void sdcard_resp_rx_block(struct sdcard_device *sd) { sd->resp_ptr = 0; sd->tx_len = 0; // We are overwriting it, so it must be zero - sdcard_setstate(sd, TX_R1_RX_BLOCK); + sd->state_next = TX_R1_RX_BLOCK; + sdcard_setstate(sd, TX_BUSY); } int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { @@ -395,34 +408,28 @@ int sdcard_read(struct sdcard_device *sd, int cs, UINT8 data) { dprint(1,"SD: read when RX_CMD\n"); break; + case TX_BUSY: + result = 0xff; // first resp, indicate busy + sdcard_setstate(sd, NEXT); + break; + case TX_R1: - switch (sd->resp_ptr) { - case 0: - result = 0xff; // first resp, indicate busy - break; - case 1: - result = sd->r1; // second, return response code - sdcard_setstate(sd, IDLE); - break; - } - sd->resp_ptr++; + result = sd->r1; // second, return response code + sdcard_setstate(sd, IDLE); break; case TX_R3: case TX_R7: switch (sd->resp_ptr) { case 0: - result = 0xff; // first resp, indicate busy - break; - case 1: result = sd->r1; // second, return response code break; + case 1: case 2: case 3: - case 4: - result = sd->resp[sd->resp_ptr-2]; + result = sd->resp[sd->resp_ptr-1]; break; - case 5: + case 4: result = sd->resp[3]; sdcard_setstate(sd, IDLE); break; @@ -433,17 +440,14 @@ int sdcard_read(struct sdcard_device *sd, int cs, UINT8 data) { case TX_R1_TX_BLOCK: switch (sd->resp_ptr) { case 0: - result = 0xff; // first resp, indicate busy - break; - case 1: result = 0x00; // second, send R1 break; - case 2: + case 1: result = 0xfe; // finally, data token break; default: { - int index = sd->resp_ptr-3; + int index = sd->resp_ptr-2; if (index < sd->tx_len) { // Send the actual data @@ -461,17 +465,9 @@ int sdcard_read(struct sdcard_device *sd, int cs, UINT8 data) { break; case TX_R1_RX_BLOCK: - switch (sd->resp_ptr) { - case 0: - result = 0xff; // first resp, indicate busy - sd->resp_ptr++; - break; - case 1: - result = 0x01; // second, return idle state - sdcard_reset_ptr(sd); - sdcard_setstate(sd, RX_BLOCK); - break; - } + result = 0x01; // second, return idle state + sdcard_reset_ptr(sd); + sdcard_setstate(sd, RX_BLOCK); break; case TX_RX_BLOCK_STAT: diff --git a/sdcard/sdcard.h b/sdcard/sdcard.h index 2d52be3..7b2d672 100644 --- a/sdcard/sdcard.h +++ b/sdcard/sdcard.h @@ -7,10 +7,14 @@ #ifndef SDCARD_H #define SDCARD_H +// States are named from the SDcard's point of view (thus "TX" is the card +// intends to transmit) +// // Remember to update sdcard_state_names too enum sdcard_state { IDLE = 0, RX_CMD, + TX_BUSY, TX_R1, TX_R3, TX_R7, @@ -18,11 +22,14 @@ enum sdcard_state { TX_R1_RX_BLOCK, RX_BLOCK, TX_RX_BLOCK_STAT, + + NEXT, // Pseudo state, requesting to shift to the "next" state }; struct sdcard_device { int fd; enum sdcard_state state; + enum sdcard_state state_next; int cmd_ptr; int resp_ptr; int tx_len; // size of valid data in resp to TX From f5e76b32a56048cda391ca2d1560b1d7a4b6d3a5 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Tue, 24 Jan 2023 09:51:38 +0000 Subject: [PATCH 16/18] Add a state for transmitting the R3/R7 trailing data and standarise on always using the r1 status --- sdcard/sdcard.c | 48 ++++++++++++++++++++++++------------------------ sdcard/sdcard.h | 1 + 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 1ea1077..63b49ed 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -30,6 +30,7 @@ char *sdcard_state_names[] = { [TX_R1] = "TX_R1", [TX_R3] = "TX_R3", [TX_R7] = "TX_R7", + [TX_IMM32] = "TX_IMM32", [TX_R1_TX_BLOCK] = "TX_R1_TX_BLOCK", [TX_R1_RX_BLOCK] = "TX_R1_RX_BLOCK", [RX_BLOCK] = "RX_BLOCK", @@ -120,9 +121,9 @@ void sdcard_resp_r3(struct sdcard_device *sd, UINT8 r1, int value) { } // TODO: r7 is almost identical to r3, coalesce them -void sdcard_resp_r7(struct sdcard_device *sd, int value) { +void sdcard_resp_r7(struct sdcard_device *sd, UINT8 r1, int value) { sd->resp_ptr = 0; - sd->r1 = R1_OK; + sd->r1 = r1; // TODO: sd->tx_len = 4; sdcard_resp_reply32(sd, value); sd->state_next = TX_R7; @@ -139,6 +140,7 @@ void sdcard_resp_tx_block(struct sdcard_device *sd, int tx_len) { void sdcard_resp_rx_block(struct sdcard_device *sd) { sd->resp_ptr = 0; sd->tx_len = 0; // We are overwriting it, so it must be zero + sd->r1 = 0x01; // afterwards, return idle state sd->state_next = TX_R1_RX_BLOCK; sdcard_setstate(sd, TX_BUSY); } @@ -159,6 +161,7 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { case TX_R1: case TX_R3: case TX_R7: + case TX_IMM32: case TX_R1_TX_BLOCK: case TX_R1_RX_BLOCK: case TX_RX_BLOCK_STAT: @@ -211,13 +214,14 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { // TODO: wire up write command here + sd->r1 = 0x05; // Data accepted sdcard_setstate(sd, TX_RX_BLOCK_STAT); } sd->resp_ptr++; return 0xff; default: - dprint(1,"SD: unexpected state %i\n", sd->state); + dprint(1,"SD:WR: unexpected state %i\n", sd->state); return 0xff; } @@ -249,7 +253,7 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { reply |= sd->cmd[3] << 8; reply |= sd->cmd[4]; - sdcard_resp_r7(sd, reply); + sdcard_resp_r7(sd, R1_OK, reply); break; case 0x49: @@ -413,28 +417,24 @@ int sdcard_read(struct sdcard_device *sd, int cs, UINT8 data) { sdcard_setstate(sd, NEXT); break; + case TX_R3: + case TX_R7: + sd->state_next = TX_IMM32; + /* FALL THROUGH */ + case TX_R1: result = sd->r1; // second, return response code - sdcard_setstate(sd, IDLE); + sdcard_setstate(sd, NEXT); break; - case TX_R3: - case TX_R7: - switch (sd->resp_ptr) { - case 0: - result = sd->r1; // second, return response code - break; - case 1: - case 2: - case 3: - result = sd->resp[sd->resp_ptr-1]; - break; - case 4: - result = sd->resp[3]; - sdcard_setstate(sd, IDLE); - break; - } + case TX_IMM32: + result = sd->resp[sd->resp_ptr]; sd->resp_ptr++; + + if (sd->resp_ptr==4) { + sdcard_setstate(sd, IDLE); + } + break; case TX_R1_TX_BLOCK: @@ -465,18 +465,18 @@ int sdcard_read(struct sdcard_device *sd, int cs, UINT8 data) { break; case TX_R1_RX_BLOCK: - result = 0x01; // second, return idle state + result = sd->r1; sdcard_reset_ptr(sd); sdcard_setstate(sd, RX_BLOCK); break; case TX_RX_BLOCK_STAT: - result = 0x05; // Data accepted + result = sd->r1; sdcard_setstate(sd, IDLE); break; default: - dprint(1,"SD: unexpected state %i\n", sd->state); + dprint(1,"SD:RD: unexpected state %i\n", sd->state); result = 0xff; break; } diff --git a/sdcard/sdcard.h b/sdcard/sdcard.h index 7b2d672..f5cbe91 100644 --- a/sdcard/sdcard.h +++ b/sdcard/sdcard.h @@ -18,6 +18,7 @@ enum sdcard_state { TX_R1, TX_R3, TX_R7, + TX_IMM32, TX_R1_TX_BLOCK, TX_R1_RX_BLOCK, RX_BLOCK, From 243e1592cbe85aa7db3a8342753a1644bf0a3aff Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Tue, 24 Jan 2023 20:28:57 +0000 Subject: [PATCH 17/18] Add more states to cover the sending of a read block, use (hopefully) more rational state names --- sdcard/sdcard.c | 81 +++++++++++++++++++++++++++---------------------- sdcard/sdcard.h | 10 ++++-- 2 files changed, 52 insertions(+), 39 deletions(-) diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 63b49ed..65e4db1 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -25,15 +25,19 @@ int sdcard_trace = 1; char *sdcard_state_names[] = { [IDLE] = "IDLE", + [RX_CMD] = "RX_CMD", + [RX_BLOCK] = "RX_BLOCK", + [TX_BUSY] = "TX_BUSY", [TX_R1] = "TX_R1", [TX_R3] = "TX_R3", [TX_R7] = "TX_R7", [TX_IMM32] = "TX_IMM32", - [TX_R1_TX_BLOCK] = "TX_R1_TX_BLOCK", - [TX_R1_RX_BLOCK] = "TX_R1_RX_BLOCK", - [RX_BLOCK] = "RX_BLOCK", + [TX_BLOCK_R1] = "TX_BLOCK_R1", + [TX_BLOCK_TOKEN] = "TX_BLOCK_TOKEN", + [TX_BLOCK_BUF] = "TX_BLOCK_BUF", + [TX_RX_BLOCK_R1] = "TX_RX_BLOCK_R1", [TX_RX_BLOCK_STAT] = "TX_RX_BLOCK_STAT", [NEXT] = "next", @@ -130,10 +134,11 @@ void sdcard_resp_r7(struct sdcard_device *sd, UINT8 r1, int value) { sdcard_setstate(sd, TX_BUSY); } -void sdcard_resp_tx_block(struct sdcard_device *sd, int tx_len) { +void sdcard_resp_tx_block(struct sdcard_device *sd, UINT8 r1, int tx_len) { sd->resp_ptr = 0; sd->tx_len = tx_len; - sd->state_next = TX_R1_TX_BLOCK; + sd->r1 = r1; + sd->state_next = TX_BLOCK_R1; sdcard_setstate(sd, TX_BUSY); } @@ -141,7 +146,7 @@ void sdcard_resp_rx_block(struct sdcard_device *sd) { sd->resp_ptr = 0; sd->tx_len = 0; // We are overwriting it, so it must be zero sd->r1 = 0x01; // afterwards, return idle state - sd->state_next = TX_R1_RX_BLOCK; + sd->state_next = TX_RX_BLOCK_R1; sdcard_setstate(sd, TX_BUSY); } @@ -162,8 +167,10 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { case TX_R3: case TX_R7: case TX_IMM32: - case TX_R1_TX_BLOCK: - case TX_R1_RX_BLOCK: + case TX_BLOCK_R1: + case TX_BLOCK_TOKEN: + case TX_BLOCK_BUF: + case TX_RX_BLOCK_R1: case TX_RX_BLOCK_STAT: // got a write when we thought we needed a read dprint(2,"SD: got write, expected read (data=0x%02x)\n", data); @@ -277,7 +284,7 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { sd->resp[rp++] = 0x01; // last bit is stop bit // TODO: use real backing store for size - sdcard_resp_tx_block(sd, 16); + sdcard_resp_tx_block(sd, R1_0,16); break; case 0x4a: @@ -300,7 +307,7 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { sd->resp[rp++] = 0x01; // y=2001 sd->resp[rp++] = 0x01; // last bit is stop bit - sdcard_resp_tx_block(sd, 16); + sdcard_resp_tx_block(sd, R1_0, 16); break; case 0x50: @@ -328,7 +335,8 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { read(sd->fd, &sd->resp, 0x200); } - sdcard_resp_tx_block(sd, 512); + // TODO: could use result of read as source of r1 status + sdcard_resp_tx_block(sd, R1_0, 512); break; } @@ -372,7 +380,7 @@ int sdcard_write(struct sdcard_device *sd, int cs, UINT8 data) { sd->resp[rp++] = 0x00; sd->resp[rp++] = 0x00; sd->resp[rp++] = 0x00; - sdcard_resp_tx_block(sd, 8); + sdcard_resp_tx_block(sd, R1_0, 8); break; default: @@ -437,34 +445,35 @@ int sdcard_read(struct sdcard_device *sd, int cs, UINT8 data) { break; - case TX_R1_TX_BLOCK: - switch (sd->resp_ptr) { - case 0: - result = 0x00; // second, send R1 - break; - case 1: - result = 0xfe; // finally, data token - break; - - default: { - int index = sd->resp_ptr-2; - - if (index < sd->tx_len) { - // Send the actual data - result = sd->resp[index]; - } else if (index == sd->tx_len) { - result = 0; // CRC1; - } else if (index == sd->tx_len+1) { - result = 0; // CRC2; - sdcard_setstate(sd, IDLE); - } - break; - } + // TODO? with a deeper queue of state_next values, the TX_BLOCK + // could be simpler + case TX_BLOCK_R1: + result = sd->r1; + sdcard_setstate(sd, TX_BLOCK_TOKEN); + break; + + case TX_BLOCK_TOKEN: + result = 0xfe; // data token + sdcard_setstate(sd, TX_BLOCK_BUF); + break; + + case TX_BLOCK_BUF: { + int index = sd->resp_ptr; + + if (index < sd->tx_len) { + // Send the actual data + result = sd->resp[index]; + } else if (index == sd->tx_len) { + result = 0; // CRC1; + } else { + result = 0; // CRC2; + sdcard_setstate(sd, IDLE); } sd->resp_ptr++; break; + } - case TX_R1_RX_BLOCK: + case TX_RX_BLOCK_R1: result = sd->r1; sdcard_reset_ptr(sd); sdcard_setstate(sd, RX_BLOCK); diff --git a/sdcard/sdcard.h b/sdcard/sdcard.h index f5cbe91..12986f5 100644 --- a/sdcard/sdcard.h +++ b/sdcard/sdcard.h @@ -13,15 +13,19 @@ // Remember to update sdcard_state_names too enum sdcard_state { IDLE = 0, + RX_CMD, + RX_BLOCK, + TX_BUSY, TX_R1, TX_R3, TX_R7, TX_IMM32, - TX_R1_TX_BLOCK, - TX_R1_RX_BLOCK, - RX_BLOCK, + TX_BLOCK_R1, + TX_BLOCK_TOKEN, + TX_BLOCK_BUF, + TX_RX_BLOCK_R1, TX_RX_BLOCK_STAT, NEXT, // Pseudo state, requesting to shift to the "next" state From 75b67b9545cbe3e62b27ca0845f9459d4e2ea256 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Thu, 26 Jan 2023 08:33:51 +0000 Subject: [PATCH 18/18] Show correct R1 state on write --- sdcard/sdcard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 65e4db1..8e3f94b 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -144,8 +144,8 @@ void sdcard_resp_tx_block(struct sdcard_device *sd, UINT8 r1, int tx_len) { void sdcard_resp_rx_block(struct sdcard_device *sd) { sd->resp_ptr = 0; - sd->tx_len = 0; // We are overwriting it, so it must be zero - sd->r1 = 0x01; // afterwards, return idle state + sd->tx_len = 0; // This overwrites the buffer, so mark it as empty + sd->r1 = 0; // R1 should indicate not idle sd->state_next = TX_RX_BLOCK_R1; sdcard_setstate(sd, TX_BUSY); }