石原 博の覚書

電子工作に関する日々の覚書を記載します

SDカードをDISK代わりにしたForth

2023-07-18 21:38:10 | 日記
前回forthでSDカードをアクセスし、基本的な動作を確認したので、forth自身に8080機械語でSDカードアクセスを組み込んでみた。

Forthは出来るだけ変更を少なくするため、ワードR/Wを変更。
R/W ( ADDR BLK FLAG -- ERRFLAG )

RSLW DW $+2
LXI D,0FH ;SD CARD R/W
CALL IOS
STA DSKERR+2
JMP NEXT

呼び出し先は

ORG 100H
BIOS: JMP SINIT ;FUNCTION1 0
JMP CONST ;FUNCTION2 3 CONSOLE STATUS
JMP CONIN ;FUNCTION3 6 CONSOLE INPUT
JMP CONOUT ;FUNCTION4 9 CONSOLE OUTPUT
RET ;FUNCTION5 C PRINTER OUTPUT
NOP
NOP
JMP RSLW0 ;FUNCTION6 F SD CARD R/W LINK


; FORTH ROUTINE ADDR, BLK, FLAG
RSLW0: POP D ;RETURN AD
POP H ;FLAG
MOV A,L
POP H ;BLK
PUSH PSW
DAD H ;BLK * 2
MOV A,H
STA SDPARAM+2
MOV A,L
STA SDPARAM+3
POP PSW
POP H ;ADDR
SHLD DMA
PUSH D ;RETURN AD
.........................


注意点
・SDカードはSDHCしか考慮していない。
・KBBUF=スクリーン=1024としている。
・与えられたブロックを2倍してSDカードのセクタを指定(SDPARAM+2, SDPARAM+3)。
 RSLWでは1024バイトを読み取る。
 このため、ブロック(スクリーン)は1〜32767が有効。(使い切れる量じゃない。たとえ全部使ったとしても高々33MB)
 →「1 LIST」と「32769 LIST」は同じ

DENSITY, SEC/BLK 等のワードは残っているが意味はない。DR1でオフセットを設定出来るが意味ある動作にはならない。

・M80アセンブラのように .PHASEが使えれば、1本のソースと出来るが、ASMを使うので以下のようにROM書き込み段階で分けている。

KBCZ11SD.HEX 0 --> 0
FORTH130.HEX 8100 --> 800
として、起動時に 800H から 8100Hにコピーしている。



