z80softspi: Software SPI for the Z80
authorAlan Cox <alan@linux.intel.com>
Tue, 8 Jan 2019 00:59:51 +0000 (00:59 +0000)
committerAlan Cox <alan@linux.intel.com>
Tue, 8 Jan 2019 00:59:51 +0000 (00:59 +0000)
Mainly intended for use with the Z80PIO but ought to work with other hardware
too providing it's got a single register with input and output bits present.

Kernel/dev/z80softspi.h [new file with mode: 0644]
Kernel/dev/z80softspi.s [new file with mode: 0644]

diff --git a/Kernel/dev/z80softspi.h b/Kernel/dev/z80softspi.h
new file mode 100644 (file)
index 0000000..5e891e8
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ *     Interfaces provided by the Z80 SoftSPI that are not present
+ *     in the core devsd code
+ */
+
+extern uint8_t spi_piostate;
+extern uint16_t spi_port;
+
+extern void sd_spi_rx_sector(uint16_t addr) __z88dk_fastcall;
+extern void sd_spi_tx_sector(uint16_t addr) __z88dk_fastcall;
+
diff --git a/Kernel/dev/z80softspi.s b/Kernel/dev/z80softspi.s
new file mode 100644 (file)
index 0000000..7d9b204
--- /dev/null
@@ -0,0 +1,142 @@
+;
+;      Software SPI. Implements the minimal bits needed to support the
+;      SD card interface
+;
+
+       .module softspi
+
+       .globl _sd_spi_transmit_byte
+       .globl _sd_spi_receive_byte
+       .globl _sd_spi_tx_sector
+       .globl _sd_spi_rx_sector
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+
+       .globl _spi_port                ; Port to use
+       .globl _spi_piostate            ; PIO bits to preserve
+
+       .area _COMMONMEM
+
+       ; Must be in common space
+
+_spi_port:
+       .dw     0
+_spi_piostate:
+       .db     0
+
+sd_spi_set_regs:
+       ld a,(_spi_piostate)
+       ld e,a
+       ld a,#SPI_DATA
+       or e
+       ld l,a
+       or #SPI_CLOCK
+       ld h,a
+       ld a,e
+       or #SPI_CLOCK
+       ld d,a
+       ld bc, (_spi_port)
+       ret     
+
+_sd_spi_transmit_byte:
+       ld a,l                          ; C argument
+       push af
+       call sd_spi_set_regs
+       pop af
+       call spi0_bitbang_tx
+       out (c),e                       ; drop final clock
+       ret
+
+_sd_spi_receive_byte:
+       call sd_spi_set_regs
+       call spi0_bitbang_rx
+       out (c),e
+       ld l,d
+       ret
+
+_sd_spi_rx_sector:
+       exx
+       call sd_spi_set_regs
+       exx
+       ld b,#0
+spi_rx_loop:
+       exx
+       call spi0_bitbang_rx
+       ld a,d
+       exx
+       ld (hl),a
+       inc hl
+       exx
+       call spi0_bitbang_rx
+       ld a,d
+       exx
+       ld (hl),a
+       inc hl
+       djnz spi_rx_loop
+       exx
+       out (c),e
+       exx
+       ret
+
+_sd_spi_tx_sector:
+       exx
+       call sd_spi_set_regs
+       exx
+       ld b,#0
+spi_tx_loop:
+       ld a,(hl)
+       inc hl
+       exx
+       call spi0_bitbang_tx
+       exx
+       ld a,(hl)
+       inc hl
+       exx
+       call spi0_bitbang_tx
+       exx
+       djnz spi_tx_loop
+       exx
+       out (c),e
+       exx
+       ret
+
+;
+;      The low level bits for the Z80 PIO
+;
+;      The basic idea is that we keep the port in C and each needed byte
+;      value in a register. The values are all precomputed so we don't
+;      touch other bits and so we can different modes
+;      
+spi0_bitbang_tx:
+       ld b,#8                 ; 7
+spi0_bit_tx:
+       rla                     ; 4
+       jp nc, spi0_tx0         ; 10            For SPI 0
+       out (c),l               ; 11            low | 1
+       out (c),h               ; 11            high | 1        (sample)
+       djnz spi0_bit_tx        ; 13/8
+       ret                     ; 10
+spi0_tx0:
+       out (c),e               ; 11            low | 0
+       out (c),d               ; 11            low | 1         (sample)
+       djnz spi0_bit_tx        ; 13/8
+       ret
+;
+;      Send 0xFF and receive a byte.
+;
+;      With call overhead about 500 clocks a byte or about 14Kbytes/second
+;      at 7.3MHz
+;
+spi0_bitbang_rx:
+       ld b,#8
+       ld d,#0
+spi0_bit_rx:
+       out (c),l               ; 11            low | 1
+       out (c),h               ; 11            high | 1
+       in a,(c)                ; 11
+       rra                     ; 4
+       rl d                    ; 8
+       djnz spi0_bit_rx        ; 13/8
+       ret