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.
This commit is contained in:
Virgil Dupras 2020-09-17 09:36:16 -04:00
parent 350b7c5939
commit 1a6a549857
13 changed files with 63 additions and 48 deletions

View File

@ -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!.

View File

@ -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)
;

View File

@ -1,4 +1,4 @@
: _err (spid) ABORT" SDerr" ;
: _err 0 (spie) ABORT" SDerr" ;
( Tight definition ahead, pre-comment.

View File

@ -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 ;

View File

@ -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) ;

15
blk/595
View File

@ -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".

13
blk/596
View File

@ -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

View File

@ -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 ;

View File

@ -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)

View File

@ -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()) {

View File

@ -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)

View File

@ -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);

View File

@ -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.