;KBCZ11SD.ASM
;
;KBC-Z11 Board 8080 SD(SPI access)routine
;
;Copyright 2023/5, Hiroshi Ishihara
;
;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 3 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, see <http://www.gnu.org/licenses/>
;
;
DEBUG EQU 0
;
; TMPZ84C011
STACK EQU 0H
PPAC EQU 54H
;PPBC EQU 55H
;PPCC EQU 56H
;PPDC EQU 34H
;PPEC EQU 44H
PPAD EQU 50H
;PPBD EQU 51H
;PPCD EQU 52H
;PPDD EQU 30H
;PPED EQU 40H
;
; SD CARD
CS EQU 80H
SCK EQU 40H
MOSI EQU 20H
MISO EQU 10H
;
RAMST EQU 8000H ; RAM START
ROMST EQU 800H ; ROM CONTENTS START
ROMSIZE EQU 2000H ; ROM SIZE
RAMST EQU 8000H ; RAM START
FORTHST EQU 8100H
;
CR EQU 0DH
LF EQU 0AH
;
; WORK AREA
ORG RAMST
CHARBUF:DS 1 ;KB INPUT
OCR: DS 4 ;OCR SAVE AREA
DMA: DS 2 ;SD CARD R/W
SDPARAM:DS 5 ;SD CARD SECTOR(4BYTE),CRC(FF)
;
ORG 0H
JMP 100H
;
ORG 100H
BIOS: JMP SINIT ;FUNCTION1 0
JMP CONST ;FUNCTION2 3 CONSOLE STATUS
JMP CONIN ;FUNCTION3 6 CONSOLE INPUT
JMP CONOUT ;FUNCTION4 9 CONSOLE OUTPUT
RET ;FUNCTION5 C PRINTER OUTPUT
NOP
NOP
JMP RSLW0 ;FUNCTION6 F SD CARD R/W LINK
;
; SYSTEM INITIALIZE
SINIT: LXI SP,STACK
CALL IOINIT
CALL SDINIT
JC SYSERR
CALL COPY
JMP FORTHST
;
SYSERR: CALL MSG
DB 'SDERR HALT',CR,LF,0
HALT
;
; Z84C011 PORT I/O INITIALIZE
IOINIT: MVI A,11100001B ;OUT=1, IN=0
OUT PPAC ;CS,SCK,MOSI,MISO,_,_,RXD,TXD
MVI A,0E1H ;INITIAL CS=1,SCK=1,MOSI=1,TXD=1
OUT PPAD
XRA A
STA CHARBUF
RET
;
; SD INIT
SDINIT: LXI H,0
SHLD SDPARAM ;SD SECTOR 4BYTE
SHLD SDPARAM+2
MVI A,0FFH
STA SDPARAM+4 ;FF(CRC)
CALL SDWAIT ;1mSEC
CALL SD80 ;SCLK >74CLOCK
;
CALL CMD0
JC CMD0$TIMEOUT
CPI 1
JNZ CMD0$RESPONSE
;
CALL CMD8
JC CMD8$TIMEOUT
CPI 1
JNZ CMD8$RESPONSE
LDA OCR+2 ;00H,00H,01H,0AAH 2.7V-3.6V
CPI 01H
JNZ CMD8$OCRERR
LDA OCR+3
CPI 0AAH
JNZ CMD8$OCRERR
;
CALL CMD58
JC CMD58$TIMEOUT
CPI 1
JNZ CMD58$RESPONSE ;NO SD OR VER1.X
LDA OCR ;OCR 00H,0FFH,80H,00H
ANA A
JNZ CMD58$OCRERR
LDA OCR+1
CPI 0FFH
JNZ CMD58$OCRERR
LDA OCR+2
CPI 80H
JNZ CMD58$OCRERR
LDA OCR+3
ANA A
JNZ CMD58$OCRERR
;
PUSH B
MVI B,0
CMD55L: DCR B
JZ CMD55$A$TIMEOUT
CALL CMD55
JC CMD55$TIMEOUT
CPI 1
JNZ CMD55$RESPONSE
;
CALL ACMD41
JC ACMD41$TIMEOUT
ANA A
JNZ CMD55L
POP B
;
CALL CMD58
JC CMD58$2$TIMEOUT
ANA A
JNZ CMD58$2$RESPONSE
LDA OCR ;OCR 0C0H,0FFH,80H,00H
CPI 0C0H
JNZ CMD58$2$OCRERR ;BIT31=1:SDHC,SDXC
LDA OCR+1
CPI 0FFH
JNZ CMD58$2$OCRERR
LDA OCR+2
CPI 80H
JNZ CMD58$2$OCRERR
LDA OCR+3
ANA A
JNZ CMD58$2$OCRERR
RET ;CY=0
;
; COPY ROMPG(FORTH) TO RAM
COPY: LXI H,ROMST
LXI D,FORTHST
LXI B,ROMSIZE
COPY1: MOV A,M
INX H
STAX D
INX D
DCX B
MOV A,B
ORA C
JNZ COPY1
JMP FORTHST
;
OUTCH: PUSH PSW
IN PPAD
ANI 0FEH ;START BIT
OUT PPAD
CALL WAIT
POP PSW
PUSH D
PUSH B
MVI B,8
OUTCH1: MOV C,A
ANI 1 ;BIT0
MOV D,A
IN PPAD
ANI 0FEH
ORA D
OUT PPAD
CALL WAIT
MOV A,C
RRC
DCR B
JNZ OUTCH1
IN PPAD
ORI 1 ;STOP BIT
OUT PPAD
CALL WAIT
POP B
POP D
RET
;
KBHIT: PUSH B
MVI B,100
KBHIT1: IN PPAD ;START BIT CHECK
ANI 2
JZ KBHIT2
DCR B
JNZ KBHIT1
POP B
XRA A
RET
KBHIT2: CALL WAITS ;SKIP START BIT(HALF)
LXI B,0800H ;B=8,C=0
KBHIT3: CALL WAIT
IN PPAD
ANI 2
RRC
ORA C
DCR B
JZ KBHIT4
RRC
MOV C,A
JMP KBHIT3
KBHIT4: RRC ;B6..B0,B7->B7..B0
ANA A
STA CHARBUF
POP B
RET
;
WAIT: PUSH B ;11+7+(4+10)*N+10+10=38+14*N
MVI B,37 ;N=37 -> 93uSEC (6MHz)
WAIT1: DCR B
JNZ WAIT1
POP B
RET
;
WAITS: PUSH B ;11+7+(4+10)*N+10+10
MVI B,13 ;N=13 -> 37uSEC (6MHz)
WAITS1: DCR B
JNZ WAITS1
POP B
RET

