From 1a6a5498570641381ee835d93eb9ad552a3daf61 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Thu, 17 Sep 2020 09:36:16 -0400 Subject: [PATCH] Make the SPI Relay protocol support multiple devices Working on programming AVR chips exposes a glaring omission in my first design of the SPI Relay: not allowing multiple devices make this task hard. I constantly have to unplug my SD card before, plug the AVR chip holder, then play a bit, then unplug the AVR holder, then replug the SD card... My prototype for a SPI relay design is built, but I haven't tested it yet. I need to adapt the code first, which is what I do here. When the prototype is tested, I'll update the SDC recipe with a new schema. --- blk/420 | 3 ++- blk/429 | 6 +++--- blk/430 | 2 +- blk/432 | 5 +++-- blk/434 | 8 ++++---- blk/595 | 15 +++++---------- blk/596 | 13 +++++++------ blk/691 | 4 ++-- doc/protocol.txt | 16 ++++++++++++++-- emul/hw/rc2014/classic.c | 17 +++++++++-------- emul/hw/rc2014/sdc.c | 12 +++++------- emul/hw/rc2014/sdc.h | 3 +-- recipes/rc2014/sdcard.md | 7 +++++++ 13 files changed, 63 insertions(+), 48 deletions(-) diff --git a/blk/420 b/blk/420 index 57434be..1aad5e6 100644 --- a/blk/420 +++ b/blk/420 @@ -4,7 +4,8 @@ Load range: B423-B436 This subsystem is designed for a ad-hoc adapter card that acts as a SPI relay between the z80 bus and the SD card. It requires -a driver providing the SPI Relay protocol. +a driver providing the SPI Relay protocol. You need to define +SDC_DEVID to specify which ID will be supplied to (spie). Through that layer, this driver implements the SDC protocol allowing it to provide BLK@ and BLK!. diff --git a/blk/429 b/blk/429 index 1b89810..f826569 100644 --- a/blk/429 +++ b/blk/429 @@ -1,15 +1,15 @@ ( cmd arg1 arg2 -- r ) ( Send a command that expects a R1 response, handling CS. ) -: SDCMDR1 (spie) _cmd (spid) ; +: SDCMDR1 [ SDC_DEVID LITN ] (spie) _cmd 0 (spie) ; ( cmd arg1 arg2 -- r arg1 arg2 ) ( Send a command that expects a R7 response, handling CS. A R7 is a R1 followed by 4 bytes. arg1 contains bytes 0:1, arg2 has 2:3 ) : SDCMDR7 - (spie) + [ SDC_DEVID LITN ] (spie) _cmd ( r ) _idle 8 LSHIFT _idle + ( r arg1 ) _idle 8 LSHIFT _idle + ( r arg1 arg2 ) - (spid) + 0 (spie) ; diff --git a/blk/430 b/blk/430 index 8066197..912dc82 100644 --- a/blk/430 +++ b/blk/430 @@ -1,4 +1,4 @@ -: _err (spid) ABORT" SDerr" ; +: _err 0 (spie) ABORT" SDerr" ; ( Tight definition ahead, pre-comment. diff --git a/blk/432 b/blk/432 index b5799bf..fb7b9f0 100644 --- a/blk/432 +++ b/blk/432 @@ -1,5 +1,6 @@ : _sdc@ ( dstaddr blkno -- ) - (spie) 0x51 ( CMD17 ) 0 ROT ( a cmd 0 blkno ) _cmd + [ SDC_DEVID LITN ] (spie) + 0x51 ( CMD17 ) 0 ROT ( a cmd 0 blkno ) _cmd IF _err THEN _wait 0xfe = NOT IF _err THEN 0 SWAP ( crc a ) @@ -11,5 +12,5 @@ LOOP DROP ( crc1 ) _idle 8 LSHIFT _idle + ( crc2 ) - _wait DROP (spid) + _wait DROP 0 (spie) = NOT IF _err THEN ; diff --git a/blk/434 b/blk/434 index 6d8aebf..6f74196 100644 --- a/blk/434 +++ b/blk/434 @@ -1,8 +1,8 @@ : _sdc! ( srcaddr blkno -- ) - (spie) 0x58 ( CMD24 ) 0 ROT ( a cmd 0 blkno ) _cmd + [ SDC_DEVID LITN ] (spie) + 0x58 ( CMD24 ) 0 ROT ( a cmd 0 blkno ) _cmd IF _err THEN - _idle DROP 0xfe (spix) DROP - 0 SWAP ( crc a ) + _idle DROP 0xfe (spix) DROP 0 SWAP ( crc a ) 512 0 DO ( crc a ) C@+ ( crc a+1 n ) ROT OVER ( a n crc n ) @@ -13,4 +13,4 @@ LOOP DROP ( crc ) 256 /MOD ( lsb msb ) (spix) DROP (spix) DROP - _wait DROP (spid) ; + _wait DROP 0 (spie) ; diff --git a/blk/595 b/blk/595 index 42fcecc..69080af 100644 --- a/blk/595 +++ b/blk/595 @@ -1,15 +1,10 @@ SPI relay driver This driver is designed for a ad-hoc adapter card that acts as a -SPI relay between the z80 bus and the SPI device. Sending any- -thing on SPI_CSLOW and SPI_CSHIGH is expected to select/deselect -the device, and writing to SPI_DATA is expected to initiate a -byte exchange. The result of the exchange is excpected to be re- -trieved by reading SPI_DATA. - -You also need to define the exchange delay with SPI_DELAY. If -SPI clock is the same as system clock, 2 NOPs are enough: - -: SPI_DELAY NOP, NOP, ; +SPI relay between the z80 bus and the SPI device. When writing +to SPI_CTL, we expect a bitmask of the device to select, with +0 meaning that everything is de-selected. Reading SPI_CTL +returns 0 if the device is ready or 1 if it's still running an +exchange. Writing to SPI_DATA initiates an exchange. Provides the SPI relay protocol. Load driver with "596 LOAD". diff --git a/blk/596 b/blk/596 index e38ff34..e4e2e29 100644 --- a/blk/596 +++ b/blk/596 @@ -1,12 +1,13 @@ CODE (spix) ( n -- n ) - HL POP, - chkPS, - A L LDrr, + HL POP, chkPS, A L LDrr, SPI_DATA OUTiA, - SPI_DELAY + ( wait until xchg is done ) + BEGIN, SPI_CTL INAi, A ORr, JRNZ, AGAIN, SPI_DATA INAi, L A LDrr, HL PUSH, ;CODE -CODE (spie) SPI_CSLOW OUTiA, ;CODE -CODE (spid) SPI_CSHIGH OUTiA, ;CODE +CODE (spie) ( n -- ) + HL POP, chkPS, A L LDrr, + SPI_CTL OUTiA, +;CODE diff --git a/blk/691 b/blk/691 index 2b618ba..851d921 100644 --- a/blk/691 +++ b/blk/691 @@ -7,8 +7,8 @@ VARIABLE aspprevx SWAP aspprevx ! ( b ) ; : _cmd ( b4 b3 b2 b1 -- r4 ) _xc DROP _x DROP _xc DROP _x ; : asprdy ( -- ) BEGIN 0 0 0 0xf0 _cmd 1 AND NOT UNTIL ; -: asp$ ( -- ) - ( RESET pulse ) (spie) (spid) (spie) +: asp$ ( spidevid -- ) + ( RESET pulse ) DUP (spie) 0 (spie) (spie) ( wait >20ms ) 5000 0 DO LOOP ( enable prog ) 0xac (spix) DROP 0x53 _x DROP 0 _xc DROP 0 _x DROP ; diff --git a/doc/protocol.txt b/doc/protocol.txt index c8d2d90..85b06bf 100644 --- a/doc/protocol.txt +++ b/doc/protocol.txt @@ -15,13 +15,25 @@ These protocols are described here. # PS/2 protocol +This protocol enables communication with a device that spits +PS/2 keycodes. + (ps2kc) -- kc Returns the next typed PS/2 keycode from the console. Blocking. # SPI Relay protocol -(spie) -- Enable SPI device -(spid) -- Disable SPI device +This protocol enables communication with a SPI relay. This +protocol is designed to support devices with multiple endpoints. +To that end, (spie) takes a device ID argument, with a meaning +that is up to the device itself. To disable all devices, supply +0 to (spie). + +We expect relay devices to support only one enabled device at +once. Enabling a specific device is expected to disable the +previously enabled one. + +(spie) n -- Enable SPI device (spix) n -- n Perform SPI exchange (push a number, get a number back) diff --git a/emul/hw/rc2014/classic.c b/emul/hw/rc2014/classic.c index 9d7ba16..c363d60 100644 --- a/emul/hw/rc2014/classic.c +++ b/emul/hw/rc2014/classic.c @@ -18,8 +18,7 @@ #define RAMSTART 0x8000 #define ACIA_CTL_PORT 0x80 #define ACIA_DATA_PORT 0x81 -#define SDC_CSHIGH 0x06 -#define SDC_CSLOW 0x05 +#define SDC_CTL 0x05 #define SDC_SPI 0x04 #define MAX_ROMSIZE 0x2000 @@ -56,14 +55,16 @@ static void iowr_sdc_spi(uint8_t val) sdc_spi_wr(&sdc, val); } -static void iowr_sdc_cshigh(uint8_t val) +// in emulation, exchanges are always instantaneous, so we +// always report as ready. +static uint8_t iord_sdc_ctl() { - sdc_cshigh(&sdc); + return 0; } -static void iowr_sdc_cslow(uint8_t val) +static void iowr_sdc_ctl(uint8_t val) { - sdc_cslow(&sdc); + sdc_ctl_wr(&sdc, val); } int main(int argc, char *argv[]) @@ -117,8 +118,8 @@ int main(int argc, char *argv[]) m->iowr[ACIA_DATA_PORT] = iowr_acia_data; m->iord[SDC_SPI] = iord_sdc_spi; m->iowr[SDC_SPI] = iowr_sdc_spi; - m->iowr[SDC_CSHIGH] = iowr_sdc_cshigh; - m->iowr[SDC_CSLOW] = iowr_sdc_cslow; + m->iord[SDC_CTL] = iord_sdc_ctl; + m->iowr[SDC_CTL] = iowr_sdc_ctl; char tosend = 0; while (emul_step()) { diff --git a/emul/hw/rc2014/sdc.c b/emul/hw/rc2014/sdc.c index ed39939..6339e0b 100644 --- a/emul/hw/rc2014/sdc.c +++ b/emul/hw/rc2014/sdc.c @@ -23,14 +23,12 @@ void sdc_init(SDC *sdc) sdc->cmd24bytes = -2; } -void sdc_cslow(SDC *sdc) +// TODO: for now, any nonzero value enables the SDC. To allow +// emulation of systems with multi-devices SPI relay, change +// this. +void sdc_ctl_wr(SDC *sdc, uint8_t val) { - sdc->selected = true; -} - -void sdc_cshigh(SDC *sdc) -{ - sdc->selected = false; + sdc->selected = val; } void sdc_spi_wr(SDC *sdc, uint8_t val) diff --git a/emul/hw/rc2014/sdc.h b/emul/hw/rc2014/sdc.h index 6a84ecb..7298ad2 100644 --- a/emul/hw/rc2014/sdc.h +++ b/emul/hw/rc2014/sdc.h @@ -31,7 +31,6 @@ typedef struct { } SDC; void sdc_init(SDC *sdc); -void sdc_cslow(SDC *sdc); -void sdc_cshigh(SDC *sdc); +void sdc_ctl_wr(SDC *sdc, uint8_t val); void sdc_spi_wr(SDC *sdc, uint8_t val); uint8_t sdc_spi_rd(SDC *sdc); diff --git a/recipes/rc2014/sdcard.md b/recipes/rc2014/sdcard.md index c3332f1..975dbd8 100644 --- a/recipes/rc2014/sdcard.md +++ b/recipes/rc2014/sdcard.md @@ -1,5 +1,12 @@ # Accessing a MicroSD card +Warning: this recipe is temporarily broken. The schema below hasn't yet been +updated to work with the new SPI relay protocol. If you've already built an +old design, use an earlier commit or work around it in the SPI driver it should +only be a matter of testing the input value for zero-ness to decide whether we +ping the CSLOW or CSHIGH port. If you haven't, wait a little bit before building +one: the upcoming design is better. + SD cards are great because they are accessible directly. No supporting IC is necessary. The easiest way to access them is through the SPI protocol.