From 1fe367f21f239bc5585873ec9083b5cf65192d55 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 8 Jan 2019 00:59:51 +0000 Subject: [PATCH] z80softspi: Software SPI for the Z80 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 | 11 ++++ Kernel/dev/z80softspi.s | 142 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 Kernel/dev/z80softspi.h create mode 100644 Kernel/dev/z80softspi.s diff --git a/Kernel/dev/z80softspi.h b/Kernel/dev/z80softspi.h new file mode 100644 index 00000000..5e891e81 --- /dev/null +++ b/Kernel/dev/z80softspi.h @@ -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 index 00000000..7d9b2040 --- /dev/null +++ b/Kernel/dev/z80softspi.s @@ -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 -- 2.34.1