SDWAIT: PUSH B ;11+7+(17+93+4+10)*N+10+10=38+124*N
MVI B,50 ;N=50 -> 1039uSEC = 1mSec (6MHz)
SDWAIT1:CALL WAIT
DCR B
JNZ SDWAIT1
POP B
RET
;
CONST: CALL KBHIT
RZ
MVI A,0FFH
RET
;
CONIN: LDA CHARBUF ;RETURN CHARACTER IN A
ANI 07FH
JZ CONIN1
PUSH PSW
XRA A
STA CHARBUF
POP PSW
RET
CONIN1: CALL CONST
JZ CONIN1
JMP CONIN
;
CONOUT: MOV A,C ;WRITE CHARACTER IN C
ANI 07FH
JMP OUTCH
;
MSG: XTHL
PUSH PSW
MSG1: MOV A,M
INX H
ANA A
JZ MSG2
CALL OUTCH
JMP MSG1
MSG2: POP PSW
XTHL
RET
;
OUT2HEX:PUSH PSW
RRC
RRC
RRC
RRC
CALL OUTHEX
POP PSW
OUTHEX: ANI 0FH
CPI 10
JC OUTHEX2
ADI 'A'-'0'-10
OUTHEX2:ADI '0'
JMP OUTCH
;
OUT2HEX$SP:
CALL OUT2HEX
MVI A,' '
JMP OUTCH
;
CRLF: CALL MSG
DB CR,LF,0
RET
;
OUT2HEX$CR:
CALL OUT2HEX
CALL CRLF
CALL CSH
STC
RET
;
OUT2HEX$CR$POPH
CALL OUT2HEX$CR
POP H
POP B
RET
;
CSH: PUSH PSW
IN PPAD
ORI CS
OUT PPAD
CALL SPI8R ;DUMMY READ
POP PSW
ANA A ;CY=0
RET
;
CSL: IN PPAD
ANI (CS XOR 0FFH)
OUT PPAD
PUSH B
MVI B,0
BUSYW: DCR B ;B=0
JZ CSL$TIMEOUT
CALL SPI8R ;BUSY CHECK
ANA A
JZ BUSYW
POP B
RET ;CY=0
;
SD80: PUSH B
MVI B,10 ;SCLK 80 (>74)
SD801: MVI A,0FFH
CALL SPI8W
DCR B
JNZ SD801
POP B
RET
;
SPI8W: RRC ;2BIT SHIFT B7..B0->B5..B0,B7,B6
RRC
PUSH D
PUSH B
MVI B,8
SPI8W1: MOV C,A
ANI MOSI
MOV D,A
IN PPAD
ANI (MOSI XOR 0FFH)
ORA D
OUT PPAD
ANI (SCK XOR 0FFH)
OUT PPAD ;SCK L
ORI SCK
OUT PPAD ;SCK H
MOV A,C
RLC
DCR B
JNZ SPI8W1
POP B
POP D
RET
;
SPI8R: PUSH B
LXI B,800H ;B=8(COUNT) C=0(DATA)
SPI8R1: IN PPAD
ANI (SCK XOR 0FFH)
OUT PPAD ;SCK L
ORI SCK
OUT PPAD ;SCK H
IN PPAD
ANI MISO ;10H
ORA C
RLC
MOV C,A
DCR B
JNZ SPI8R1
MOV A,C ;B2,B1,B0,B7 B6,B5,B4,B3
POP B
RLC
RLC
RLC
RET
;
GETR1: CALL GETR
JMP CSH
;
GETR3:
GETR7: CALL GETR
JC CSH ;TIMEOUT
PUSH PSW
CALL SKIP4
POP PSW
RET ;CY=0
;
GETR: PUSH B
MVI B,0
IF DEBUG
CALL MSG
DB 'GETR ',0 ;
ENDIF
GETRR: DCR B
JZ GETRR1
CALL SPI8R
IF DEBUG
PUSH PSW
CALL OUT2HEX$SP
POP PSW
ENDIF
CPI 80H
JNC GETRR
POP B
ANA A ;CY=0
RET
GETRR1: IF DEBUG
CALL CRLF
ENDIF
POP B
STC ;CY=1
RET
;
SKIPFF: PUSH B
MVI B,0
IF DEBUG
CALL MSG
DB 'SKIPFF ',0
ENDIF
SKIPFF1:DCR B
JZ GETRR1 ;TIME OUT
CALL SPI8R
IF DEBUG
PUSH PSW
CALL OUT2HEX$SP
POP PSW
ENDIF
CPI 0FFH
JZ SKIPFF1
ANA A ;CY=0
POP B
RET
;
SKIP4: IF DEBUG
CALL MSG
DB CR,LF,' SKIP4 ',0
ENDIF
CALL SPI8R ;VOLTAGE, OCR
STA OCR
IF DEBUG
CALL OUT2HEX$SP
ENDIF
CALL SPI8R
STA OCR+1
IF DEBUG
CALL OUT2HEX$SP
ENDIF
CALL SPI8R
STA OCR+2
IF DEBUG
CALL OUT2HEX$SP
ENDIF
CALL SPI8R
STA OCR+3
IF DEBUG
CALL OUT2HEX
ENDIF
ANA A ;CY=0
JMP CSH
;
CMD0: CALL CSL
RC
IF DEBUG
CALL MSG
DB CR,LF,'DEBUG CMD0 ',0
ENDIF
CALL CMDS
DB 40H, 00H, 00H, 00H, 00H, 95H
JMP GETR1
;
CMD8: CALL CSL
RC
IF DEBUG
CALL MSG
DB CR,LF,'DEBUG CMD8 ',0
ENDIF
CALL CMDS
DB 48H, 00H, 00H, 01H, 0AAH, 87H
JMP GETR7
;
CMD58: CALL CSL
RC
IF DEBUG
CALL MSG
DB CR,LF,'DEBUG CMD58 ',0
ENDIF
CALL CMDS
DB 7AH, 00H, 00H, 00H, 00H, 0FFH
JMP GETR3
;
CMD55: CALL CSL
RC
IF DEBUG
CALL MSG
DB CR,LF,'DEBUG CMD55 ',0
ENDIF
CALL CMDS
DB 77H, 00H, 00H, 00H, 00H, 0FFH
JMP GETR ;NO CSH
;
ACMD41: IF DEBUG
CALL MSG
DB CR,LF,'DEBUG ACMD41 ',0
ENDIF
CALL CMDS
DB 69H, 40H, 0FFH, 80H, 00H, 0FFH
JMP GETR1
;
CMDS: XTHL
PUSH B
MVI B,6
CMDS1: MOV A,M
INX H
CALL SPI8W
DCR B
JNZ CMDS1
POP B
XTHL
RET
;
READ: CALL CSL ;512BYTE READ
RC
IF DEBUG
CALL MSG
DB CR,LF,'DEBUG CMD17 ',0
ENDIF
MVI A,51H ;CMD17
CALL SPI8W
PUSH B
PUSH H
LXI H,SDPARAM ;SECTOR
MVI B,5 ;SECTOR + CRC
RD1: MOV A,M
INX H
CALL SPI8W
DCR B
JNZ RD1
CALL GETR
JC READ$TIMEOUT
ANA A
JNZ READ$RESPONSE
CALL SKIPFF
JC READ$D$TIMEOUT
CPI 0FEH ;DATA TOKEN
JNZ READ$D$RESPONSE
LHLD DMA
LXI B,200H
RD2: CALL SPI8R
MOV M,A
INX H
DCX B
MOV A,B
ORA C
JNZ RD2
POP H
POP B
CALL SPI8R ;CRC SKIP
CALL SPI8R ;CRC SKIP
JMP CSH ;CY=0
;
WRITE: CALL CSL ;512BYTE WRITE
RC
IF DEBUG
CALL MSG
DB CR,LF,'DEBUG CMD24 ',0
ENDIF
MVI A,58H ;CMD24
CALL SPI8W
PUSH B
PUSH H
LXI H,SDPARAM ;SECTOR
MVI B,5 ;SECTOR + CRC
WR1: MOV A,M
INX H
CALL SPI8W
DCR B
JNZ WR1
CALL GETR
JC WRITE$TIMEOUT
ANA A
JNZ WRITE$RESPONSE
MVI A,0FFH ;DUMMY
CALL SPI8W
MVI A,0FEH
CALL SPI8W ;DATA TOKEN
LHLD DMA
LXI B,200H
WR2: MOV A,M
INX H
CALL SPI8W
DCX B
MOV A,B
ORA C
JNZ WR2
MVI A,0FFH
CALL SPI8W ;CRC
MVI A,0FFH
CALL SPI8W ;CRC
CALL SPI8R ;DATA RESPONSE
ANI 1FH
CPI 5 ;DATA ACCEPTED
JNZ WRITE$D$RESPONSE
POP H
POP B
JMP CSH ;CY=0
;
; FORTH ROUTINE ADDR, BLK, FLAG
RSLW0: POP D ;RETURN AD
POP H ;FLAG
MOV A,L
POP H ;BLK
PUSH PSW
DAD H ;BLK * 2
MOV A,H
STA SDPARAM+2
MOV A,L
STA SDPARAM+3
POP PSW
POP H ;ADDR
SHLD DMA
PUSH D ;RETURN AD
ANA A ;FLAG CHECK
PUSH B
MVI B,2 ;1BLK=512BYTE
JNZ RSLW2 ;0:WRITE 1:READ
RSLW1: CALL WRITE
JC RSLWER
CALL RSLWINC ;INC BLK
DCR B
JNZ RSLW1
JMP RSLW3
RSLW2: CALL READ
JC RSLWER
CALL RSLWINC ;INC BLK
DCR B
JNZ RSLW2
RSLW3: POP B
XRA A ;RESET DSKERR
RET
RSLWER: POP B
MVI A,1 ;SET DSKERR
RET
;
RSLWINC:LDA SDPARAM+3 ;(SDPARAM)=(SDPARAM)+1
INR A
STA SDPARAM+3
JNZ RSLWS1
LDA SDPARAM+2
INR A
STA SDPARAM+2
RSLWS1: LHLD DMA ;(DMA)=(DMA)+200H
LXI D,200H
DAD D
SHLD DMA
RET
;
CMD0$TIMEOUT:
CALL MSG$CMD0
JMP TIMEOUT
;
CMD0$RESPONSE:
CALL MSG$CMD0
JMP OUT2HEX$CR
;
MSG$CMD0:
CALL MSG
DB 'CMD0 ',0
RET
;
CMD8$TIMEOUT:
CALL MSG$CMD8
JMP TIMEOUT
;
CMD8$RESPONSE:
CALL MSG$CMD8
JMP OUT2HEX$CR
;
CMD8$OCRERR:
CALL MSG$CMD8
JMP OCR$PR
;
MSG$CMD8:
CALL MSG
DB 'CMD8 ',0
RET
;
CMD58$TIMEOUT:
CALL MSG$CMD58
JMP TIMEOUT
;
CMD58$RESPONSE:
CALL MSG$CMD58
JMP OUT2HEX$CR
;
CMD58$OCRERR:
CALL MSG$CMD58
OCR$PR: CALL MSG
DB 'OCR ',0
LDA OCR
CALL OUT2HEX$SP
LDA OCR+1
CALL OUT2HEX$SP
LDA OCR+2
CALL OUT2HEX$SP
LDA OCR+3
JMP OUT2HEX$CR
;
MSG$CMD58:
CALL MSG
DB 'CMD58 ',0
RET
;
CMD55$A$TIMEOUT:
CALL MSG
DB 'CMD55,ACMD41 TIMEOUT',CR,LF,0
POP B
JMP CSH
;
CMD55$TIMEOUT:
CALL MSG$CMD55
JMP TIMEOUT$POPB
;
CMD55$RESPONSE:
CALL MSG$CMD55
JMP OUT2HEX$CR
;
MSG$CMD55:
CALL MSG
DB 'CMD55 ',0
RET
;
ACMD41$TIMEOUT:
CALL MSG
DB 'ACMD41 ',0
JMP TIMEOUT$POPB
;
CMD58$2$TIMEOUT:
CALL MSG$CMD58$2
JMP TIMEOUT

CMD58$2$RESPONSE:
CALL MSG$CMD58$2
JMP OUT2HEX$CR
;
CMD58$2$OCRERR:
CALL MSG$CMD58$2
JMP OCR$PR
;
MSG$CMD58$2:
CALL MSG
DB 'CMD58 2ND ',0
RET
;
CSL$TIMEOUT:
CALL MSG
DB 'CSL ',0
JMP TIMEOUT$POPB
;
READ$TIMEOUT:
CALL MSG$READ
JMP TIMEOUT$POPH
;
READ$RESPONSE:
CALL MSG$READ
JMP OUT2HEX$CR$POPH
;
MSG$READ:
CALL MSG
DB 'READ ',0
RET
;
READ$D$TIMEOUT:
CALL MSG$READ$D
JMP TIMEOUT$POPH
;
READ$D$RESPONSE:
CALL MSG$READ$D
JMP OUT2HEX$CR$POPH
;
MSG$READ$D:
CALL MSG
DB 'READ DATA ',0
RET
;
WRITE$TIMEOUT:
CALL MSG$WRITE
JMP TIMEOUT$POPH
;
WRITE$RESPONSE:
CALL MSG$WRITE
JMP OUT2HEX$CR$POPH
;
MSG$WRITE:
CALL MSG
DB 'WRITE ',0
RET
;
WRITE$D$RESPONSE:
CALL MSG$WRITE$D
JMP OUT2HEX$CR$POPH
;
MSG$WRITE$D:
CALL MSG
DB 'WRITE DATA ',0
RET
;
TIMEOUT$POPH:
POP H
TIMEOUT$POPB:
POP B
TIMEOUT:CALL MSG
DB 'TIMEOUT ',0
CALL OUT2HEX$CR
CALL CSH
STC
RET


最新の画像もっと見る

コメントを投稿