You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4114 lines
102 KiB

; Z180MOM1.180 This is the Z180 CPU main monitor program for the S100Computers Z180 SBC Project.
; Assemble and SLR's Z180ASM Assembler
;
; The code is intended to run starting at location 0000H and ignores
; all page zero stuff. Interrupts are kept disabled. The resultant
; binary is intended to be programmed into a ROM that is addressed at
; CPU address 0000H on reset. The code assumes the CPU has been reset
; and makes no attempt to "reset" Z180 registers back to defaults.
;
; The code assumes a physical memory layout of 1MB. The first 512KB
; is assumed to be ROM and the second 512KB is assumed to be RAM. The
; code configures the MMU to place the highest 32KB of physical RAM
; into the top 32KB of CPU address space.
;
; Input XTAL clock is expected to be 18.432 MHz.
; The CPU is configured to run at the most conservative settings.
; PHI at 1/2 XTAL input, +3 memory wait states, and +3 I/O wait states.
;
; Serial port baud rate divisor is programmed to a 57,600 baud rate
; with PHI at 9.2MHz. Line characteristics are set to
; 8 data bits, 1 stop bit, no parity.
;
; The initialization code relocates the internal Z180 CPU registers
; to start at C0H. This is not a requirement of the code, but I
; thought it might be helpful for testing S100 bus external devices that are
; more likely to be located at the lower I/O addresses.
;
; PLEASE NOTE THIS CODE ALMOST TAKES UP 8K TO RESIDE FROM E000H TO FFFFH IN RAM.
; VERY LITTLE MORE CODE CAN BE ADDED WITHOUT OVERWRITING THE TOP OF RAM.
; CURRENTLY THIS IS ONLY ~80 BYTES. CHECK THE VALUE OF "ROM_EMPTY" IN THE
; Z180MON1.LST FILE IF YOU MAKE MODIFICATIONS.
;
;
; The submit file (xxx2.sub) contains:-
; R Z180MOM1.180
; SLR180 Z180MOM1 FH
; HEXCOM Z180MOM1
; W Z180MOM1.HEX
; W Z180MOM1.LST
; W Z180MOM1.COM
;
; Ignore the HEXCOM error "LOAD ADDRESS LESS THAN 100"
;
; To assemble under windows...
; Load Altair.EXE in the Windows CMD box
; do cpm3
; I:
;
; Use the "r" SIMH command to move SLR180.COM file across to the I: Drive
; Also "r" the XXX2.SUB file across to the I: drive (one time only)
; Note I already have these files on the Altair I: drive you are using here.
;
; Then....
; I:>Submit XXX2.SUB
;
; The .HEX file will have a start address of 0000H. It must reside in the ROM starting
; at 0H. For the "ROM" I use the Microchip SST39F040 chip type
; With the Wellon VP 290 Programmer:-
;
; To Buffer Address (HEX)
; For File Address (Hex) 0000 <------
; File Size (Hex) 8000
; Intel
; Clear buffer options 0
; To Buffer Mode Normal
; From File Mode Normal
;
;
;----------------------------------------------------------------------------------------
;
; V0.0 5/10/2023 ;Initial boot code supplied by Wayne Warthen
; V0.1 5/18/2023 ;First addition of S100 bus Z80 Master.Z80 monitor code.
; V0.11 6/5/2023 ;Menu to test S100 bus signals & set Baud Rate
; V0.2 7/4/2023 ;Remove baud rate option, add date,time, start IDE
; V0.21 7/6/2023 ;Cleaned up IDE drive section
; V0.22 7/6/2023 ;Added default NMI and INT0 interrupt traps
; V0.23 7/7/2023 ;Better use of ESC character for data entry aborts
; V0.24 7/8/2023 ;Added Master/Slave S100 bus request ("W" CMD)
; V0.241 7/9/2023 ;Add B command to Boot ROMWBW (by Wayne Warthen)
; V0.242 7/9/2023 ;INT0 test added (S100 Sub Menu)
; V0.30 7/16/2023 ;Added IDE menu and "P" CMD to boot CPM (Non Banked)
; V0.31 7/16/2023 ;Corrected stack problem in XModem command
; V0.32 7/16/2023 ;SD card, but not initilizing, (only partially done)
; V0.33 7/22/2023 ;SD card interface done
; V0.34 7/22/2023 ;SD card interface with high clock speed
;
;--------------------------------- Port equates used throughout the monitor ---------------
;
;
SCROLL EQU 01H ;Set scrool direction UP.
BELL EQU 07H
SPACE EQU 20H
TAB EQU 09H ;TAB ACROSS (8 SPACES FOR SD-BOARD)
CR EQU 0DH
LF EQU 0AH
FF EQU 0CH
QUIT EQU 11H ;Turns off any screen enhancements (flashing, underline etc).
NO_ENHANCEMENT EQU 17H ;Turns off whatever is on
FAST EQU 10H ;High speed scrool
ESC EQU 1BH
DELETE EQU 7FH
BACKS EQU 08H
CLEAR EQU 1AH ;TO CLEAR SCREEN
RST7 EQU 38H ;RST 7 (LOCATION FOR TRAP)
NN EQU 0H ;[I] INITIAL VALUE
SOH EQU 1 ; For XModem etc.
EOT EQU 4
ACK EQU 6
NAK EQU 15H
FALSE EQU 0
TRUE EQU NOT FALSE
DO_CODE EQU FALSE ;To skip over sections
ST8C4 EQU TRUE ;TRUE if S100_Parallel_IO Board. False if IMSAI PIO Board
IOBYTE EQU 075H ;IOBYTE PORT ON Z180 CPU Board (74H-77H or 64H-67H. Set with K8)
SOUT_PORT EQU 074H ;Onboard port to control (on/off) sOUT signal to S100 bus.
NMI_VECTOR EQU 66H ;Default NMI Vector location
INT0_VECTOR EQU 38H ;Default INT0 vector location
SD_CARD_CS EQU 0CH ;Bit 2 to select onboard SD card adaptor (0=ON, 1=off)
SD_CARD_LED EQU 0EH ;Bit 2 to turn on/off SD Card LED (0=ON, 1=off)
SD_CNTR EQU z180_cntr ;SPI CTRL PORT (0CAH)
SD_TRDR EQU z180_trdr ;SPI DATA PORT IN & OUT (0CBH)
;
;
;-------------- PROPELLER CONSOLE_IO (OR SD SYSTEMS VIDIO BOARD) FOR CONSOLE INPUT & OUTPUT
CONSOLE_STATUS EQU 0H
CONSOLE_IN EQU 01H
CONSOLE_OUT EQU 01H
;-------------- THIS IS MY PORT TO OUTPUT DATA TO HP 4050T LASAR PRINTER (IMSAI or 8PIO Board)
IF ST8C4 ;If S100_Parallel_IO Board for Printer output
PRINTER_CTRL EQU 0C2H ;ST8C4 Control Port
PRINTER_STATUS EQU 0C1H ;ST8C4 Status port
PRINTER_OUT EQU 0C0H ;ST8C4 Data port
PRINTER_ST_LOW EQU 0DH ;OUT STROBE LOW
PRINTER_ST_HIGH EQU 0CH ;OUT STROBE HIGH
ELSE
PRINTER_STATUS EQU 5 ;IN, IMSAI PIO Board PARRELL PORT
PRINTER_OUT EQU 5 ;OUT
PRINTER_STROBE EQU 4 ;OUT
ENDIF
;-------------- S100Computers MSDOS Support Board PORT ASSIGNMENTS
CMOS_PORT EQU 70H ;Base Port for CMOS Clock/Date Chip on MSDOS Support Board
MASTER_PIC_PORT EQU 20h ;Hardware port the 8259A (two ports 20H & 21H)
MasterICW1 equ 00010111B ;EDGE triggered, 4 bytes, single Master,ICW4 needed
MasterICW2 equ 8H ;Base address for 8259A Int Table (IBM-PC uses 8X4 = 20H)
MasterICW3 equ 0H ;No slave
MasterICW4 equ 00000011B ;No special mode, non buffer, Auto EOI, 8086. ;<<<<,
;-------------------------- SMBs Board ------------------------------------------------
SW_TMAX EQU 0EEH ;OUTPUT BIT 0 HIGH FROM THIS PORT LOWERS DMA0* ON THE SMB_V2 (SWITCH IN THE 8086 FAMILY of boards)
;OUTPUT BIT 1 HIGH FROM THIS PORT LOWERS DMA1* ON THE SMB_V2 (SWITCH IN THE 68000 CPU Board)
;OUTPUT BIT 2 HIGH FROM THIS PORT LOWERS DMA2* ON THE SMB_V2
;OUTPUT BIT 3 HIGH FROM THIS PORT LOWERS DMA3* ON THE SMB_V2
SW_TMA0 EQU 0EDH ;INPUT FROM THIS PORT LOWERS DMA0* (SWITCHES IN THE 8088,8086,80286 or 80386 boards)
;-------------- S100Computers I/O BOARD PORT ASSIGNMENTS (A0-AC) ------------------------------------
BCTL EQU 0A0H ;CHANNEL B CONTROL (SPEECH PORT) ;<--- Adjust as necessary,
BDTA EQU 0A2H ;CHANNEL B DATA
ACTL EQU 0A1H ;CHANNEL A CONTROL (MODEM_CTL_PORT)
ADTA EQU 0A3H ;CHANNEL A DATA (MODEM_DATA_PORT)
PortA_8255 EQU 0A8H ;A port of 8255 ;<--- Adjust as necessary
PortB_8255 EQU 0A9H ;B port of 8255
PortC_8255 EQU 0AAH ;C Port of 8255
PortCtrl_8255 EQU 0ABH ;8255 configuration port
AinBout8255cfg EQU 10011000b ;Set 8255 ports:- A input, B output,
USB_DATA EQU 0ACH ;PORT ASSIGNEMENT FOR DLP-USB Controller chip
USB_STATUS EQU 0AAH ;Status port for USB port (Port C of 8255, bits 6,7)
USB_RXE EQU 80H ;If Bit 7 = 0, data available to recieve by S-100 Computer
USB_TXE EQU 40H ;If Bit 6 = 0 data CAN be written for transmission to PC
BASE_PORT EQU 0A1H ;For XModem communication routines
MODEM_CTL_PORT EQU BASE_PORT ;A1H (Note modem I/O will be on CHANNEL A. Speaker on CHANNEL B
MODEM_DATA_PORT EQU BASE_PORT+2 ;A3H
MODEM_SEND_MASK EQU 4
SEND_READY EQU 4 ;VALUE WHEN READY
MODEM_RECV_MASK EQU 1
RECV_READY EQU 1 ;BIT ON WHEN READY
MODEM_ERR_LIMIT EQU 8 ;Max number of Modem serial port re-reads aborting
MODEM_RTS_DELAY EQU 1 ;Time to check Modem RTS line (See XMODEM_LOAD & P_XMODEM_LOAD). Not critical.
RECVD_SECT_NO EQU 0H ;IX Offset for XModem Recieved Sector Number
SECTNO EQU 1H ;IX Offset for XModem CURRENT SECTOR NUMBER
ERRCT EQU 2H ;IX Offset for XModem ERROR COUNT
;-------------- S100Computers IDE/CF CARD Port Assignements (30-34H)----------------------------
IDEAport EQU 030H ;lower 8 bits of IDE interface
IDEBport EQU 031H ;upper 8 bits of IDE interface
IDECport EQU 032H ;control lines for IDE interface
IDECtrl EQU 033H ;8255 configuration port
IDEDrivePort EQU 034H ;To select the 1st or 2nd CF card/drive (Not used with this monitor)
IDE_Reset_Delay EQU 020H ;Time delay for reset/initilization (~60 uS, with 10MHz Z80, 2 I/O wait states)
CPM_ADDRESS EQU 100H ;Will place the CPMLDR.COM Loader here with
;CPMLDR.COM will ALWAYS be on TRK 0,SEC2, (LBA Mode)
SEC_COUNT EQU 12 ;CPMLDR.COM requires (currently) 10, 512 byte sectors
RDcfg8255 EQU 10010010B ;Set 8255 IDECport out, IDEAport/B input
WRcfg8255 EQU 10000000B ;Set all three 8255 ports output
;IDE control lines for use with IDEportC.
IDEa0line EQU 01H ;direct from 8255 to IDE interface
IDEa1line EQU 02H ;direct from 8255 to IDE interface
IDEa2line EQU 04H ;direct from 8255 to IDE interface
IDEcs0line EQU 08H ;inverter between 8255 and IDE interface
IDEcs1line EQU 10H ;inverter between 8255 and IDE interface
IDEwrline EQU 20H ;inverter between 8255 and IDE interface
IDErdline EQU 40H ;inverter between 8255 and IDE interface
IDEreset EQU 80H ;inverter between 8255 and IDE interface
;Symbolic constants for the IDE Drive registers, which makes the
;code more readable than always specifying the address bits
REGdata EQU IDEcs0line
REGerr EQU IDEcs0line + IDEa0line
REGseccnt EQU IDEcs0line + IDEa1line
REGsector EQU IDEcs0line + IDEa1line + IDEa0line
REGcylinderLSB EQU IDEcs0line + IDEa2line
REGcylinderMSB EQU IDEcs0line + IDEa2line + IDEa0line
REGshd EQU IDEcs0line + IDEa2line + IDEa1line ;(0EH)
REGcommand EQU IDEcs0line + IDEa2line + IDEa1line + IDEa0line ;(0FH)
REGstatus EQU IDEcs0line + IDEa2line + IDEa1line + IDEa0line
REGcontrol EQU IDEcs1line + IDEa2line + IDEa1line
REGastatus EQU IDEcs1line + IDEa2line + IDEa1line + IDEa0line
;IDE Command Constants. These should never change.
COMMANDrecal EQU 10H
COMMANDread EQU 20H
COMMANDwrite EQU 30H
COMMANDinit EQU 91H
COMMANDid EQU 0ECH
COMMANDspindown EQU 0E0H
COMMANDspinup EQU 0E1H
; IDE Status Register:
; bit 7: Busy 1=busy, 0=not busy
; bit 6: Ready 1=ready for command, 0=not ready yet
; bit 5: DF 1=fault occured insIDE drive
; bit 4: DSC 1=seek complete
; bit 3: DRQ 1=data request ready, 0=not ready to xfer yet
; bit 2: CORR 1=correctable error occured
; bit 1: IDX vendor specific
; bit 0: ERR 1=error occured
SEC$SIZE EQU 512 ;Assume sector size as 512. (Not tested for other sizes)
MAXSEC EQU 3DH ;Sectors per track for CF my Memory drive, Kingston CF 8G. (For CPM format, 0-3CH)
;This translates to LBA format of 1 to 3D sectors, for a total of 61 sectors/track.
;This CF card actully has 3F sectors/track. Will use 3D for my CPM3 system because
;my Seagate drive has 3D sectors/track. Don't want different CPM3.SYS files around
;so this program as is will also work with a Seagate 6531 IDE drive
MAXTRK EQU 0FFH ;CPM3 allows up to 8MG so 0-256 "tracks"
STARTCPM EQU 100H ;Start location for CPM
;-----------------------------------------------------------------------------------------------------
z180_base equ 0C0h ;Will relocate all internal Z180 IO ports from 0-3FH to C0-FFH. The S100 bus
;hardware intrerface will kick in if these ports are activeted.
;See the schematic
;
mon_start EQU 0E000h ;Final location of this monitor 0E000H (First 56K free RAM)
RAM_STORE EQU 07000H ;Need to store some RAM variables
STACK EQU 0DFF0H ;The stack below the monitor
IDE_Buffer EQU 100H ;Will place the IDE/CF Card Buffer here
SD_Buffer EQU 100H ;Will place the SD Card buffer here
;
z180_cntla0 equ z180_base + 00H ; asci0 control a
z180_cntla1 equ z180_base + 01H ; asci1 control a
z180_cntlb0 equ z180_base + 02H ; asci0 control b
z180_cntlb1 equ z180_base + 03H ; asci1 control b
z180_stat0 equ z180_base + 04H ; asci0 status
z180_stat1 equ z180_base + 05H ; asci1 status
z180_tdr0 equ z180_base + 06H ; asci0 transmit
z180_tdr1 equ z180_base + 07H ; asci1 transmit
z180_rdr0 equ z180_base + 08H ; asci0 receive
z180_rdr1 equ z180_base + 09H ; asci1 receive
z180_cntr equ z180_base + 0aH ; csi/o control ;<----- For SD Card
z180_trdr equ z180_base + 0bH ; csi/o transmit/receive ;<----- For SD card
z180_tmdr0l equ z180_base + 0cH ; timer 0 data lo
z180_tmdr0h equ z180_base + 0dH ; timer 0 data hi
z180_rldr0l equ z180_base + 0eH ; timer 0 reload lo
z180_rldr0h equ z180_base + 0fH ; timer 0 reload hi
z180_tcr equ z180_base + 10H ; timer control
;
z180_asext0 equ z180_base + 12H ; asci0 extension control (z8s180)
z180_asext1 equ z180_base + 13H ; asci1 extension control (z8s180)
;
z180_tmdr1l equ z180_base + 14H ; timer 1 data lo
z180_tmdr1h equ z180_base + 15H ; timer 1 data hi
z180_rldr1l equ z180_base + 16H ; timer 1 reload lo
z180_rldr1h equ z180_base + 17H ; timer 1 reload hi
z180_frc equ z180_base + 18H ; free running counter
z180_astc0l equ z180_base + 1aH ; asci0 time constant lo (z8s180)
z180_astc0h equ z180_base + 1bH ; asci0 time constant hi (z8s180)
z180_astc1l equ z180_base + 1cH ; asci1 time constant lo (z8s180)
z180_astc1h equ z180_base + 1dH ; asci1 time constant hi (z8s180)
z180_cmr equ z180_base + 1eH ; clock multiplier (latest z8s180)
z180_ccr equ z180_base + 1fH ; cpu control (z8s180)
;
z180_sar0l equ z180_base + 20H ; dma0 source addr lo
z180_sar0h equ z180_base + 21H ; dma0 source addr hi
z180_sar0b equ z180_base + 22H ; dma0 source addr bank
z180_dar0l equ z180_base + 23H ; dma0 dest addr lo
z180_dar0h equ z180_base + 24H ; dma0 dest addr hi
z180_dar0b equ z180_base + 25H ; dma0 dest addr bank
z180_bcr0l equ z180_base + 26H ; dma0 byte count lo
z180_bcr0h equ z180_base + 27H ; dma0 byte count hi
z180_mar1l equ z180_base + 28H ; dma1 memory addr lo
z180_mar1h equ z180_base + 29H ; dma1 memory addr hi
z180_mar1b equ z180_base + 2aH ; dma1 memory addr bank
z180_iar1l equ z180_base + 2bH ; dma1 i/o addr lo
z180_iar1h equ z180_base + 2cH ; dma1 i/o addr hi
z180_iar1b equ z180_base + 2dH ; dma1 i/o addr bank (z8s180)
z180_bcr1l equ z180_base + 2eH ; dma1 byte count lo
z180_bcr1h equ z180_base + 2fH ; dma1 byte count hi
z180_dstat equ z180_base + 30H ; dma status
z180_dmode equ z180_base + 31H ; dma mode
z180_dcntl equ z180_base + 32H ; dma/wait control
z180_il equ z180_base + 33H ; interrupt vector load
z180_itc equ z180_base + 34H ; int/trap control
;
z180_rcr equ z180_base + 36H ; refresh control
;
z180_cbr equ z180_base + 38H ; mmu common base register
z180_bbr equ z180_base + 39H ; mmu bank base register
z180_cbar equ z180_base + 3aH ; mmu common/bank area register
;
z180_omcr equ z180_base + 3eH ; operation mode control
z180_icr equ z180_base + 3fH ; i/o control register
;
;
CLOCK_VALUE_CMR equ 00H ;For setting CPU clock speed
CLOCK_VALUE_CCR equ 00H ; " "
CNTLB0_VALUE equ 00H ; For setting final baud rate from clock
;
; (CMR) (CCR) (CNTLB0) Baud PHI ;These settings need to be checked!
; 00H 80H 20H 38,400 18.432 MHz ;Using 18.432MHz Oscillator
; 00H 00H 20H 19,200 9.2 MHz ;Using 18.432MHz Oscillator
; 00H 80H 00H 115,200 18.432 MHz ;Using 18.432MHz Oscillator
;
; 00H 00H 00H 57,600 9.2 MHz ;Setting for S100 Bus Interface
;
;=======================================================================
; BOOTSTRAP
;
; This code is begins at 0000H and is expected to get control upon
; CPU reset. It does minimal Z180 CPU initialization, then copy
; the monitor code to upper CPU RAM (F000H) and jump to it.
;=======================================================================
;
org 0000h
;
; Initialize Z180
;
; This code does *not* handle interrupts. Disable them and leave
; them disabled.
im 1
di
;
; Set base for CPU I/O registers.
; Do not use z180_icr equate from z180.inc because the ICR
; is not yet at the running location. At reset, the Z180
; register base I/O address is zero, so initially, ICR is
; at 3FH.
ld a,z180_base ; C0H
out0 (3Fh),a ; at reset, icr is at 3FH
xor a ; Disable refresh (not really required)
out0 (z180_rcr),a
; To make PHI=Osc Input, set bit 7 of CCR
; To make OHI=2X Osc Input, set bits 7 of CCR and CMR
ld a,CLOCK_VALUE_CMR ; 00H, Set clock speed,(normally 0H)
out0 (z180_cmr),a ; set CMR
ld a,CLOCK_VALUE_CCR ; 80H, (normally 80H, OSC=PHI)
out0 (z180_ccr),a ; set CCR
;
;
; set default wait states (super conservative for now)
ld a,0F0h ; +3 mem waits, +3 i/o waits
out0 (z180_dcntl),a
;
; Setup Z180 MMU assuming physical memory is
; 512KB ROM / 512KB RAM. CPU address spaces is split at
; 32KB/32KB. The upper 32KB is mapped to the top 32KB of
; physical memory (RAM). The lower 32KB is left mapped to
; the lowest 32KB of memory (ROM), so we continue to run
; from ROM at this point.
ld a,80h
out0 (z180_cbar),a ; setup for 32k/32k bank config
ld a,(1024 - 64) >> 2
out0 (z180_cbr),a ; common base = last (top) bank
;
; We have RAM now in upper 32K now. Initialize the stack
; at top of CPU memory.
ld sp,STACK ; Put the stack just below the monitor at E000H (DFFF0)
;
; Confirm RAM is working by pushing a value on the stack, then
; popping the value to a different register and writing it to the
; diagnostic LEDs
;
ld hl,mon_img
ld de,mon_start
ld bc,mon_len
ldir
;
jp mon_start
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;To clean up PROM for easy reading
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Db 0,0,0,0
; Jump to monitor!!!
;
;
;=======================================================================
; MONITOR
;
; This is the system moitor code that is intended to run from RAM at
; E000H.
;=======================================================================
;
mon_img equ $ ; start of monitor image
;
.phase mon_start ; running location for monitor
;
JP OVER_VECTORS
CON_OUT: JP ZCO ;0E003H, Interrupt/BIOS routines are counting on these locations
CON_STAT: JP ZCSTS ;0E006H, never changing
CON_IN: JP ZCI ;0E009H
SEND_STRING: JP PRINT_STRING ;0E00CH
MONITOR_NMI JP DEFAULT_NMI ;0E00FH
MONITOR_INTO JP DEFAULT_INT0 ;0E012H
DEFAULT_NMI:
PUSH AF
PUSH BC
PUSH HL
LD HL,NMI_MSG
CALL PRINT_STRING
POP HL
POP BC
POP AF
RETI
DEFAULT_INT0:
PUSH AF
PUSH BC
PUSH HL
LD HL,INT0_MSG
CALL PRINT_STRING
POP HL
POP BC
POP AF
RETI
OVER_VECTORS:
ld a,64h ; xmit enable, rcv enable, 8 data bits, no parity
out0 (z180_cntla0),a
ld a,CNTLB0_VALUE ; 20H, Baud=19,200 @ 9.2 MHz
out0 (z180_cntlb0),a
ld a,60h ; dcd0 disable, cts0 disable
out0 (z180_asext0),a
;
;
ld b,0 ; Delay after ASCI setup (should not be needed)
djnz $
djnz $
;
; Select first bank of RAM into lower 32K of CPU memory. This is
; where we abandon the physical ROM and switch to all RAM in the
; CPU address space.
;
ld a,10h ; first physical bank of RAM
call bnksel ; do it
;
; *** Add code as desired to setup Z180 zero page ***
;
; At this point RAM is mapped to entire CPU address space. This is
; the right place to setup lower RAM, if needed. However, nothing
; needs to be done for the remainder of this sample code.
;
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
;
BEGIN0: JP BEGIN ;JUMP OVER COMMAND TABLE
TBL: DW FLUSH ;"@" SEND FF to LaserJet printer
DW MEMMAP ;"A" DISPLAY A MAP OF MEMORY
DW BOOT ;"B" BOOT ROMWBW
DW NOT_DONE ; "C" SPARE
DW DISP ;"D" DISPLAY MEMORY (IN HEX & ASCII)
DW CHAR_TEST ;"E" ECHO CHAR IN TO CHAR OUT
DW FILL ;"F" FILL MEMORY WITH A CONSTANT
DW GOTO ;"G" GO TO [ADDRESS]
DW SHOW_DATE ;"H" SHOW CURRENT DATE
DW SHOW_TIME ;"I" SHOW CURRENT TIME
DW MEM_TEST ;"J" DESTRUCTIVE MEMORY TEST
DW KCMD ;"K" DISPLAY THE LIST OF MONITOR COMMANDS
DW NOT_DONE ; "L" SPARE
DW MOVE ;"M" MOVE BLOCK OF MEMORY (START,FINISH,DESTINATION)
DW S100_TESTS ;"N" Hardware tests for the S100 bus
DW SWITCH_8086 ;"O" INPUT Port ED (switched in 8086/80286)
DW HBOOTCPM ;"P" BOOT IN CPM FROM The S100 bus IDE/CF Card Board
DW QUERY ;"Q" QUERY PORT (IN OR OUT)
DW INPORTS ;"R" Read ALL Input Ports
DW SUBS ;"S" SUBSTITUTE &/OR EXAMINE MEMORY
DW TYPE ;"T" TYPE ASCII PRESENT IN MEMORY (Same as D cmd except ASCII)
DW HALT_CPU ;"U" HALT CPU
DW VERIFY ;"V" COMPARE MEMORY
DW SD_CARD_MENU ;"W" SD CARD MENU
DW XMODEM ;"X" DOWNLOAD A FILE FROM PC VIA XMODEM VIA THE S100 SERIAL BOARD
DW IDE_BOARD_MENU ;"Y" IDE Menu for IDE/CF Card Board
DW SIZE ;"Z" FIND HIGHEST R/W RAM
BEGIN: DI ;No interrupts
XOR A ;SET INTERRUPT TO PAGE 0H
LD I,A ;Z80 Interrupt page 0
SETUP_STACK:
LD SP,AHEAD-4 ;SETUP A FAKE STACK
JP MEMSZ1 ;RETURNS WITH TOP OF RAM IN [HL]
DW AHEAD ;A Return opcode will pick up this address
AHEAD:
LD SP,STACK ;Put stack below monitor at 0EFF0H
LD HL,0
ADD HL,SP
PUSH HL ;Store it for below
POP IY
IF ST8C4 ;If S100_Parallel_IO Board for Printer output
LD A,08H ;Initilize the ST8C4 PC-Printer Port IO
OUT (PRINTER_CTRL),A
ELSE
LD A,0FFH ;IMSAI PIO Board. Clear Printer strobe, comes up 0 on a reset
OUT (PRINTER_STROBE),A
ENDIF
;We need to clear the 8259A otherewise the 8086 monitor sometimes hangs
LD A,MasterICW1 ;Initilize the 8259A PIC Controller (;EDGE triggered, 4 bytes, single Master,ICW4 needed)
OUT (MASTER_PIC_PORT),A
LD A,MasterICW2 ;Ints starts at 20H in RAM (IBM-PC uses 8X4 = 20H)
OUT (MASTER_PIC_PORT+1),A
LD A,MasterICW4 ;No slaves above, so 8259 does not expect ICW3
out (MASTER_PIC_PORT+1),A
LD A,11111111b ;Allow no interrupts to the 8259A with Z80.
out (MASTER_PIC_PORT+1),A
LD HL,SIGNON_MSG
CALL PRINT_STRING ;Have a Stack, so now we can use CALL
LD HL,TOP_RAM_MSG ;Print Top of RAM
CALL PRINT_STRING
LD HL,STACK-0F0H ;Top of RAM available RAM
CALL HL_ONLY ;Print HL/SP
LD HL,SP_MSG ;Print Current Stack Location
CALL P_STRING
PUSH IY ;SP is stored from above in [IY]
POP HL
CALL HL_ONLY ;Print HL/SP
LD HL,IOBYTE_MSG ;Print Current IOBYTE value
CALL P_STRING
IN0 A,(IOBYTE) ;Show IOBYTE. If bit 0=0 (force printer output), CMP/3 boot will hang
CALL ZBITS
CALL ZCRLF ;Then ZCRLF
LD A,04H ; Turn off the SD card adaptor CS* line
OUT0 (SD_CARD_CS),A ; 0CH
OUT0 (SD_CARD_LED),A ; 0EH
CALL ZCSTS ;CHECK IF GARBAGE AT KEYBOARD
CALL NZ,ZCI ;If so flush it
; Echo input to output
;Initilize the S100Computers Serial Ports I/O Board
CALL INIT_SCC_A ;Initilize the Zilog 8530-A (XModem I/O)
CALL INIT_SCC_B ;Initilize the Zilog 8530-B (Speech synthizer)
;Next initilize the 8255 on this same board
LD A,AinBout8255cfg ;A input, B output, C(bits 0-3) output, (bits 4-7)input
OUT (PortCtrl_8255),A ;Config 8255 chip, Mode 0
;Note 8255 port C used for DLP-USP Port Chip Status
LD HL,CR_SMSG_SP ;lets V-Stamp chip get baud rate
CALL SPEAK$
;-------THIS IS THE START ON THE MAIN MONITOR LOOP--------------------------------
ZSTART: LD DE,ZSTART
PUSH DE ;EXTRA UNBALANCED POP & [DE] WOULD END UP IN [PC]
CALL ZCRLF
LD C,'-'
CALL ZCO
LD C,'>'
CALL ZCO
STARO: CALL TI ; Main loop. Monitor will stay here until cmd.
CP ESC ; escape?
jp z,echoz ; done if so
AND 7FH
JR Z,STARO
SUB '@' ;Commands @ to Z only
RET M
CP 1BH ;A-Z only
RET NC
ADD A,A
LD HL,TBL
ADD A,L
LD L,A
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
LD C,02H
JP (HL) ;JUMP TO THE COMMAND TABLE
;>>>>>>>>>>>>>>>>>>>> MAIN CONSOLE ROUTINES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Print a single character in C to the primary CONSOLE PORT
; Will wait for serial output port to be ready.
;
ZCO: IN0 A,(IOBYTE) ;Charcter in C
BIT 0,A
JR NZ,SERIAL_ZCO
S100_ZCO:
IN0 A,(CONSOLE_STATUS) ;S100 Bus PROPELLER CONSOLE I/O BOARD PORT
AND 4H
JR Z,S100_ZCO
; CALL DELAY
LD A,C
CP 07H ;IS IT A BELL
JR Z,BELL1
CP 0H ;SD BOARD CANNOT TAKE A NULL!
RET Z
OUT0 (CONSOLE_OUT),A
RET ;RETURN CHARACTER SENT IN [A]
BELL1: LD A,06H ;SEND A BELL
OUT0 (CONSOLE_OUT),A
LD A,0FH
CALL BELL_DELAY
LD A,07H
OUT0 (CONSOLE_OUT),A
LD A,C
RET
BELL_DELAY:
DEC A ;GENERAL COUNT DOWN TIME DELAY
RET Z ;LENGTH SET IN [A]
PUSH AF
LD A,05H
MORE: DEC A
PUSH AF
XOR A
MORE2: DEC A
JR NZ,MORE2
POP AF
JR NZ,MORE
POP AF
JR BELL_DELAY
;
;
SERIAL_ZCO: ;;SC131 CIRCUIT SERIAL PORT
call outstat ; get output status
jr z,SERIAL_ZCO ; loop till ready
; CALL DELAY
out0 (z180_tdr0),C ; send character in C
ret ; done
;
; Check status of ASCI serial output. Returns non-zero (ZF cleared)
; if output register ready
;
outstat:
in0 a,(z180_stat0) ; get status
and 02h ; bit 1 set means ready
ret ; done
;
;
;
;
; Get a single character from the primary CONSOLE PORT and return
; it in A. Will wait for serial input port to have a char ready.
;
ZCI: IN0 A,(IOBYTE)
BIT 0,A
JR NZ,SERIAL_ZCI
S100_ZCI:
IN0 A,(CONSOLE_STATUS) ;NEED CONSTAT TO CLEAN UP SHIFT KEYS ETC
AND 02H
JR Z,S100_ZCI
IN0 A,(CONSOLE_IN)
AND 7FH ;7 bits only
RET
;
;
SERIAL_ZCI:
call SERIAL_ZCSTS ; get input status
jr z,SERIAL_ZCI ; loop till char ready
in0 a,(z180_rdr0) ; get it
ret ; done
;
;
; Check status of CONSOLE INPUT PORT. Returns non-zero (ZF cleared)
; if the input port has a character available. Note that Z180 ASCI
; will stall (stop reception) if a line error is detected. In order
; to ensure continuous reception, it is necessary to check for and
; clear line errors.
;
ZCSTS: IN0 A,(IOBYTE)
BIT 0,A
JR NZ,SERIAL_ZCSTS
S100_ZCSTS:
IN0 A,(CONSOLE_STATUS)
AND 02H
JP Z,NOCHAR
XOR A
DEC A ;RETURN WITH 0FFH IN [A] IF SOMETHING
RET
NOCHAR: XOR A ;RETURN WITH 0 IN A IF NOTHING THERE
RET
;
;
SERIAL_ZCSTS:
in0 a,(z180_stat0) ; read stat reg
push af ; save status
and 70h ; parity, framing, or overrun error?
jr z,instat1 ; jump ahead if no errors
; clear error(s) or nothing further can be received!!!
in0 a,(z180_cntla0) ; read CNTLA
res 3,a ; clear efr (error flag reset)
out0 (z180_cntla0),a ; write updated CNTLA
instat1:
pop af ; restore status value
and 80h ; data ready?
ret ; done
;
;
;DELAY:
; PUSH BC
; LD B,10
; DJNZ $
; POP BC
; RET
;---------------------------- A COMMAND MEMORY MAP -------------------------------------------
;MEMORY MAP PROGRAM CF.DR.DOBBS VOL 31 P40.
;IT WILL SHOW ON CONSOL TOTAL MEMORY SUMMARY OF RAM,PROM, AND NO MEMORY
MEMMAP:
CALL ZCRLF
LD HL,0
LD B,1
MAP1: LD E,'R' ;PRINT R FOR RAM
LD A,(HL)
CPL
LD (HL),A
CP (HL)
CPL
LD (HL),A
JR NZ,MAP2
CP (HL)
JR Z,PRINT
MAP2: LD E,'p'
MAP3: LD A,0FFH
CP (HL)
JR NZ,PRINT
INC L
XOR A
CP L
JR NZ,MAP3
LD E,'.'
PRINT: LD L,0
DEC B
JR NZ,NLINE
LD B,16
CALL ZCRLF
CALL HXOT4
NLINE: LD A,SPACE
CALL OTA
LD A,E
CALL OTA
INC H
JR NZ,MAP1
CALL ZCRLF
CALL ZCRLF
JP ZSTART
;16 HEX OUTPUT ROUTINE
HXOT4: LD C,H
CALL HXO2
LD C,L
HXO2: LD A,C
RRA
RRA
RRA
RRA
CALL HXO3
LD A,C
HXO3: AND 0FH
CP 10
JR C,HADJ
ADD A,7
HADJ: ADD A,30H
OTA: PUSH BC
LD C,A
CALL ZCO ;SEND TO CONSOL
POP BC
RET
;---------------------------- B COMMAND BOOT ROMWBW -------------------------------------------
;RESTART SYSTEM WITH ROMWBW BOOT OVERRIDE FLAG IN THE Z180 RELOAD
;REGISTER 1 LOW
BOOT: LD HL,BOOT_ROM_MSG ;Booting ROMWBW
CALL PRINT_STRING
LD A,'W' ;OVERRIDE VALUE
OUT0 (Z180_RLDR1L),A ;SET RELOAD REGISTER 1 LOW
XOR A ;ROM BANK 0 PLEASE
CALL bnksel ;SELECT BANK IN LOW MEM
JP 0 ;AND JUMP TO THE START
;----------------------- D COMMAND DISPLAY MEMORY IN HEX ---------------------------------------
DISP: CALL EXLF ;GET PARAMETERS IN [HL],[DE]
LD A,L ;ROUND OFF ADDRESSES TO XX00H
AND 0F0H
LD L,A
LD A,E ;FINAL ADDRESS LOWER HALF
AND 0F0H
ADD A,10H ;FINISH TO END 0F LINE
SF172: CALL LFADR
SF175: CALL BLANK
LD A,(HL)
CALL ZHEXOUT
CALL HILOX
LD A,L
AND 0FH
JR NZ,SF175
LD C,TAB ;INSERT A TAB BETWEEN DATA
CALL ZCO
LD B,4H ;ALSO 4 SPACES
TA11: LD C,SPACE
CALL ZCO
DJNZ TA11
LD B,16 ;NOW PRINT ASCII (16 CHARACTERS)
PUSH DE ;TEMPORLY SAVE [DE]
LD DE,0010H
SBC HL,DE
POP DE
T11: LD A,(HL)
AND 7FH
CP ' ' ;FILTER OUT CONTROL CHARACTERS'
JR NC,T33
T22: LD A,'.'
T33: CP 07CH
JR NC,T22
LD C,A ;SET UP TO SEND
CALL ZCO
INC HL
DJNZ T11 ;REPEAT FOR WHOLE LINE
JR SF172
BLANK: LD C,' '
JP ZCO
;----------------------- N COMMAND S100 BUS TESTS ---------------------------------------
S100_TESTS:
LD HL,S100_MENU
CALL PRINT_STRING
CALL PCHK
CP '0'
JP Z,ROOL_ADDRESSES
CP '1'
JP Z,sOUT_TEST
CP '2'
JP Z,sINP_TEST
CP '3'
JP Z,CONSOLE_IO_TEST
CP '4'
JP Z,SPEECH_TEST
CP '5'
JP Z,MODEM_TEST
CP '6'
JP Z,PRINTER_TEST
CP '7'
JP Z,TOGGLE_INTS
CP ESC
JP Z,MENU_DONE
JP ERROR
MENU_DONE:
CALL ZCRLF
CALL ZCRLF
JP BEGIN
ROOL_ADDRESSES:
LD HL,0
HL_LOOP:
PUSH HL
CALL HL_ONLY
CALL ZSPACE
LD A,(HL)
CALL ZHEXOUT
CALL ZCRLF
POP HL
INC HL
CALL ZCSTS ; get input status
JR Z,HL_LOOP ; nothing
CALL ZCI ; loop till char ready
CP A,ESC ; Abort if ESC
JP Z,S100_TESTS ; done
JR HL_LOOP
sOUT_TEST:
LD A,'3'
OUT (CONSOLE_OUT),A
JR sOUT_TEST
sINP_TEST:
IN0 A,(CONSOLE_IN)
PUSH AF
CALL ZHEXOUT
CALL ZSPACE
POP AF
CALL ZBITS
CALL ZCRLF
JR sINP_TEST
CONSOLE_IO_TEST:
LD HL,CONSOLE_TEST ;'Enter S100 bus keyboard char. ESC to abort ',0
CALL PRINT_STRING
IN_TEST2:
CALL S100_ZCI
CP A,ESC
JP Z,S100_TESTS ; done
LD C,A
CALL S100_ZCO
JR IN_TEST2
SPEECH_TEST:
LD HL,SMSG_SP
CALL SPEAK$
JP S100_TESTS ; done
MODEM_TEST:
LD HL,CONSOLE_TEST ;'Enter S100 bus keyboard char. ESC to abort ',0
CALL PRINT_STRING
MODEM_TEST1:
CALL S100_ZCSTS
JR Z,MODEM_TEST2
CALL ZCI ;Get a keyboard character
LD C,A
CP A,ESC
JP Z,S100_TESTS ; done
CALL ZCO
CALL MODEM_ZCO
MODEM_TEST2:
CALL MODEM_ZSTATUS
JP Z,MODEM_TEST1
CALL MODEM_ZCI ;Get a character
LD C,A
CP A,ESC
JP Z,S100_TESTS ; done
CALL ZCO
CALL MODEM_ZCO
JP MODEM_TEST1
PRINTER_TEST:
LD HL,S100_MENU ; Print test menu
PRINTER_TEST1:
ld a,(hl) ; get next char
CP A,'$' ; Terminate with a '$' or 0H
JP Z,PRINTER_TEST2
or a ; end of string?
JP Z,PRINTER_TEST2
LD C,A
call LO ; print the char
inc hl ; bump to next char in string
jr PRINTER_TEST1 ; loop till done
PRINTER_TEST2:
CALL FLUSH
RET
TOGGLE_INTS:
LD HL,NMI_VECTOR ;Set default NMI vector jump at 66H in RAM
LD A,0C3H
LD (HL),A
INC HL
LD DE,DEFAULT_NMI
LD (HL),E
INC HL
LD (HL),D
LD HL,INT0_VECTOR ;Set default INT0 vector jump at 38H in RAM
LD A,0C3H
LD (HL),A
INC HL
LD DE,DEFAULT_INT0
LD (HL),E
INC HL
LD (HL),D
LD A,(@INTS_FLAG)
OR A
JR Z,TURN_ON_INTS
LD HL,INTS_OFF_MSG ;'Turning off Interrupts'
CALL PRINT_STRING
XOR A
LD (@INTS_FLAG),A ;Flag Interrupts as OFF
DI ;Just in case
JP S100_TESTS ;done
TURN_ON_INTS:
LD HL,INTS_ON_MSG ;'Turning on Interrupts'
CALL PRINT_STRING
LD A,0FFH
LD (@INTS_FLAG),A ;Flag Interrupts as ON
EI ;Just in case
JP S100_TESTS ;done
;------------------------------ S COMMAND SUBSTITUTE AND / OR MODIFY MEMORY ----------------------
SUBS: LD C,1
CALL HEXSP
POP HL
SF2E3: LD A,(HL)
CALL ZHEXOUT
LD C,'-'
CALL ZCO
CALL PCHK
RET C
JR Z,SF2FC
CP ESC ;Abort if ESC
JP Z,ESC_ABORT
CP 5FH
JR Z,SF305
PUSH HL
CALL EXF
POP DE
POP HL
LD (HL),E
LD A,B
CP CR
RET Z
SF2FC: INC HL
SF2FD: LD A,L
AND 07H
CALL Z,LFADR
JR SF2E3
SF305: DEC HL
JR SF2FD
;-------------------------- F COMMAND FILL A BLOCK OF MEMORY WITH A VALUE ------------------------
FILL: CALL EXPR3
SF1A5: LD (HL),C
CALL HILOX
JR NC,SF1A5
POP DE
JP ZSTART
;---------------------------- G COMMAND GO TO A RAM LOCATION --------------------------------
GOTO: LD C,1 ;SIMPLE GOTO FIRST GET PARMS.
CALL HEXSP
CALL ZCRLF
POP HL ;GET PARAMETER PUSHED BY EXF
JP (HL)
;-------------------------- Q COMMAND GET OR OUTPUT TO A PORT ---------------------------------
QUERY: CALL PCHK
CP 'O' ;OUTPUT TO PORT
JR Z,OUT_PORT
CP 'I' ;INPUT FROM PORT
JP Z,IN_PORT
LD C,'*'
JP ZCO ;WILL ABORT IF NOT 'I' OR 'O'
IN_PORT:
LD C,1 ;IN Port
CALL HEXSP
POP BC
IN A,(C)
CALL ZSPACE
JP ZBITS
;
OUT_PORT:
CALL HEXSP ;OUT Port
POP DE
POP BC
OUT (C),E
RET
;-------------------------- U COMMAND HALT the Z180 CPU ---------------------------------
HALT_CPU:
LD HL,HALT_MSG
CALL PRINT_STRING ;Print message up to '$'
HALT
;-------------------------- W COMMAND Switch control of S100 Bus to slave CPU (eg 8086) ---------------------------------
SWITCH_8086: ; "W" INPUT Port ED (switched in 8086/80286)
;Note currently the S100 slave switch ports overlaps with the Z180 internal ports
LD HL,SLAVE_MSG ;Send before we switch internal ports
CALL PRINT_STRING
ld a,00H ;Move back to the defauly Z180 base register port (00H)
out0 (0FFH),a ;icr is currently at FFH
IN0 A,(SW_TMA0) ;THIS SWITCHES CPU'S with no block Move
NOP ;Z80 WILL BE HELD HERE
NOP
LD A,01 ;Utilize the more specific circuit on the V2-SMB
OUT0 (SW_TMAX),A ;Make sure its bit 0
NOP
NOP
NOP
JP BEGIN0 ;If we get back control
;------THIS IS THE MAIN ROUTINE TO GET THE TIME DATA FROM THE CMOS-RTC Chip on the MSDOS Support Board
SHOW_TIME:
LD HL,TIME_MSG
CALL PRINT_STRING ;Print message up to '$'
CALL READ_TIME
RET
SHOW_DATE:
LD HL,DATE_MSG
CALL PRINT_STRING ;Print message up to '$'
CALL READ_DATE
RET
;-------------------------------------------------------------------------------------
READ_TIME:
CALL UPD_IN_PR ;CHECK FOR UPDATE IN PROCESS
JP NC,RTC_2A ;GO AROUND IF OK
JP ERROR ;IF ERROR
RTC_2A: LD E,-2 ;-2 goes to 0 for PORT_INC_2
CALL PORT_INC_2 ;SET ADDRESS OF SECONDS
IN0 A,(CMOS_PORT+1) ;Get BCD value returned
LD D,A ;SAVE IN D
CALL PORT_INC_2 ;SET ADDRESS OF MINUTES
IN0 A,(CMOS_PORT+1) ;Get BCD value returned
LD C,A ;SAVE IN C
CALL PORT_INC_2 ;SET ADDRESS OF HOURS
IN0 A,(CMOS_PORT+1) ;Get BCD value returned
LD B,A ;SAVE
LD E,0 ;SET E TO ZERO
CALL DisplayTime ;<<<<<<<<<<<<<<
CALL ZCRLF
CALL ACTIVATE_CLOCK
RET
;Display time
; Arrive with B = HOURS IN BCD
; C = Minutes in BCD
; D = Seconds in BCD
DisplayTime:
PUSH HL
PUSH DE
PUSH BC
LD A,B
CALL PRINT_BCD ;Hours. Convert BCD to ASCII
LD C,':'
CALL ZCO
POP BC
LD A,C
CALL PRINT_BCD ;Minutes. Convert BCD to ASCII
LD C,':'
CALL ZCO
POP DE
LD A,D
CALL PRINT_BCD ;Seconds. Convert BCD to ASCII
POP HL
RET
;-------------------------------------------------------------------------------------------
READ_DATE:
CALL UPD_IN_PR
JP NC,RTC_4A
JP ERROR ;ON ERROR
RTC_4A: LD E,6
CALL PORT_INC ;POINT TO DAY
IN0 A,(CMOS_PORT+1)
LD B,A ;SAVE IN A
CALL PORT_INC ;POINT TO MONTH
IN0 A,(CMOS_PORT+1)
LD D,A ;SAVE IN D
CALL PORT_INC ;POINT TO YEAR
IN0 A,(CMOS_PORT+1)
LD C,A ;SAVE IN C
LD E,31H ;POINT TO CENTURY BYTE SAVE AREA
CALL PORT_INC ;
IN0 A,(CMOS_PORT+1) ;GET VALUE
LD E,B ;GET DAY BACK
LD B,A
CALL DisplayDate
CALL ZCRLF
CALL ACTIVATE_CLOCK
RET ;FINISHED
;Display date
; Return B = CENTURY IN BCD
; C = Year in BCD
; D = Month in BCD
; E = Day in BCD
DisplayDate:
PUSH HL
PUSH DE
PUSH DE
PUSH BC
LD A,20H ;<--20
CALL PRINT_BCD ;Century (19/20). Convert BCD to ASCII
POP BC
LD A,C
CALL PRINT_BCD ;Year. Convert BCD to ASCII
LD C,'/'
CALL ZCO
POP DE
LD A,D
CALL PRINT_BCD ;Month. Convert BCD to ASCII
LD C,'/'
CALL ZCO
POP DE
LD A,E
CALL PRINT_BCD ;Day. Convert BCD to ASCII
POP HL
CALL ACTIVATE_CLOCK
RET
ACTIVATE_CLOCK:
LD A,0AH
OUT0 (CMOS_PORT),A
LD A,0AAH
OUT0 (CMOS_PORT+1),A
RET
PRINT_BCD: ;Print BCD in [A]
PUSH AF
PUSH AF
RRA
RRA
RRA
RRA
AND A,0FH
ADD A,30H
LD C,A ;Write high byte mins to CRT
CALL ZCO
POP AF
AND A,0FH
ADD A,30H
LD C,A
CALL ZCO
POP AF
RET
UPD_IN_PR: ;Check we are ready to read clock
PUSH BC
LD BC,8000 ;SET LOOP COUNT
UPDATE: LD A,0AH ;ADDRESS OF [A] REGISTER
OUT0 (CMOS_PORT),A
NOP
NOP
NOP
IN0 A,(CMOS_PORT+1) ;READ IN REGISTER [A]
AND A,80H ;IF 8XH--> UIP BIT IS ON (CANNOT READ TIME)
JP Z,UPD_IN_PREND ;Are we ready/done
DEC BC
LD A,C
OR A,B
JP NZ,UPDATE ;Try again
XOR A,A ;
SCF ;SET CARRY FOR ERROR
POP BC
RET
UPD_IN_PREND:
XOR A,A ;Clear Carry
POP BC
RET ;RETURN
PORT_INC:
LD A,E
INC A ;INCREMENT ADDRESS
LD E,A
OUT0 (CMOS_PORT),A
RET
PORT_INC_2:
LD A,E
ADD 2 ;INCREMENT ADDRESS
LD E,A
OUT0 (CMOS_PORT),A
RET
;--------------------- J COMMAND MEMORY TEST ---------------------------------
MEM_TEST:
LD HL,MEM_TEST_MSG ;Memory test
CALL PRINT_STRING
LD HL,0DF00H
LD E,00H
LD D,01H
LD B,0H ;256 loops
MEM_LOOP:
LD (HL),00H ;Fill RAM with 0's
DEC HL
LD A,L
OR A,H
JR NZ,MEM_LOOP
LD HL,0DF00H ;Next check and change to 1's....
LD E,00H
LD D,01H
MEM_LOOP1:
PUSH AF
PUSH BC
CALL ZPRINT_HL
LD A,E
CALL ZHEXOUT ;Print address and value + CR
CALL ZSPACE
LD C,CR
CALl ZCO
POP BC
POP AF
LD A,(HL)
CP A,E
CALL NZ,RAM_ERROR
LD (HL),D
DEC HL
LD A,L
OR A,H
JR NZ,MEM_LOOP1
CALL ZCRLF
LD HL,0DF00H
INC E
INC D
DEC B ;Do 256 tests
JR NZ,MEM_LOOP1
JP BEGIN
RAM_ERROR:
PUSH HL
LD HL,MEM_ERR_MSG ;Memory error
CALL PRINT_STRING
POP HL
CALL ZPRINT_HL
CALL ZCRLF
RET
;---------------------- M COMMAND MOVE A BLOCK OF MEMORY TO ANOTHER LOCATION -------------------
MOVE: CALL EXPR3
SF21E: LD A,(HL)
LD (BC),A
INC BC
CALL HILOX
JR SF21E
;----------------------V COMMAND VERIFY ONE BLOCK OF MEMORY WITH ANOTHER ----------------------
VERIFY: CALL EXPR3
VERIO: LD A,(BC)
CP (HL)
JR Z,SF78E
PUSH BC
CALL CERR
POP BC
SF78E: INC BC
CALL HILOX
JR VERIO
RET
;
CERR: LD B,A
CALL ZPRINT_HL
LD A,(HL)
CALL ZHEXOUT
CALL BLANK
LD A,B
CALL ZHEXOUT
JP ZCRLF
;-------------------- E COMMAND CHECK ECHO CHAR IN TO CHAR OUT --------------------------------
CHAR_TEST:
LD HL,CHAR_TEST_MSG ;Keyboard test
CALL PRINT_STRING
CHAR_TEST1:
CALL ZCI ;Routeen to check keyboard etc.
CP ESC ;Loop until ^C or ESC
RET Z
CP 'Z'-40H
RET Z
LD C,A
CALL ZCO
JR CHAR_TEST
;----------------- T COMMAND READ ASCII FROM MEMORY --------------------------------------
TYPE: CALL EXLF
SF30B: CALL LFADR
LD B,56
SF310: LD A,(HL)
AND 7FH
CP SPACE
JR NC,SF319
SF317: LD A,2EH
SF319: CP 7CH
JR NC,SF317
LD C,A
CALL ZCO
CALL HILOX
DJNZ SF310
JR SF30B
;---------------------- R COMMAND Display all active IO inputports in the system ----------------------
;
INPORTS:CALL ZCRLF
LD B,0 ;Now loop through all ports (0-FF)
LD D,6 ;Display 6 ports across
LD E,0FFH ;Will contain port number
LOOPIO: LD C,E
LD A,E
CP A,SW_TMA0 ;Inputting here will switch out the Z80 to 8086/80286
JR Z,SKIP ;Skip because we don't want that right now
CP SOUT_PORT
JR Z,SKIP
;
IN A,(C) ;Remember [ZASMB does not work with this opcode,SLR is OK]
CP A,0FFH ;No need for 0FF's
JR Z,SKIP
LD H,A ;store port data in H for below
LD A,E ;Need to print port # first
CALL ZHEXOUT ;Print port number
LD C,'-'
CALL ZCO
LD C,'>'
CALL ZCO
LD A,H ;get back port data
CALL ZHEXOUT ;print it
LD C,TAB
CALL ZCO
DEC D ;6 ports per line
JR NZ,SKIP
LD D,6
CALL ZCRLF
SKIP: DEC E ;Next Port
DJNZ LOOPIO
CALL ZCRLF
RET
;----------------- K COMMAND PRINT MAIN MONITOR MENU ON CRT ---------------------------
KCMD: LD HL,SIGNON_MSG ;Signon Msg again (K Command)
CALL PRINT_STRING
LD HL,SMSG_SP ;Signon speech message
CALL SPEAK$
LD HL,MENUMSG ;Then Menu Message
JP PRINT_STRING
;---------------------- X COMMAND XMODEM ---------------------------------------------------
;This routine will download any XMODEM formatted data from a file on a PC over teh USB port.
;If the USB port is NOT also also used console I/O progress of the download will appear on the screen.
;If the USB port is ALSO used for console I/O no progress is shown until the download is complete.
XMODEM:
LD HL,MODEM_SIGNON ;Send Modem signon message
CALL PRINT_STRING
LD HL,0 ;SP to HL
ADD HL,SP
LD DE,40H ;Drop 40H bytes below to be safe
SBC HL,DE
PUSH HL
POP IX ;Will store data below in RAM 40H bytes below SP to be safe
XOR A,A ;Initilize flags
LD (IX+RECVD_SECT_NO),A
LD (IX+SECTNO),A
LD (IX+ERRCT),A
LD HL,MODEM_RAM_LOC ;Get RAM location for where to place code
CALL PRINT_STRING
LD C,1
CALL HEXSP ;Get 16 bit value, put on stack
POP IY ;DMA Value now in IY
CALL ZCRLF
CALL INIT_SCC_A ;INITITIALIZE THE SCC SERIAL PORT A Just in case it changed
LD B,1 ;TIMEOUT DELAY
CALL MODEM_ZCI ;GOBBLE UP GARBAGE CHARS FROM THE LINE
RECV_LOOP: ;<------- MAIN RECIEVE LOOP
XOR A,A ;GET 0
LD (IX+ERRCT),A ;INITIAL ERROR COUNT SET TO 0
RECV_HDR:
LD HL,RMSG
CALL PRINT_STRING ;Skip print if USB port is also console
LD A,(IX+SECTNO) ;Get current sector number
INC A
CALL LBYTE ;Show Sector Number on Console if USB port is NOT also console
LD HL,MODEM_RAM_MSG ;"H. IF OK, will write to RAM location"
CALL P_STRING
PUSH IY
POP HL ;IY to HL
CALL LADR ;Show DMA Address if USB port is NOT also console
CALL ZCRLF
LD B,5 ;5 SEC TIMEOUT
CALL MODEM_ZCI
JP NC,RHNTO ;IF ALL OK (NO TIMEOUT), THEN DROP DOWN TO RHNTO TO GET DATA
RECV_HDR_TIMEOUT:
CALL TOUT ;PRINT TIMEOUT
RECV_SECT_ERR: ;PURGE THE LINE OF INPUT CHARS
LD B,1 ;1 SEC W/NO CHARS
CALL MODEM_ZCI
JP NC,RECV_SECT_ERR ;LOOP UNTIL SENDER DONE
LD A,NAK
CALL MODEM_ZCO ;SEND NAK
LD A,(IX+ERRCT)
INC A
LD (IX+ERRCT),A
CP A,MODEM_ERR_LIMIT
JP C,RECV_HDR
CALL CHECK_FOR_QUIT
JP Z,RECV_HDR
LD HL,BAD_HEADER_MSG
CALL PRINT_STRING
JP BEGIN
RHNTO: CP A,SOH ;GOT CHAR - MUST BE SOH
JP Z,GOT_SOH ;Z IF OK
OR A,A ;00 FROM SPEED CHECK?
JP Z,RECV_HDR
CP A,EOT
JP Z,GOT_EOT
;DIDN'T GET SOH -
CALL LBYTE ;Print [A] on console
LD HL,ERRSOH
CALL PRINT_STRING
JP RECV_SECT_ERR
GOT_SOH:
LD B,1
CALL MODEM_ZCI
JP C,RECV_HDR_TIMEOUT
LD D,A ;D=BLK #
LD B,1
CALL MODEM_ZCI ;GET CMA'D SECT #
JP C,RECV_HDR_TIMEOUT
CPL
CP A,D ;GOOD SECTOR #?
JP Z,RECV_SECTOR
LD HL,ERR2 ;GOT BAD SECTOR #
CALL PRINT_STRING
JP RECV_SECT_ERR
RECV_SECTOR: ;Sector is OK, so read data and place in RAM
LD A,D ;GET SECTOR #
LD (IX+RECVD_SECT_NO),A
LD C,0 ;INIT CKSUM
LD E,80H ;Sector Byte Count
PUSH IY
POP HL ;DMA address (IY) to HL
RECV_CHAR:
LD B,1 ;1 SEC TIMEOUT
CALL MODEM_ZCI ;GET CHAR
JP C,RECV_HDR_TIMEOUT
LD (HL),A ;STORE CHAR
INC HL
DEC E ;Next sector byte
JP NZ,RECV_CHAR
;VERIFY CHECKSUM
LD D,C ;SAVE CHECKSUM
LD B,1 ;TIMEOUT
CALL MODEM_ZCI ;GET CHECKSUM
JP C,RECV_HDR_TIMEOUT
CP A,D ;CHECK
JP NZ,RECV_CKSUM_ERR
;GOT A SECTOR, WRITE IF = 1+PREV SECTOR
LD A,(IX+RECVD_SECT_NO)
LD B,A ;SAVE IT
LD A,(IX+SECTNO) ;GET PREV
INC A ;CALC NEXT SECTOR #
CP B ;MATCH?
JP NZ,DO_ACK
LD (IX+SECTNO),A ;UPDATE SECTOR #
DO_ACK: LD A,ACK
CALL MODEM_ZCO
PUSH HL ;ALL OK SO SAVE DMA Address in IY
POP IY
JP RECV_LOOP ;Back to Top recieve loop
RECV_CKSUM_ERR:
LD HL,ERR3
CALL PRINT_STRING
JP RECV_SECT_ERR
GOT_EOT:
LD A,ACK ;ACK THE EOT
CALL MODEM_ZCO
JP XFER_CPLT
TOUT: LD HL,TOUTM ;PRINT TIMEOUT MESSAGE
CALL PRINT_STRING
LD A,(IX+ERRCT)
CALL LBYTE
CALL ZCRLF
RET
CHECK_FOR_QUIT: ;MULTIPLE ERRORS, ASK IF TIME TO QUIT
XOR A,A ;GET 0
LD (IX+ERRCT),A ;RESET ERROR COUNT
LD HL,QUITM
CALL PRINT_STRING
CI3: IN0 A,(CONSOLE_STATUS) ;NEED CONSTAT TO CLEAN UP SHIFT KEYS ETC
AND A,02H
JP Z,CI3
IN0 A,(CONSOLE_IN)
AND A,7FH
PUSH AF ;SAVE CHAR
CALL ZCRLF
POP AF
CP A,'R'
RET Z ;RETURN IF RETRY
CP A,'r'
RET Z
CP A,'Q' ;QUIT?
JP NZ,LCQ
OR A,A ;TURN OFF ZERO FLAG
RET
LCQ: CP A,'q'
JP NZ,CHECK_FOR_QUIT
OR A,A ;TURN OFF ZERO FLAG
RET
XFER_CPLT: ;DONE - CLOSE UP SHOP
LD HL,MODEM_DONE_MSG
CALL PRINT_STRING
JP ZSTART
;-------------- P COMMAND BOOT UP CPM FROM HARD DISK ON S100COMPUTERS IDE BOARD ----------------
;BOOT UP THE 8255/IDE Board HARD DISK/Flash Memory Card
ZBOOT: ;Allow CTL Z to always boot CPM
HBOOTCPM:
IN0 A,(IOBYTE) ;Charcter in A
BIT 0,A
JP NZ,S100_ONLY
POP HL ;CLEAN UP STACK
LD HL,SPEAKCPM_SP ;Announce Booting CPM on speaker 'Loading CPN'
CALL SPEAK$
CALL IDEInit ;Initilze the 8255 and drive
RET C ;Abort if carry set
LD D,11100000B ;Data for IDE SDH reg (512bytes, LBA mode,single drive)
LD E,REGshd ;00001110,(0EH) CS0,A2,A1,
CALL IDEwr8D ;Write byte to select the MASTER device
LD B,0FFH ;Delay time to allow a Hard Disk to get up to speed
WaitInit:
LD E,REGstatus ;Get status after initilization
CALL IDErd8D ;Check Status (info in [D])
BIT 7,D
JR Z,SECREAD ;Zero, so all is OK to write to drive
;Delay to allow drive to get up to speed
PUSH BC
LD BC,0FFFFH
DXLAY2: LD D,2 ;May need to adjust delay time to allow cold drive to
DXLAY1: DEC D ;to speed
JR NZ,DXLAY1
DEC BC
LD A,C
OR B
JR NZ,DXLAY2
POP BC
DJNZ WaitInit ;If after 0FFH, 0FEH, 0FDH... 0, then drive initilization problem
IDError:
LD HL,DRIVE_NR_ERR ;Drive not ready
JP ABORT_ERR_MSG
SECREAD: ;Note CPMLDR will ALWAYS be on TRK 0,SEC 1,Head 0
CALL IDEwaitnotbusy ;Make sure drive is ready
JR C,IDError ;NC if ready
LD D,1 ;Load track 0,sec 1, head 0
LD E,REGsector ;Send info to drive
CALL IDEwr8D
LD D,0 ;Send Low TRK#
LD E,REGcylinderLSB
CALL IDEwr8D
LD D,0 ;Send High TRK#
LD E,REGcylinderMSB
CALL IDEwr8D
LD D,SEC_COUNT ;Count of CPM sectors we wish to read
LD E,REGseccnt
CALL IDEwr8D
LD D,COMMANDread ;Send read CMD
LD E,REGcommand
CALL IDEwr8D ;Send sec read CMD to drive.
CALL IDEwaitdrq ;Wait until it's got the data
LD HL,CPM_ADDRESS ;DMA address where the CPMLDR resides in RAM
LD B,0 ;256X2 bytes
LD C,SEC_COUNT ;Count of sectors X 512
BOOT_MoreRD16:
LD A,REGdata ;REG regsiter address
OUT (IDECport),A
OR IDErdline ;08H+40H, Pulse RD line
OUT (IDECport),A
IN A,(IDEAport) ;read the LOWER byte
LD (HL),A
INC HL
IN A,(IDEBport) ;read the UPPER byte
LD (HL),A
INC HL
LD A,REGdata ;Deassert RD line
OUT (IDECport),A
DJNZ BOOT_MoreRD16
DEC C
JR NZ,BOOT_MoreRD16
LD E,REGstatus ;Check the R/W status when done
CALL IDErd8D
BIT 0,D
JR NZ,IDEerr1 ;Z if no errors
LD HL,STARTCPM
LD A,(HL)
CP 31H ;EXPECT TO HAVE 31H @80H IE. LD SP,80H
JP Z,STARTCPM ;AS THE FIRST INSTRUCTION. IF OK JP to 100H in RAM
JP ERR_LD1 ;Boot Sector Data incorrect
IDEerr1:
LD HL,IDE_RW_ERROR ;Drive R/W Error
JP ABORT_ERR_MSG
ABORT_ERR_MSG:
CALL PRINT_STRING
RET ;BACK TO START OF MONITOR.
ERR_NR: LD HL,DRIVE_NR_ERR ;"DRIVE NOT READY
JP ABORT_ERR_MSG
ERR_LD: LD HL,BOOT_LD_ERR ;"ERROR READING BOOT/LOADER SECTORS"
JP ABORT_ERR_MSG
ERR_LD1:LD HL,BOOT_LD1_ERR ;"DATA ERROR IN BOOT SECTOR"
JP ABORT_ERR_MSG
;-----------------------Y IDE Menu ---------------------------------------------------
IDE_BOARD_MENU:
IN0 A,(IOBYTE) ;Charcter in A
BIT 0,A
JP NZ,S100_ONLY
LD HL,0100H ;Default DMA address
LD (@RAM_ADDRESS),HL
XOR A
LD (@SEC),A
LD (@TRK+1),A
LD (@TRK),A
CALL WRITE_DRIVE_LBA ;Update Drive
IDE_MENU1:
LD HL,1
LD (@SEC_COUNT),HL
IDE_MENU:
CALL PRINT_IDE_TRK_SEC ;Show current Track & Sector
LD HL,IDE_SD_MENU_MSG ;Menu
CALL PRINT_STRING
CALL PCHK
CP '0'
JP Z,INITILIZE_IDE ;Initilize drive
CP '1'
JP Z,SET_LBA ;Set track/Sector
CP '2'
JP Z,SET_IDE_DMA_ADDRESS ;Set Location in RAM to read/write sector data
CP '3'
JP Z,READ_IDE_SEC ;Read Current Sector
CP '4'
JP Z,WRITE_IDE_SEC ;Write to Current Sector
CP '5'
JP Z,READ_N_IDE_SEC
CP '6'
JP Z,WRITE_N_IDE_SEC
CP '7'
JP Z,GOTO_NEXT_IDE
CP '+'
JP Z,GOTO_NEXT_IDE
CP ESC
JP Z,MENU_DONE
JP IDE_MENU1
S100_ONLY:
LD HL,S100_ONLY_MSG
CALL PRINT_STRING
JP MENU_DONE
;------------------------------------------------------
INITILIZE_IDE:
CALL IDEInit
JP C,IDE_MENU
LD HL,INIT_OK
CALL PRINT_STRING
JP IDE_MENU
IDEinit: ;Initilze the 8255 and drive then do a hard reset on the drive,
LD A,RDcfg8255 ;Config 8255 chip (10010010B), read mode on return
OUT0 (IDECtrl),A ;Config 8255 chip, READ mode
;Hard reset the disk drive
;For some reason some CF cards need to the RESET line
;pulsed very carefully. You may need to play around
LD A,IDEreset ;with the pulse length. Symptoms are: incorrect data comming
OUT0 (IDECport),A ;back from a sector read (often due to the wrong sector being read)
;I have a (negative)pulse of 60 uSec. (10Mz Z80, two IO wait states).
LD C,IDE_Reset_Delay ;~60 uS seems to work for the 5 different CF cards I have
ResetDelay:
DEC C
JP NZ,ResetDelay ;Delay (reset pulse width)
XOR A
OUT0 (IDECport),A ;No IDE control lines asserted (just bit 7 of port C)
CALL DELAY_15 ;Need to delay a little before checking busy status
IDEwaitnotbusy: ;Drive READY if 01000000
LD B,0FFH
LD C,080H ;Delay, must be above 80H for 4MHz Z80. Leave longer for slower drives
MoreWait:
LD E,REGstatus ;Wait for RDY bit to be set
CALL IDErd8D
LD A,D
AND 11000000B
XOR 01000000B
JR Z,DoneNotbusy
DJNZ MoreWait
DEC C
JR NZ,MoreWait
LD HL,INIT_ERR
CALL PRINT_STRING
SCF ;Set carry to indicate an error
RET
DoneNotBusy:
LD A,1
OR A ;Clear carry it indicate no error
RET
DELAY_15:
LD A,40 ;DELAY ~15 MS
DELAY1: LD B,0
M0: DJNZ M0
DEC A
JR NZ,DELAY1
RET
PRINT_IDE_TRK_SEC:
LD HL,IDE_MENU0_MSG ;'S100 Bus IDE Board Menu Track= '
CALL PRINT_STRING
LD HL,(@TRK) ;Track number'
CALL HL_ONLY
LD HL,IDE_MENU1_MSG ;H Sector=
CALL P_STRING
LD A,(@SEC)
CALL ZHEXOUT
SD_PRINT_2: ;Also used by SD CARD Menu
LD HL,IDE_MENU3_MSG ;H RAM Address=
CALL P_STRING
LD HL,(@RAM_ADDRESS)
CALL HL_ONLY
LD HL,H_MSG ;H.
CALL P_STRING
RET
;-----------------------------------------
SET_LBA: ;Set the logical block address
LD HL,GET_LBA_MSG
CALL PRINT_STRING
CALL GET_DRIVE_LBA ;Get new CPM style Track & Sector number and put them in RAM at @SEC & @TRK
JR C,main3b ;Ret C set if abort/error
CALL WRITE_DRIVE_LBA ;Update LBA on drive
main3b: CALL ZCRLF
JP IDE_MENU
;-----------------------------------------
SET_IDE_DMA_ADDRESS
LD HL,GET_DMA_MSG
CALL PRINT_STRING
CALL ZGET_HL ;Not clear why this returns incorrect values
JP C,IDE_MENU
LD (@RAM_ADDRESS),HL
JP IDE_MENU
;-------------------------------------------
GOTO_NEXT_IDE:
CALL BUMP_IDE_SECTOR ;Advance one sector
JP IDE_MENU
;-------------------------------------------
READ_N_IDE_SEC:
LD HL,ENTER_SEC_COUNT
CALL PRINT_STRING
CALL GETHEX ;get 2 HEX digits
LD HL,0
LD L,A
LD (@SEC_COUNT),HL
MORE_RD_SEC:
CALL READSECTOR
JR Z,main1b_N ;Z means the sector read was OK
CALL ZCRLF
JP IDE_MENU ;Was an error, don't display data
main1b_N:
CALL PRINT_IDE_TRK_SEC
LD HL,msgrd ;Sector read OK
CALL PRINT_STRING
LD HL,(@SEC_COUNT)
DEC HL
LD (@SEC_COUNT),HL
LD A,L
OR A
JP Z,IDE_MENU1
CALL BUMP_IDE_SECTOR ;Bump TRK, SEC, DMA
JR MORE_RD_SEC
;-------------------------------------------
READ_IDE_SEC: ;Read Sector @ LBA to the RAM buffer
LD HL,READING_MSG ;Sector read to @RAM_ADDRESS
CALL PRINT_STRING
CALL READSECTOR
JR Z,main1b ;Z means the sector read was OK
CALL ZCRLF
JP IDE_MENU ;Was an error, don't display data
main1b: LD HL,msgrd ;Sector read OK
CALL PRINT_STRING
LD HL,(@RAM_ADDRESS)
CALL HEXDUMP ;Show sector data at @RAM_ADDRESS
LD HL,CONTINUE_MSG ;Print any character to continue
CALL PRINT_STRING
CALL ZCI
CP A,ESC
JP Z,BEGIN
JP IDE_MENU
;Read a sector, specified by the 3 bytes in LBA
;Z on success, NZ call error routine if problem
READSECTOR:
CALL WRITE_DRIVE_LBA
CALL IDEwaitnotbusy ;make sure drive is ready
JP C,SHOWerrors ;Returned with NZ set if error
LD D,COMMANDread
LD E,REGcommand
CALL IDEwr8D ;Send sec read command to drive.
CALL IDEwaitdrq ;wait until it's got the data
JP C,SHOWerrors
LD HL,(@RAM_ADDRESS) ;DMA address
LD B,0 ;Read 512 bytes to [HL] (256X2 bytes)
MoreRD16:
LD A,REGdata ;REG regsiter address
OUT0 (IDECport),A
OR A,IDErdline ;08H+40H, Pulse RD line
OUT0 (IDECport),A
IN0 A,(IDEAport) ;Read the lower byte first (Note very early versions had high byte then low byte
LD (HL),A ;this made sector data incompatable with other controllers).
INC HL
IN0 A,(IDEBport) ;THEN read the upper byte
LD (HL),A
INC HL
LD A,REGdata ;Deassert RD line
OUT0 (IDECport),A
DJNZ MoreRD16
LD (@NEXT_ADDRESS),HL ;For multi sec read
LD E,REGstatus
CALL IDErd8D
LD A,D
AND A,1H
CALL NZ,SHOWerrors ;If error display status
RET
SHOWerrors:
LD HL,DRIVE_ERRORS
CALL PRINT_STRING
LD A,D
CALL ZBITS
CALL ZCRLF
OR A ;Set NZ flag
SCF ;Set Carry Flag
RET
BUMP_IDE_SECTOR: ;For multi sec read/writes
LD HL,(@NEXT_ADDRESS)
LD (@RAM_ADDRESS),HL ;DMA address
ld hl,(@SEC)
inc hl
ld (@SEC),hl
ld a,L ;0 to 62 CPM Sectors
cp MAXSEC-1
RET nz
ld hl,0 ;Back to CPM sector 0
ld (@SEC),hl
ld hl,(@TRK) ;Bump to next track
inc hl
ld (@TRK),hl
RET
;-------------------------------------------
WRITE_N_IDE_SEC:
LD HL,ENTER_SEC_COUNT
CALL PRINT_STRING
CALL GETHEX ;get 2 HEX digits
LD HL,0
LD L,A
LD (@SEC_COUNT),HL
MORE_WR_SEC:
CALL WRITESECTOR
JR Z,main3b_N ;Z means the sector read was OK
CALL ZCRLF
JP IDE_MENU ;Was an error, don't display data
main3b_N:
CALL PRINT_IDE_TRK_SEC
LD HL,msgwr ;Sector write OK
CALL PRINT_STRING
LD HL,(@SEC_COUNT)
DEC HL
LD (@SEC_COUNT),HL
LD A,L
OR A
JP Z,IDE_MENU1
CALL BUMP_IDE_SECTOR ;Bump TRK, SEC, DMA
JR MORE_WR_SEC
;-------------------------------------------
WRITE_IDE_SEC:
ld HL,Write_Sure ;Are you sure?
call PRINT_STRING
call ZCI
call TO_UPPER
LD C,A ;Print response
CALL ZCO
CP 'Y'
PUSH AF
CALL ZCRLF
POP AF
jp nz,IDE_MENU
CALL ZCRLF
call WRITESECTOR
jr z,main2b ;Z means the sector write was OK
call ZCRLF
jp IDE_MENU
main2b: ld HL,msgwr ;Sector written OK
call PRINT_STRING
CALL ZCRLF
JP IDE_MENU
;Write a sector, specified by the 3 bytes in LBA
;Z on success, NZ to error routine if problem
WRITESECTOR:
CALL WRITE_DRIVE_LBA
call IDEwaitnotbusy ;Make sure drive is ready
jp c,SHOWerrors
ld d,COMMANDwrite
ld e,REGcommand
call IDEwr8D ;tell drive to write a sector
call IDEwaitdrq ;wait unit it wants the data
jp c,SHOWerrors
ld hl,(@RAM_ADDRESS)
ld b,0 ;256X2 bytes
ld a,WRcfg8255
out0 (IDECtrl),a
MoreWR16:
ld a,(hl)
inc hl
out0 (IDEAport),a ;Write the lower byte first (Note early versions had high byte then low byte
ld a,(hl) ;this made sector data incompatible with other controllers).
inc hl
out0 (IDEBport),a ;THEN High byte on B
ld a,REGdata
push af
out0 (IDECport),a ;Send write command
or IDEwrline ;Send WR pulse
out0 (IDECport),a
pop af
out0 (IDECport),a
DJNZ MoreWR16
ld a,RDcfg8255 ;Set 8255 back to read mode
out0 (IDECtrl),a
LD (@NEXT_ADDRESS),HL ;For multi sec read
ld e,REGstatus
call IDErd8D
ld a,D
and A,1H
call nz,SHOWerrors ;If error display status
RET
GET_DRIVE_LBA: ;Get CPM style Track# & Sector# data and convert to LBA format
LD HL,ENTER_SECL ;Enter sector number
CALL PRINT_STRING
CALL GETHEX ;get 2 HEX digits
RET C
LD (@SEC),A ;Note: no check data is < MAXSEC, sectors start 0,1,2,3....
LD HL,ENTER_TRKH ;Enter high byte track number
CALL PRINT_STRING
CALL GETHEX ;get 2 HEX digits
RET C
LD (@TRK+1),A
LD HL,ENTER_TRKL ;Enter low byte track number
CALL PRINT_STRING
CALL GETHEX ;get 2 more HEX digits
RET C
LD (@TRK),A
CALL ZCRLF
XOR A
OR A ;To return NC
RET
WRITE_DRIVE_LBA: ;Write the logical block address to the drive's registers
;Note we do not need to set the upper nibble of the LBA
;It will always be 0 for these small drives
LD A,(@SEC) ;LBA mode Low sectors go directly
INC A ;Sectors are numbered 1 -- MAXSEC (even in LBA mode)
LD (@DRIVE$SEC),A ;<<<<< For Diagnostic Display Only
LD D,A
LD E,REGsector ;Send info to drive
CALL IDEwr8D ;Note: For drive we will have 0 - MAXSEC sectors only
LD HL,(@TRK)
LD A,L
LD (@DRIVE$TRK),A
LD D,L ;Send Low TRK#
LD E,REGcylinderLSB
CALL IDEwr8D
LD A,H
LD (@DRIVE$TRK+1),A
LD D,H ;Send High TRK#
LD E,REGcylinderMSB
CALL IDEwr8D
LD D,1 ;For now, one sector at a time
LD E,REGseccnt
CALL IDEwr8D
RET
IDEwaitdrq: ;Wait for the drive to be ready to transfer data.
LD B,0FFH
LD A,0FFH ;Delay, must be above 80H for 4MHz Z80. Leave longer for slower drives
LD (@DELAYStore),A
MoreDRQ:
LD E,REGstatus ;wait for DRQ bit to be set
CALL IDErd8D
LD A,D
AND A,10001000B
CP A,00001000B
JR Z,DoneDRQ
DEC B
JR NZ,MoreDRQ
LD A,(@DELAYStore) ;Check timeout delay
DEC A
LD (@DELAYStore),A
JR NZ,MoreDRQ
SCF ;Set carry to indicate error
RET
DoneDRQ:
OR A ;Clear carry
RET
HEXDUMP: ;Print a hexdump of the data in the 512 byte buffer @[HL]
PUSH AF ;Save everything
PUSH BC
PUSH DE
PUSH HL
NEXT_SECTOR:
CALL ZCRLF ;CR/LF first
LD D,32 ;Print 32 lines total
LD B,16 ;16 characters across
LD (@StartLineHex),HL ;Save the buffer location (@RAM_ADDRESS++) for ASCII display below
LD HL,0
LD (@BYTE$COUNT),HL
SF172X: CALL ZCRLF
LD HL,(@BYTE$COUNT)
LD A,H
CALL ZHEXOUT ;Print byte count in sector
LD A,L
CALL ZHEXOUT
PUSH DE
LD DE,16
ADD HL,DE
LD (@BYTE$COUNT),HL ;store for next time
POP DE
CALL ZSPACE
LD HL,(@StartLineHex)
LD (@StartLineASCII),HL ;Store for ASCII display below
SF175X: LD A,(HL)
CALL LBYTE ;Display [A] on CRT/LCD
INC HL
DJNZ SF175X
;
LD (@StartLineHex),HL ;Save for next line later
CALL ShowAscii ;Now translate to ASCII and display
LD B,16 ;16 characters across for next line
DEC D
JP NZ,SF172X ;Have we done all 32 lines
;
CALL ZCRLF
POP HL ;Get back origional registers
POP DE
POP BC
POP AF
RET
ShowAscii: ;Now show as ascii info
LD HL,(@StartLineASCII)
LD B,16 ;16 ASCII characters across
XF172: CALL ZSPACE ;send a space character
CALL ZSPACE
XF175: LD A,(HL)
AND A,7FH
CP A,' ' ;FILTER OUT CONTROL CHARACTERS
JR NC,XT33
XT22: LD A,'.'
XT33: CP A,07CH
JR NC,XT22
LD C,A ;SET UP TO SEND
PUSH BC
CALL ZCO
POP BC
INC HL ;Next position in buffer
DJNZ XF175
RET
;
;------------------------------------------------------------------
; Low Level 8 bit R/W to the drive controller. These are the routines that talk
; directly to the drive controller registers, via the 8255 chip.
; Note the 16 bit I/O to the drive (which is only for SEC R/W) is done directly
; in the routines READSECTOR & WRITESECTOR for speed reasons.
;
IDErd8D: ;READ 8 bits from IDE register in [E], return info in [D]
LD A,E
OUT0 (IDECport),A ;drive address onto control lines
OR A,IDErdline ;RD pulse pin (40H)
OUT0 (IDECport),A ;assert read pin
IN0 A,(IDEAport)
LD D,A ;return with data in [D]
LD A,E ;<---Ken Robbins suggestion
OUT0 (IDECport),A ;Deassert RD pin
XOR A
OUT0 (IDECport),A ;Zero all port C lines
RET
IDEwr8D: ;WRITE Data in [D] to IDE register in [E]
LD A,WRcfg8255 ;Set 8255 to write mode
OUT0 (IDECtrl),A
LD A,D ;Get data put it in 8255 A port
OUT0 (IDEAport),A
LD A,E ;select IDE register
OUT0 (IDECport),A
OR IDEwrline ;lower WR line
OUT0 (IDECport),A
LD A,E ;<-- Kens Robbins suggestion, raise WR line
OUT0 (IDECport),A
XOR A ;Deselect all lines including WR line
OUT0 (IDECport),A
LD A,RDcfg8255 ;Config 8255 chip, read mode on return
OUT0 (IDECtrl),A
RET
;-----------------------W Command SD CARD Menu ---------------------------------------------------
SD_CARD_MENU:
LD HL,0100H ;Default DMA address
LD (@RAM_ADDRESS),HL
LD HL,0
LD (@SEC),HL ;low byte,high byte
LD (@TRK),HL
XOR A
LD (@CARD_TYPE),A ; Unknown Card Type so far
SD_MENU1:
LD HL,1
LD (@SEC_COUNT),HL
SD_MENU:
CALL PRINT_SD_SEC ;Show current Sector
LD HL,IDE_SD_MENU_MSG ;Menu
CALL PRINT_STRING
CALL PCHK
CP A,'0'
JP Z,INITILIZE_SD_CARD
CP A,'1'
JP Z,SET_SD_SECTOR
CP A,'2'
JP Z,SET_SD_DMA_ADDRESS ;Set Location in RAM to read/write sector data
CP A,'3'
JP Z,READ_SD_SEC ;Read to Current SD Sector
CP A,'4'
JP Z,WRITE_SD_SEC ;Write to Current SD Sector
CP '5'
JP Z,READ_N_SD_SEC ;Read N SD Sectors
CP '6'
JP Z,WRITE_N_SD_SEC ;Write N SD Sectors
CP '7'
JP Z,GOTO_NEXT_SEC
CP '+'
JP Z,GOTO_NEXT_SEC
CP '8'
JP Z,GOTO_PREVIOUS_SEC
CP '-'
JP Z,GOTO_PREVIOUS_SEC
CP ESC
JP Z,MENU_DONE
JP SD_MENU1
;========================================== INITILIZE SD CARD =====================================================
INITILIZE_SD_CARD:
LD A,0
LD (@CARD_TYPE),A ; Unknown Card Type so far
LD A,06H ; Wayne Warthen's recomended slow value at the start
OUT0 (z180_cntr),A
CALL SEND_SD_RESET ; Repeatidly send the RESET CMD0 to the adaptor (Up to 256 times)
JP NZ,BAD_SD_RESET
LD HL,INIT_OK ; Drive Init. OK
CALL PRINT_STRING
CALL SEND_GET_TYPE ; Will put card type in (CARD_TYPE)
CALL SEND_GET_TYPE ; Initilize a Type 2 Card, Get Card Type CMD8. Required for SDHC cards
LD HL,CF_TYPE_ERR_MSG ; 'Sorry, SD Card Type 2 was NOT detected. (Status =
CALL NZ,CMD_FAIL
JP NZ,SD_MENU1
LD HL,CARD_TYPE2_MSG ; "SD Card Type 2 detected."
CALL PRINT_STRING
CALL TYPE_2_ACTIVATE ; Type 2 needs special activation
LD HL,CMD55_FAIL_MSG ; SD Card Type 2 Initilization failed (CMD55 or CMD41).
CALL NZ,CMD_FAIL
JP NZ,SD_MENU1
LD HL,CMD41_55_OK_MSG ; 'CMD41 & CMD55 accepted OK. SD Card is now initilized.'
CALL PRINT_STRING
CALL STOP_CRC_CHECK ; Turn off CRC Checking
LD HL,CRC_ERROR_MSG ; "Got error trying to turn off CRC checking."
CALL NZ,CMD_FAIL
JP NZ,SD_MENU1
CALL SET_SEC_SIZE ; <<<<<<<<<<< Set Sector size to 512 bytes
LD HL,SIZE_ERROR_MSG ; "Got error trying set sector size to 512 bytes. (Status = "
CALL NZ,CMD_FAIL
LD A,00H ; Set to high speed SPI clock
OUT0 (z180_cntr),A
JP SD_MENU1
BAD_SD_RESET:
LD HL,INIT_ERR ; 'Drive Init. Error
CALL CMD_FAIL ; Print Error
JP SD_MENU1
;========================================== SET SECTOR =====================================================
SET_SD_SECTOR:
LD HL,ENTER_SEC_NUM ; 'Please enter Sector Number (XXXXH):
CALL P_STRING
CALL ZGET_HL
JP C,DATA_ERROR
LD (@SEC),HL ; Store here
JP SD_MENU1
DATA_ERROR:
LD HL,DATA_ERROR_MSG ; "Data error"
CALL PRINT_STRING
JP SD_MENU1
;========================================== SET DMA ADDRESS =====================================================
SET_SD_DMA_ADDRESS:
LD HL,GET_DMA_MSG
CALL PRINT_STRING
CALL ZGET_HL
JP C,SD_MENU1
LD (@RAM_ADDRESS),HL
JP SD_MENU1
;-------------------------------------------SD CARD RESET -----------------------------------------------------------
SEND_SD_RESET: ; Send Card Reset CMD. CS is always off for SPI dummy clocks
LD B,0 ; Repeatidly send the RESET CMD0 (256 times)
INIT2: CALL DRIVE_CS_OFF ; Lower CS on SD card (Port 0CH)
LD C,12 ; Send 12 empty clock cycles
INIT1: CALL SPI_DUMMY_CLOCKS ; Clear SPI circuit/SD card
DEC C
JP NZ,INIT1
CALL DRIVE_CS_ON ; Lower CS on SD card (Port 0CH)
LD HL,CMD_0 ; (CMD0 OR 40H)
CALL SEND_SD_CMD
CALL READ_SPI ; Value returned in [A]
CALL DRIVE_CS_OFF ; -- Turn off CS on both SD Cards (AF Unchanged)
CP A,01H ; Is it OK
RET Z ; All OK ret Z set
DJNZ INIT2 ; Try 256 times
XOR A
DEC A
RET ; Error RET NZ
;------------------------------------------------ SEND_IDLE_STATE --------------------------------------
SEND_IDLE_STATE: ; Wait until card is in Idle state
LD B,40 ; Try several times
CALL DRIVE_CS_ON ; Lower CS on current SD card
SEND_IDLE1:
LD HL,CMD_1 ; <<<<<<<< SEND CMD1
CALL SEND_SD_CMD
CALL READ_SPI
CP A,0
JP Z,SEND_IDLE2
DJNZ SEND_IDLE1 ; Need to retry several times.
CALL DRIVE_CS_OFF ; -- Turn off CS on both SD Cards
XOR A
DEC A
RET ; Error RET NZ
SEND_IDLE2:
LD A,0FFH ; Flush with extra 0FF's
CALL WRITE_SPI
LD A,0FFH ; Flush with extra 0FF's
CALL WRITE_SPI
CALL DRIVE_CS_OFF ; -- Turn off CS on both SD Cards
XOR A
RET ; Error RET Z
;------------------------------------------------ GET CARD VOLTAGE/TYPE --------------------------------------
SEND_GET_TYPE: ; Get Card Voltage/Type
LD B,40 ; Try several times
CALL DRIVE_CS_ON ; Lower CS on current SD card
GET_TYPE1:
LD HL,CMD_8 ; SEND CMD8 to get Card Voltage
CALL SEND_SD_CMD
CALL READ_SPI
CP A,01H ; If 01 then Type 2
JP Z,SD_TYPE_2 ; If CMD8 is Illegal Cmd, then probably CARD_TYPE=1
DJNZ GET_TYPE1
CALL DRIVE_CS_OFF ; Turn off CS on both SD Cards
LD A,1 ; Probably Type 1 card
LD (@CARD_TYPE),A ; Type 1 or Type 2 Card
XOR A,A
DEC A
RET ; SD CARD not Type 2, Return NZ
SD_TYPE_2: ; Confirm type 2
CALL READ_SPI ; value returned in [A] is 00H
CALL READ_SPI ; value returned in [A] is 00H
CALL READ_SPI ; value returned in [A] is 01H
CALL READ_SPI ; value returned in [A] is 87H
CALL DRIVE_CS_OFF ; Turn off CS on both SD Cards
CP A,0AAH ; Must be 0AAH for Type 2 cards
JP NZ,NOT_2 ; SD CARD UNKNOWN_TYPE, Return NZ
LD A,2
LD (@CARD_TYPE),A ; Definately Type 2 card
XOR A,A
RET ; RET Z
NOT_2: LD A,0 ; Unknown card
LD (@CARD_TYPE),A ; Not Type 1 or Type 2 Card
XOR A,A
DEC A
RET ; Return NZ
; ------------------------------------- AVCTIVATE TYPE 2 CARDS ---------------------------------
TYPE_2_ACTIVATE: ; Initilize the SD card Type 2 cards with CMD55 & CMD44 Commands
LD B,40 ; Will try 40 times
ACT1: CALL DRIVE_CS_ON ; Lower CS on current SD card
LD HL,CMD_55 ; Application specific command next
CALL SEND_SD_CMD
CALL READ_SPI ; value returned in [A]
CP A,01H ; Correct response is 01H
JP Z,ACT2 ; Got correct response try CMD41
DJNZ ACT1
CALL DRIVE_CS_OFF ; -- Turn off CS on both SD Cards
XOR A
DEC A
RET ; Error RET NZ
ACT2: CALL DRIVE_CS_OFF ; Turn off CS on both SD Cards
CALL DRIVE_CS_ON ; Turn back on, Lower CS on current SD card (required!)
LD HL,CMD_41
CALL SEND_SD_CMD
CALL READ_SPI ; Value returned in [A]
CALL DRIVE_CS_OFF ; -- Turn off CS on both SD Cards
CP A,0
RET Z ; RET Z
DJNZ ACT1
XOR A
DEC A
RET ; Error RET NZ
; ---------------------------------------------- DEACTIVATE CRC CHECKING ----------------
STOP_CRC_CHECK: ; Will now stop CRC checking
CALL DRIVE_CS_ON ; Lower CS on current SD card
LD HL,CMD_59
CALL SEND_SD_CMD ; SEND CMD59 Turn off CRC checking
CALL READ_SPI ; Value returned in [A]
CALL DRIVE_CS_OFF ; Turn off CS on both SD Cards
CP A,0H
RET Z ; RET Z
XOR A
DEC A
RET ; Error RET NZ
; ---------------------------------------------- SET SECTOR SIZE FOR TYPE 1 & 2 CARDS ----------------
SET_SEC_SIZE: ; Will now set the sector size to 512 bytes
CALL DRIVE_CS_ON ; Lower CS on current SD card
LD HL,CMD_16
CALL SEND_SD_CMD ; SEND CMD16 to set sector size (512 Bytes)
CALL READ_SPI ; Value returned in [A]
CALL DRIVE_CS_OFF ; Turn off CS on both SD Cards
CP A,0H ; Should be 00000000B
RET Z ; RET Z
XOR A
DEC A
RET ; Error RET NZ
;------------------------------------------------ SEND CARD STATUS --------------------------------------
GET_CARD_STATUS: ; Get card status
LD B,40 ; Try several times
CALL DRIVE_CS_ON ; Lower CS on current SD card
CARD_STATUS_1:
LD HL,CMD_13 ; <<<<<<<< SEND CMD13
CALL SEND_SD_CMD
CALL READ_SPI
CP A,0
JP Z,CARD_STATUS_2
DJNZ CARD_STATUS_1 ; Need to retry several times.
CALL DRIVE_CS_OFF ; -- Turn off CS on both SD Cards
XOR A
DEC A
RET ; Error RET NZ
CARD_STATUS_2:
LD A,0FFH ; Flush with extra 0FF's
CALL WRITE_SPI
LD A,0FFH ; Flush with extra 0FF's
CALL WRITE_SPI
CALL DRIVE_CS_OFF ; -- Turn off CS on both SD Cards
XOR A
RET ; Error RET Z
;------------------------------------------- READ N SECTORS ----------------------------------------
READ_N_SD_SEC:
LD HL,ENTER_SEC_COUNT
CALL PRINT_STRING
CALL GETHEX ;get 2 HEX digits
LD HL,0
LD L,A
LD (@SEC_COUNT),HL
MORE_RD_SEC2:
CALL CORE_SD_READ ;Read one sector at a time
JR Z,MORE_RD_SEC1 ;Z means the sector read was OK
CALL ZCRLF
JP SD_MENU1 ;Was an error, don't display data
MORE_RD_SEC1:
CALL PRINT_SD_SEC ;Show current Sector
LD HL,msgrd ;Sector read OK
CALL PRINT_STRING
LD HL,(@SEC_COUNT)
DEC HL
LD (@SEC_COUNT),HL
LD A,L
OR A
JP Z,SD_MENU1
CALL BUMP_SD_SECTOR ;Bump SEC, DMA
JR MORE_RD_SEC2
;------------------------------------------- READ ONE SECTOR ----------------------------------------
READ_SD_SEC:
LD A,(@CARD_TYPE) ; Flag to check if SD card type has been determined
OR A,A
JP NZ,SD_CARD_RD_OK
LD HL,READ_ERR_MSG1 ; 'Sorry, SD Card must first be initilized (Menu 0).
CALL PRINT_STRING
JP SD_MENU1 ; Back to main menu
SD_CARD_RD_OK:
CALL CORE_SD_READ ; >>>>>> The main Read SD sector routine <<<<<<<<<
JR Z,DONE_RD_WR_SEC1 ;Z means the sector read was OK
CALL ZCRLF
JP SD_MENU1 ;Was an error, don't display data
DONE_RD_WR_SEC1:
LD HL,msgrd ; Sector Read OK
CALL PRINT_STRING
LD HL,(@RAM_ADDRESS) ; Point to start of DMA address
CALL HEXDUMP ; Display sector contents
LD HL,CONTINUE_MSG ; Print any character to continue
CALL PRINT_STRING
CALL ZCI
CP A,ESC
JP Z,BEGIN ;Abort everything
JP SD_MENU1
;========================================== READ A SECTOR =====================================================
CORE_SD_READ:
CALL DRIVE_CS_ON ; Lower CS on current SD card
LD B,0H ; Try up to 255 times!
READ_SEC1:
LD A,51H ; <<<<<<<< SEND CMD17 OR bits 40H added
CALL WRITE_SPI
LD A,0 ; Second byte of CMD
CALL WRITE_SPI
LD A,0 ; Third byte of CMD
CALL WRITE_SPI
LD HL,(@SEC) ; <---------- SECTOR NNUMBER ----
LD A,L ; Forth byte of CMD
CALL WRITE_SPI
LD A,H ; Fifth byte of CMD
CALL WRITE_SPI
LD A,0FFH ; CRC byte of CMD
CALL WRITE_SPI
LD A,0FFH ; Flush with extra 0FF's
CALL WRITE_SPI
CALL READ_SPI
CP A,0H ; Should be 00000000B
JP Z,READ_SEC_OK1
LD HL,SEC_RD_ERR0_MSG ; Got error with Read Sector command CMD17. (Status = "
CALL CMD_FAIL ; Deselect CS, Low speed CLK, send error Message, Ret NZ
JP SD_MENU1
LD B,0H
READ_SEC_OK1:
CALL READ_SPI
CP A,0FFH
JP Z,READ_SEC_OK1
CP A,0FEH ; Should be 0FEH (Start Token)
JP Z,READ_SEC_OK2
DJNZ READ_SEC_OK1 ; Keep trying until we see 0FEH
LD HL,SEC_RD_ERR1_MSG ; Got error with Read Sector command CMD17. (Status = "
CALL CMD_FAIL ; Deselect CS, Low speed CLK, send error Message, RET NZ
JP SD_MENU1
READ_SEC_OK2:
LD HL,(@RAM_ADDRESS) ; <---------- RAM ADDRESS ----
LD B,0
READ_256:
CALL READ_SPI
LD (HL),A
; CALL ZHEXOUT ; For debugging
INC HL
DJNZ READ_256
LD B,0
READ_512:
CALL READ_SPI
LD (HL),A
; CALL ZHEXOUT ; For debugging
INC HL
DJNZ READ_512
LD (@NEXT_ADDRESS),HL ; Save next sector DMA address
CALL READ_SPI ; Read 16 bit CRC
CALL READ_SPI
CALL READ_SPI ; Need one extra!
CALL DRIVE_CS_OFF ; Turn off CS on SD Card
XOR A
RET
;------------------------------------------- WRITE N SECTORS ----------------------------------------
WRITE_N_SD_SEC:
LD HL,ENTER_SEC_COUNT
CALL PRINT_STRING
CALL GETHEX ;get 2 HEX digits
LD HL,0
LD L,A
LD (@SEC_COUNT),HL
MORE_WR_SEC2:
CALL CORE_SD_WRITE ;Write one sector at a time
JR Z,MORE_WR_SEC1 ;Z means the sector read was OK
CALL ZCRLF
JP SD_MENU1 ;Was an error, don't display data
MORE_WR_SEC1:
CALL PRINT_SD_SEC ;Show current Sector
LD HL,msgwr ;Sector written OK
CALL PRINT_STRING
LD HL,(@SEC_COUNT)
DEC HL
LD (@SEC_COUNT),HL
LD A,L
OR A
JP Z,SD_MENU1
CALL BUMP_SD_SECTOR ;Bump SEC, DMA
JR MORE_WR_SEC2
;------------------------------------------- WRITE ONE SECTOR ----------------------------------------
WRITE_SD_SEC:
LD A,(@CARD_TYPE) ; Flag to check if SD card type has been determined
OR A,A
JP NZ,SD_CARD_WR_OK
LD HL,READ_ERR_MSG1 ; 'Sorry, SD Card must first be initilized (Menu 0).
CALL PRINT_STRING
JP SD_MENU1 ; Back to main menu
SD_CARD_WR_OK:
CALL CORE_SD_WRITE ; >>>>>> The main Write SD sector routine <<<<<<<<<
JP Z,DONE_RD_WR_SEC1 ;Z means the sector read was OK
CALL ZCRLF
JP SD_MENU1 ;Was an error, don't display data
;========================================== WRITE A SECTOR =====================================================
CORE_SD_WRITE:
CALL DRIVE_CS_ON ; Lower CS on current SD card
LD A,58H ; <<<<<<<< SEND CMD24 OR bits 40H added
CALL WRITE_SPI
LD A,0 ; Second byte of CMD
CALL WRITE_SPI
LD A,0 ; Third byte of CMD
CALL WRITE_SPI
LD HL,(@SEC)
LD A,L ; Forth byte of CMD
CALL WRITE_SPI
LD A,H ; Fifth byte of CMD
CALL WRITE_SPI
LD A,0FFH ; CRC byte of CMD
CALL WRITE_SPI
LD A,0FFH ; Flush with extra 0FF's
CALL WRITE_SPI
CALL READ_SPI
CP A,0H ; Should be 00000000B
JP Z,WRITE_SEC_OK1
LD HL,SEC_WR_ERR0_MSG ; 'Got error with Write Sector command CMD24. (Status =
CALL CMD_FAIL ; Deselect CS, Low speed CLK, send error Message
JP SD_MENU1
WRITE_SEC_OK1:
LD A,0FEH ; Start Block write flag
CALL WRITE_SPI
LD HL,(@RAM_ADDRESS)
LD B,0
WRITE_256:
LD A,(HL)
CALL WRITE_SPI
INC HL
DJNZ WRITE_256
LD B,0
WRITE_512:
LD A,(HL)
CALL WRITE_SPI
INC HL
DJNZ WRITE_512
LD (@NEXT_ADDRESS),HL ; Save next sector DMA address
LD A,0FFH ; Send 16 bit CRC
CALL WRITE_SPI
CALL WRITE_SPI
CALL READ_SPI ; Check all is OK
AND A,1FH
CP A,05H ; Should be xxx0AAA1H (AAA = 010)
JP Z,WRITE_SEC_OK2
CALL DRIVE_CS_OFF ; Turn off CS on SD Card
LD HL,SEC_WR_ERR1_MSG ; Got error with Read Sector command CMD24. (Status = "
CALL CMD_FAIL ; Deselect CS, Low speed CLK, send error Message
JP SD_MENU1
LD HL,0000H ; Wait until writing is done
WRITE_SEC_OK2:
CALL READ_SPI ; Wait for SD card to complete writing, (64K times)
CP A,0
JP Z,WRITE_SEC_OK3
DEC HL
LD A,L
OR A,H
JP NZ,WRITE_SEC_OK2
WRITE_ERR:
CALL DRIVE_CS_OFF ; Turn off CS on SD Card
LD HL,SEC_WR_ERR2_MSG ; Error waiting for SD Card to complete sector write. (Status = "
CALL CMD_FAIL ; Deselect CS, Low speed CLK, send error Message
JP SD_MENU1
; >>> NOT CLEAR WHAT IS WRONG WITH THIS WRITE SECTOR CODE
; >>> I NEED TO RESET THE CARD AFTER EACH SECTOR WRITE
; >>> OTHEREWISE THE NEXT SEC READ GIVES ERROROUS DATA
WRITE_SEC_OK3:
CALL SEND_SD_RESET ; CMD0
JP NZ,WRITE_RESET_ERR3 ; Error resetting SD Card after sector write, CMD0. (Status =
CALL SEND_GET_TYPE ; CMD8
JP NZ,WRITE_RESET_ERR4 ; Error getting SD Card type after sector write, CMD8. (Status =
CALL TYPE_2_ACTIVATE ; CMD55+CMD41
JP NZ,WRITE_RESET_ERR5
CALL DRIVE_CS_OFF ; Turn off CS on both SD Cards
XOR A,A
RET
WRITE_RESET_ERR3:
LD HL,SEC_WR_ERR3_MSG ; Error resetting SD Card after sector write, CMD0. (Status =
CALL CMD_FAIL ; Deselect CS, Low speed CLK, send error Message
JP SD_MENU1
WRITE_RESET_ERR4:
LD HL,SEC_WR_ERR4_MSG ; Error getting SD Card type after sector write. (Status =
CALL CMD_FAIL ; Deselect CS, Low speed CLK, send error Message
JP SD_MENU1
WRITE_RESET_ERR5:
LD HL,SEC_WR_ERR5_MSG ; Error re-activating Type 2 Card after sector write. (Status =
CALL CMD_FAIL ; Deselect CS, Low speed CLK, send error Message
JP SD_MENU1
;--------------------------------------------------------------------------------------------------
GOTO_NEXT_SEC:
CALL BUMP_SD_SECTOR
JP SD_MENU1
GOTO_PREVIOUS_SEC:
LD HL,(@NEXT_ADDRESS)
LD (@RAM_ADDRESS),HL ;DMA address
LD HL,(@SEC)
LD A,L
OR H
JR Z,AT_ZERO
DEC HL
LD (@SEC),HL
JP SD_MENU1
AT_ZERO:
LD C,BELL
CALL ZCO
JP SD_MENU1
;--------------------------------------------------------------------------------------------------
PRINT_SD_SEC:
LD HL,SD_MENU0_MSG ;'SD Card Menu Sector='
CALL PRINT_STRING
LD HL,(@SEC)
CALL HL_ONLY
JP SD_PRINT_2
;--------------------------------------------------------------------------------------------------
BUMP_SD_SECTOR: ;For multi sec read/writes
LD HL,(@NEXT_ADDRESS)
LD (@RAM_ADDRESS),HL ;DMA address
ld hl,(@SEC)
inc hl
ld (@SEC),hl
RET
;------------------------- SPI COMMANDS -------------------------------------------------
SPI_DUMMY_CLOCKS: ; Only [A] register altered
LD A,0FFH
CALL WRITE_SPI
RET
SEND_SD_CMD: ; Generalized CMD to send SD Card 6 commands. Only [A] & [HL] registers altered
LD A,(HL) ; Get first byte from CMD table (Note already has OR bits 40H added)
CALL WRITE_SPI
INC HL
LD A,(HL) ; Get second byte from CMD table
CALL WRITE_SPI
INC HL
LD A,(HL) ; Get third byte from CMD table
CALL WRITE_SPI
INC HL
LD A,(HL) ; Get forth byte from CMD table
CALL WRITE_SPI
INC HL
LD A,(HL) ; Get fifth byte from CMD table
CALL WRITE_SPI
INC HL
LD A,(HL) ; Get sixth byte from CMD table
CALL WRITE_SPI
INC HL
LD A,0FFH ; Send dummy byte to get returned message (Required!)
CALL WRITE_SPI
RET
WRITE_SPI: ; SEND ONE BYTE, No registers altered
PUSH AF
PUSH BC
CALL MIRROR ; MSB<-->LSB MIRROR BITS, RESULT IN C
CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING
OUT0 (SD_TRDR),C ; PUT BYTE IN BUFFER
IN0 A,(SD_CNTR)
SET 4,A ; SET TRANSMIT ENABLE
OUT0 (SD_CNTR),A
POP BC
POP AF
RET
READ_SPI: ; RECEIVE ONE BYTE, Only [A] register altered
PUSH BC
CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING
IN0 A,(SD_CNTR) ; GET CSIO STATUS
SET 5,A ; START RECEIVER
OUT0 (SD_CNTR),A
CALL SD_WAITRX
IN0 A,(SD_TRDR) ; GET RECEIVED BYTE
CALL MIRROR ; MSB<-->LSB MIRROR BITS
LD A,C ; KEEP RESULT
POP BC
RET
SD_WAITTX: ; CSIO WAIT FOR TRANSMIT READY (TX REGSITER EMPTY)
IN0 A,(SD_CNTR) ; GET CSIO STATUS
BIT 4,A ; TX EMPTY?
JR NZ,SD_WAITTX ; LOOP WHILE BUSY
RET
SD_WAITRX: ; CSIO WAIT FOR RECEIVER READY (BYTE AVAILABLE)
IN0 A,(SD_CNTR) ; WAIT FOR RECEIVER TO FINISH
BIT 5,A ; RX EMPTY?
JR NZ,SD_WAITRX ; LOOP WHILE BUSY
RET
MIRROR: ; MSB<-->LSB MIRROR BITS IN A, RESULT IN C
LD C,A ; A = 76543210
RLCA
RLCA ; A = 54321076
XOR C
AND 0AAH
XOR C ; A = 56341270
LD C,A
RLCA
RLCA
RLCA ; A = 41270563
RRC C ; C = 05634127
XOR C
AND 066H
XOR C ; A = 01234567
LD C,A ; RETURN RESULT IN C
RET
;---------------------------------------------------------------------------------------
CMD_FAIL: ; Generalized failure message routine (Message in [HL])
CALL DRIVE_CS_OFF ; Always, turn off CS on SD Card
CALL PRINT_STRING
IN0 A,(z180_trdr) ; Return data in [A] (Is latched)
CALL ZBITS
LD HL,BITS_END_MSG ; "B) "
CALL P_STRING
XOR A
DEC A
RET ; Return NZ
DRIVE_CS_OFF: ; Raise CS on SD card
PUSH AF ; Note no registers altered
LD A,04H ; We only have one drive
OUT0 (SD_CARD_CS),A ;Bit 2 to select onboard SD card adaptor (0=ON, 1=off)
OUT0 (SD_CARD_LED),A ;Bit 2 to turn on/off SD Card LED (0=ON, 1=off)
POP AF
RET
DRIVE_CS_ON: ; Lower CS on current SD card
PUSH AF ; Note no registers altered
LD A,00H ; We only have one drive
OUT0 (SD_CARD_CS),A ;Bit 2 to select onboard SD card adaptor (0=ON, 1=off)
OUT0 (SD_CARD_LED),A ;Bit 2 to turn on/off SD Card LED (0=ON, 1=off)
POP AF
RET
;-------------------------------------------------------------------------------------------
;------------------------ SUPPORT ROUTINES -------------------------------------------------
;-------------------------------------------------------------------------------------------
;SEND MESSAGE TO CONSOL MESSAGE IN [HL],LENGTH IN [B]
TOM: LD C,(HL)
INC HL
CALL ZCO
DJNZ TOM
RET
;ABORT IF ESC AT CONSOL, PAUSE IF ^S AT CONSOL
CCHK: CALL ZCSTS ;FIRST IS THERE ANYTHING THERE
RET Z
CALL ZCI
CP 'S'-40H
JR NZ,CCHK1
CCHK2: CALL ZCSTS ;WAIT HERE UNTIL ANOTHER INPUT IS GIVEN
JR Z,CCHK2
CCHK1: CP ESC
RET NZ ;RETURN EXECPT IF ESC
;PRINT HIGHEST MEMORY FROM BOTTOM
SIZE: CALL MEMSIZ ;RETURNS WITH [HL]= RAM AVAILABLE-WORKSPACE
LFADR: CALL ZCRLF
;PRINT [HL] AND A SPACE
ZPRINT_HL:
PUSH HL
PUSH BC
CALL LADR ;Print [HL] with space afterwards
LD C,SPACE
CALL ZCO
POP BC
POP HL
RET
;PRINT [HL] ONLY
HL_ONLY:
PUSH HL
PUSH BC
CALL LADR ;Print [HL] with no space afterwards
POP BC
POP HL
RET
;PRINT A SPACE
ZSPACE: PUSH AF
PUSH BC
LD C,SPACE
CALL ZCO
POP BC
POP AF
RET
;CONVERT HEX TO ASCII
CONV: AND 0FH
ADD 90H
DAA
ADC 40H
DAA
LD C,A
RET
;GET TWO PARAMETERS AND PUT THEM IN [HL] & [DE] THEN ZCRLF
EXLF: CALL HEXSP
POP DE
POP HL
;SEND TO CONSOL CR/LF
ZCRLF: PUSH BC
LD C,LF
CALL ZCO
LD C,CR
CALL ZCO
POP BC
RET
;PUT THREE PARAMETERS IN [BC] [DE] [HL] THEN CR/LF
EXPR3: INC C ;ALREADY HAD [C]=2 FROM START
CALL HEXSP
CALL ZCRLF
POP BC
POP DE
POP HL
RET
ZGET_HL:
CALL GETHEX ;Get 4 digits into HL
RET C
LD H,A
CALL GETHEX
RET C
LD L,A
OR A ;To return NC
RET
;GET ONE PARAMETER
EXPR1: LD C,01H
HEXSP: LD HL,0000
EX0: CALL TI
CP ESC
JR NZ,EX1
JP ESC_ABORT ;ABORT BACK TO MAIN LOOP
EX1: LD B,A
CALL NIBBLE
JR C,EX2X
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL
OR L
LD L,A
JR EX0
EX2X: EX (SP),HL
PUSH HL
LD A,B
CALL QCHK
JR NC,SF560
DEC C
RET Z
SF560: JP NZ,ERROR
DEC C
JR NZ,HEXSP
RET
EXF: LD C,01H
LD HL,0000H
JR EX1
ESC_ABORT:
LD C,BELL
CALL ZCO
CALL ZCRLF
POP AF ;BALANCE UP STACK
JP ZSTART
;RANGE TEST ROUTINE CARRY SET = RANGE EXCEEDED
HILOX: CALL CCHK
CALL HILO
RET NC
POP DE ;DROP ONE LEVEL BACK TO START
RET
HILO: INC HL ;RANGE CHECK SET CARRY IF [DE]=[HL]
LD A,H
OR L
SCF
RET Z
LD A,E
SUB L
LD A,D
SBC A,H
RET
;PRINT [HL] ON CONSOL
LADR: LD A,H ;Print HEX in A no other registers altered
CALL ZHEXOUT
LD A,L
LBYTE:
ZHEXOUT:
PUSH AF ;<<<< PRINT VALUE IN [A] in HEX ON CONSOLE
RRCA
RRCA
RRCA
RRCA
CALL SF598
POP AF
SF598: CALL CONV ;Char to [C]
JP ZCO ;Will force a return
PHEX: PUSH AF
PUSH BC
CALL ZHEXOUT
POP BC
POP AF
;THIS IS A CALLED ROUTINE USED TO CALCULATE TOP OF RAM IS USED BY
;THE ERROR ROUTINE TO RESET THE STACK.
;Returns top of RAM in [HL]
MEMSIZ: PUSH BC ;SAVE [BC]
MEMSZ1: LD HL,0FFFFH ;START FROM THE TOP DOWN
MEMSZ2: LD A,(HL)
CPL
LD (HL),A
CP (HL)
CPL ;PUT BACK WHAT WAS THERE
LD (HL),A
JP Z,GOTTOP
DEC H ;TRY 100H BYTES LOWER
JR MEMSZ2 ;KEEP LOOKING FOR RAM
GOTTOP: POP BC ;RESTORE [BC]
RET
NIBBLE: SUB 30H
RET C
CP 17H
CCF
RET C
CP LF
CCF
RET NC
SUB 07H
CP LF
RET
COPCK: LD C,'-'
CALL ZCO
PCHK: CALL TI
;TEST FOR DELIMITERS
QCHK: CP SPACE
RET Z
CP ','
RET Z
CP CR
SCF
RET Z
CCF
RET
;KEYBOARD HANDELING ROUTINE (WILL NOT ECHO CR/LF)
;IT CONVERTS LOWER CASE TO UPPER CASE FOR LOOKUP COMMANDS
;ALSO ^C WILL FORCE A JUMP TO BOOT IN CP/M
;ALL OTHERE CHARACTERS ARE ECHOED ON CONSOL
TI: CALL ZCI
CP CR
RET Z
CP 'C'-40H ;^C TO BOOT IN CP/M
JP Z,ZBOOT
PUSH BC
LD C,A
CALL ZCO
LD A,C
POP BC
CP 40H ;LC->UC
RET C
CP 7BH
RET NC
SF754: AND 5FH
RET
;DISPLAY 8 BITS OF [A] (B & C registers changed)
ZBITS: PUSH DE
PUSH BC
LD E,A
CALL BITS
POP BC
POP DE
RET
;DISPLAY 8 BITS OF [A] (B & C registers changed)
BITS: LD B,08H
SF76E: SLA E
LD A,18H
ADC A,A
LD C,A
CALL ZCO
DJNZ SF76E
RET
GETHEX:
CALL GETCMD ;Get a character from keyboard & ECHO
CP A,ESC
JR Z,HEXABORT
CP A,'/' ;check 0-9, A-F
JR C,HEXABORT
CP A,'F'+1
JR NC,HEXABORT
CALL ASBIN ;Convert to binary
RRCA
RRCA
RRCA
RRCA
LD B,A ;Store it
CALL GETCMD ;Get 2nd character from keyboard & ECHO
CP A,ESC
JR Z,HEXABORT
CP A,'/' ;check 0-9, A-F
JR C,HEXABORT
CP A,'F'+1
JR NC,HEXABORT
CALL ASBIN ;Convert to binary
OR A,B ;add in the first digit
OR A ;To return NC
RET
HEXABORT:
SCF ;Set Carry flag
RET
GETCMD: CALL ZCI ;GET A CHARACTER, convert to UC, ECHO it
CALL TO_UPPER
CP A,ESC
RET Z ;Don't echo an ESC
PUSH AF ;Save it
PUSH BC
LD C,A
CALL ZCO ;Echo it
POP BC
POP AF ;get it back
RET
;Convert LC to UC
TO_UPPER:
CP A,'a' ;must be >= lowercase a
RET C ; else go back...
CP A,'z'+1 ;must be <= lowercase z
RET NC ; else go back...
SUB A,'a'-'A' ;subtract lowercase bias
RET
ASBIN: SUB A,30H
CP A,0AH
RET M
SUB A,07H
RET
echo:
call ZCI ; get a character
cp ESC ; escape?
jr z,echoz ; done if so
LD C,A
call ZCO ; else send char
jr echo ; and loop
;
echoz: ; Say "Goodbye"
ld hl,str_goodbye
call PRINT_STRING
exit:
halt
;
NOT_DONE:
LD HL,CODE_NOT_DONE
CALL PRINT_STRING
RET
ERROR: LD C,'?'
CALL ZCO
JP BEGIN
;=======================================================================
; I/O SUPPORT PROCEDURES
;
;=======================================================================
;
; Print a string at HL to the primary CONSOLE PORT. In order to save ROM space
; with numerous CR,LF's before or after the actual text this routine has 3 options:-
; 1. If there is a terminating '$' at the end of the string send a CR/LF before returning
; 2. If there is a terminating 0H at the end of the string, just terminate the string
; In both the above cases the string always starts off with a CR/LF
; 3. If P_STRING is used then no CR/LF at the start of a string.
PRINT_STRING: ;Print string on Propeller Board
CALL ZCRLF
P_STRING: ; Start without CR,LF
ld a,(hl) ; get next char
CP A,'$' ; Terminate with a '$'
JR Z,P_STRING_CRLF ;Finish with CR,LF
or a ; end of string?
ret z ; Immediatly terminate
LD C,A
call ZCO ; print the char
inc hl ; bump to next char in string
jr P_STRING ; loop till done
P_STRING_CRLF:
LD C,CR
call ZCO ; print the char
LD C,LF
call ZCO ; print the char
RET
;>>>>>>>>>>>>>>>>>>>>>>>>> MODEM SERIAL PORT ROUTINES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;
;
MODEM_ZCI:
PUSH DE ;SAVE D,E
LD A,5H ;Lower RTS line
OUT0 (MODEM_CTL_PORT),A ;Sel Reg 5
LD A,11101010B ;EAH
OUT0 (MODEM_CTL_PORT),A
NOP
NOP
MSEC: LD DE,0BBBBH ;1 SEC DCR COUNT
MWTI: IN0 A,(MODEM_CTL_PORT)
AND A,MODEM_RECV_MASK
CP A,RECV_READY
JP Z,MCHAR ;GOT CHAR
DEC E ;COUNT DOWN
JP NZ,MWTI ;FOR TIMEOUT
DEC D
JP NZ,MWTI
DEC B ;DCR # OF SECONDS
JP NZ,MSEC ;MODEM TIMED OUT RECEIVING
POP DE ;RESTORE D,E
SCF ;CARRY SHOWS TIMEOUT
RET
MCHAR: IN0 A,(MODEM_DATA_PORT)
POP DE ;RESTORE DE
PUSH AF ;CALC CHECKSUM
ADD A,C
LD C,A
POP AF
OR A,A ;TURN OFF CARRY TO SHOW NO TIMEOUT
RET
;GET A CHARACTER FROM THE "MODEM" SERIAL PORT ON THE S100 BUS SERIAL IO BOARD
MODEM_ZCO:
PUSH AF ;CHECK IF MONITORING OUTPUT
ADD A,C ;CALC CKSUM
LD C,A
SENDW: IN0 A,(MODEM_CTL_PORT) ;Don't worry PC is always fast enough!
AND A,MODEM_SEND_MASK
CP A,SEND_READY
JP NZ,SENDW
POP AF ;GET CHAR
OUT0 (MODEM_DATA_PORT),A
;Raise RTS line to prevent the next character arriving
LD A,5H ;while the Z80 is busy processing info
OUT0 (MODEM_CTL_PORT),A ;Sel Reg 5
LD A,11101000B ;E8H
OUT0 (MODEM_CTL_PORT),A
RET
;
;
MODEM_ZSTATUS:
IN0 A,(MODEM_CTL_PORT)
AND A,MODEM_RECV_MASK
CP A,RECV_READY
JP Z,MREADY ;GOT CHAR
XOR A
RET ;RET Z if nothing
MREADY: XOR A
DEC A
RET ;RET NZ IF CHARACTER
;>>>>>>>>>>>>>>>>>>>>>>>>> SPEECH OUTPUT ROUTINES <<<<<<<<<<<<<<<<<<
;
;SPEAK OUTPUT (WILL BE USED TO COMMUNICATE WITH TALKER)
; Note the S100Computers I/O board V-Stamp speech chip will use the initial baud rate
; of of the SCC to communicate with it. This is determines after each reset/slave clear.
SPEAKER_CTS: ;Cannot get this to work. SCC does not change bit 5 of RR1
;when E1 sent to WR3 (No Auto Enable). See SCCINIT:
IN0 A,(BCTL) ;A0H
BIT 5,A
LD A,0FFH
RET NZ ;Ret NZ if CTS is High
XOR A
RET ;Ret Z if CTS is Low
SPEAKOUT:
XOR A,A ;Will try 256 times, then timeout
SPXXX: PUSH AF
IN0 A,(BCTL) ;(A0), Is SCC RX Buffer empty
AND 04H
JR NZ,SENDS ;NZ if ready to recieve character
POP AF
DEC A
JR NZ,SPXXX
RET
SENDS: POP AF
LD A,C
OUT0 (BDTA),A ;(A2), Send it
RET
;
;SPEAKTOMM THIS IS A ROUTINE TO SEND A STRING TO TALKER [HL] AT STRING
SPEAK$: LD A,(HL)
CP '$'
JR Z,SPEAK1
LD C,A
CALL SPEAKOUT
INC HL
JR SPEAK$
SPEAK1: LD C,0DH ;MUST END WITH A CR
JP SPEAKOUT
;>>>>>>>>>>>>>>>>>>>> MAIN PRINTER OUTPUT ROUTINES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
LO: PUSH BC
LD B,0FFH ;First make sure an actual printer is connected
LO2: CALL LSTAT
JR NZ,LO1 ;Printer is ready go to it
DJNZ LO2
POP BC
XOR A
LD A,C
RET ;RET Z if Printer problem (Not switched on)
IF ST8C4 ;If S100_Parallel_IO Board for Printer output
LD A,80H ;Z180 internal ports must be temporaly moved away from C0-FFH
out0 (z180_base),A
LO1: POP BC
LD A,PRINTER_ST_HIGH ;Make sure strobe is high
OUT0 (PRINTER_CTRL),A
LD A,C ;Send Data from [C]
OUT0 (PRINTER_OUT),A
LD A,PRINTER_ST_LOW ;Now send strobe High->Low
OUT0 (PRINTER_CTRL),A
LD A,PRINTER_ST_HIGH ;Now returb strobe back high
OUT0 (PRINTER_CTRL),A
ld a,z180_base ;Put internal Z180 ports back to C0-FFH range
out0 (0BFh),a
OR A,A
RET ;Ret NZ if OK
ELSE ;IMSAI PIO Board PARRELL PORT
LO1: POP BC
LD A,0FFH ;Setup strobe high to low then high
OUT0 (PRINTER_STROBE),A
LD A,C
OUT0 (PRINTER_OUT),A ;Now Data
XOR A ;STROBE FOR CENTRONICS
OUT (PRINTER_STROBE),A
LD A,0FFH ;Raise strobe again
OUT0 (PRINTER_STROBE),A
OR A,A
RET ;Ret NZ if OK
ENDIF
FLUSH: LD HL,FLUSH_MSG
CALL PRINT_STRING ;Have a Stack, so now we can use CALL
LD C,FF ;Send a Form Feed to laserJet Printer
CALL LO ;This forces a partial page to be printed
RET
IF ST8C4 ;If S100_Parallel_IO Board for Printer output
LD A,0 ;Z180 internal ports must be temporaly moved away from C0-FFH
ld a,z180_base
LSTAT: IN0 A,(PRINTER_STATUS) ;0CH status port of ST8C4
AND 11111111B ;For now
CP 11011111B ;should see 11011111 if printer is selected, ready, with paper etc.
JR Z,LSTAT1
ld a,z180_base ;Put them back to C0-FFH range
ld a,z180_base ;Put internal Z180 ports back to C0-FFH range
out0 (3Fh),a
RET ;Return Z if not ready
LSTAT1: ld a,z180_base ;Put internal Z180 ports back to C0-FFH range
out0 (3Fh),a
XOR A ;PUT 0FFH IN [A] IF READY & NO ZERO FLAG
DEC A
RET
ELSE ;IMSAI PIO Board PARRELL PORT
LSTAT: IN0 A,(PRINTER_STATUS)
AND 00001111B ;XXXX0110 IS READY (BIT 3=PAPER BIT 2=FAULT
CP 00000110B ;BIT 1=SELECT BIT 0=BUSY
JR Z,LSTAT1
XOR A
RET
LSTAT1: XOR A ;PUT 0FFH IN [A] IF READY & NO ZERO FLAG
DEC A
RET
ENDIF
;
;
;S100Computers Serial I/O Board Initilization
;Note Zilog SCC serial port A will be set to 19,200 Baud initially (for speech synthesizer).
;Note Zilog SCC serial port B will be set to 38,400 Baud initially (for XModem etc).
INIT_SCC_A:
LD A,ACTL ;Program Channel A
LD C,A
LD B,0EH ;Byte count for OTIR below
LD HL,SCCINIT_A
OTIR
RET
INIT_SCC_B:
LD A,BCTL ;Program Channel B
LD C,A
LD B,0EH ;Byte count for OTIR below
LD HL,SCCINIT_B
OTIR
RET
;
;
SCCINIT_A:
DB 04H ;Point to WR4
DB 44H ;X16 clock,1 Stop,NP
DB 03H ;Point to WR3
DB 0C1H ;Enable reciever, Auto Enable, Recieve 8 bits
; DB 0E1H ;Enable reciever, No Auto Enable, Recieve 8 bits (for CTS bit)
DB 05H ;Point to WR5
DB 0EAH ;Enable, Transmit 8 bits
DB 0BH ;Set RTS,DTR, Enable. Point to WR11
DB 56H ;Recieve/transmit clock = BRG
DB 0CH ;Point to WR12
; DB 40H ;Low Byte 2400 Baud
; DB 1EH ;Low Byte 4800 Baud <<<<<<<<<<< XModem I/O
; DB 0EH ;Low Byte 9600 Baud
; DB 06H ;Low byte 19,200 Baud
DB 02H ;Low byte 38,400 Baud <<<<<<<<<<< XModem I/O
; DB 00H ;Low byte 76,800 Baud
DB 0DH ;Point to WR13
DB 00H ;High byte for Baud
DB 0EH ;Point to WR14
DB 01H ;Use 4.9152 MHz Clock. Note SD Systems uses a 2.4576 MHz clock, enable BRG
DB 0FH ;Point to WR15
DB 00H ;Generate Int with CTS going high
SCCINIT_B:
DB 04H ;Point to WR4
DB 44H ;X16 clock,1 Stop,NP
DB 03H ;Point to WR3
DB 0C1H ;Enable reciever, Auto Enable, Recieve 8 bits
DB 05H ;Point to WR5
DB 0EAH ;Enable, Transmit 8 bits
DB 0BH ;Set RTS,DTR, Enable. Point to WR11
DB 56H ;Recieve/transmit clock = BRG
DB 0CH ;Point to WR12
DB 06H ;Low byte 19,200 Baud <<<<<<<<<<< Note Speech synthizer defaults to this value
DB 0DH ;Point to WR13
DB 00H ;High byte for Baud
DB 0EH ;Point to WR14
DB 01H ;Use 4.9152 MHz Clock. Note SD Systems uses a 2.4576 MHz clock, enable BRG
DB 0FH ;Point to WR15
DB 00H ;Generate Int with CTS going high
;
; Simply bank selection routine. Enter with A indicating the
; 32K bank of memory to select into the lower 32K of CPU space.
; For example, 00H selects first bank of ROM, 10H selects first
; bank of RAM. Register A is trashed!
;
; We want 32K banks, but Z180 uses 4K increments. So, we need to
; scale the input from 32K chunks to 4K chunks.
;
bnksel:
rlca ; Scale input from
rlca ; ... 32K chunk addressing to
rlca ; ... 4K chunk addressing
out0 (z180_bbr),a ; write to bank base reg
ret
;
; Data
;
SIGNON_MSG: DB BELL,CR,LF
DB 'Z180 ROM MONITOR (V0.34) @ E000H (J.Monahan,7/22/2023)',0
MENUMSG: DB 'A=Memmap B=ROMWBW D=Disp E=Echo F=Fill G=Goto H=Date',CR,LF
DB 'I=Time J=RAM Test K=Menu M=Move N=S100 O=Bus Req P=CPM(IDE)',CR,LF
DB 'QI,O=Port R=Ports S=Subs T=Type U=Halt V=Verify W=SD Card',CR,LF
DB 'X=XModem Y=IDE Z=Top @=Flush Printer',CR,LF
DB LF,'$'
SMSG_SP: DB 'Z 1 8 0 ROM MONITOR VERSION 0.34 PRESENT$'
TOP_RAM_MSG DB 'Top of RAM=',0
SP_MSG DB 'H SP=',0
IOBYTE_MSG DB 'H IOBYTE=',0
CR_SMSG_SP: DB CR,CR,'$'
CODE_NOT_DONE DB 'Code not written yet!$'
CHAR_TEST_MSG DB 'Keyboard input test. Enter characters. (ESC or ^C to abort)$'
S100_MENU DB LF,'S100 Bus Address Tests'
DB CR,LF,'0 Address line test (0 to FFFFH)'
DB CR,LF,'1 Send "333..." to S100 Port 01H'
DB CR,LF,'2 S100 Input Port 01H Test'
DB CR,LF,'3 S100 Consol I/O Test'
DB CR,LF,'4 Speech Test'
DB CR,LF,'5 Serial Board Port Test'
DB CR,LF,'6 Test Printer'
DB CR,LF,'7 Activate Interrupts'
DB CR,LF,'ESC To return to Main Menu'
DB CR,LF,'>',0
CONSOLE_TEST DB 'Enter S100 bus keyboard char. ESC to abort ',0
FLUSH_MSG DB 'Sending FF to Printer',0
MEM_TEST_MSG DB 'Memory Test 0-DF00H$'
MEM_ERR_MSG DB BELL,'RAM error at ',0
TIME_MSG DB 'Time:- ',0
DATE_MSG DB 'Date:- ',0
Time1_Msg DB ' ',0
Date1_Msg DB ' ',0
MODEM_SIGNON: DB 'Get a File from PC (38,400 Baud)$'
RMSG: DB 'WAITING FOR SECTOR #',0
ERRSOH: DB 'H RECEIVED, NOT SOH$'
ERR2: DB '++BAD SECTOR # IN HDR$'
ERR3: DB '++BAD CKSUM ON SECTOR$'
TOUTM: DB 'TIMEOUT ',0
QUITM: DB 'MULTIPLE ERRORS.'
DB 'TYPE Q TO QUIT, R TO RETRY:',0
MODEM_DONE_MSG: DB 'TRANSFER COMPLETE',0
BAD_HEADER_MSG: DB 'INVALID HEADER.$'
MODEM_RAM_MSG: DB 'H. If OK will write to RAM at ',0
MODEM_RAM_LOC: DB 'Enter RAM location (xxxxH +CR): ',0
HALT_MSG: DB 'The CPU halted!',0
SD_MENU0_MSG: DB LF,LF,'SD Card Menu '
DB 'Sector=',0
IDE_MENU0_MSG: DB LF,LF,'S100 Bus IDE Board Menu. Track=',0
IDE_MENU1_MSG: DB 'H Sector=',0
IDE_MENU3_MSG: DB 'H RAM Address=',0
BITS_END_MSG: DB 'B)$'
H_MSG: DB 'H.',0
SD_MENU4_MSG
IDE_SD_MENU_MSG: DB '0 Initilize Drive 0'
DB CR,LF,'1 Set Sec,(Track)'
DB CR,LF,'2 Set RAM Address'
DB CR,LF,'3 Read Sec'
DB CR,LF,'4 Write Sec'
DB CR,LF,'5 Read N Sec'
DB CR,LF,'6 Write N Sec'
DB CR,LF,'+ Next Sec'
DB CR,LF,'ESC To return to Main Menu'
DB CR,LF,'>',0
INIT_ERR: DB BELL,'Drive Init. Error$'
INIT_OK: DB 'Drive Init. OK',0
msgrd: DB 'Sec. Read OK',0
msgwr: DB 'Sec. Write OK',0
DRIVE_ERRORS DB BELL,'IDE Drive Err. Status=',0
READING_MSG DB 'Reading Sector(s)',0
WRITING_MSG DB 'Writing Sector(s)',0
GET_LBA_MSG: DB 'Enter CPM style TRK & SEC (in hex).$'
ENTER_SECL DB 'Starting sector no.,(xxH) = ',0
ENTER_TRKL DB 'Track no. (LOW byte, xxH) = ',0
ENTER_TRKH DB 'Track no. (HIGH byte, xxH) = ',0
ENTER_SEC_COUNT DB 'Number of Sec (xxH) = ',0
GET_DMA_MSG DB 'Enter RAM location for Sec. data (xxxxH) = ',0
Write_Sure: DB 'Warning: this will change data on the drive, '
DB 'are you sure? (Y/N)...',0
NMI_MSG: DB 'NMI Activated',CR,LF,'>',0 ;0E00FH
INT0_MSG: DB 'INT0 Activated',CR,LF,'>',0 ;0E01FH
SLAVE_MSG DB BELL,'Activate Master/Slave switch$'
INTS_OFF_MSG DB 'Inactivating Interrupts$'
INTS_ON_MSG DB 'Activating Interrupts$'
BOOT_ROM_MSG DB 'Booting ROMWBW$'
S100_ONLY_MSG DB BELL,'Code for the S100 bus only$'
CF_TYPE_ERR_MSG: DB BELL,'SD Card Type 2 was NOT detected. (Status =',0
CARD_TYPE2_MSG: DB 'Detected a Type 2 SD card.$'
CMD41_55_OK_MSG: DB 'CMD55 & CMD41 Commands OK.',CR,LF
DB 'The SD Card init. correctly.$'
CRC_ERROR_MSG: DB BELL,'Error turning off CRC checking. (Status = ',0
SIZE_ERROR_MSG: DB BELL,'Sect. size error. (Status = ',0
CMD55_FAIL_MSG: DB BELL,'SD Card Type 2 Init. failed (CMD55/CMD41) (Status = ',0
READ_ERR_MSG1: DB BELL,'SD Card must first be initilized (Menu 0).$'
SEC_RD_ERR0_MSG: DB BELL,'Read Sec. CMD CMD17 error. (Status = ',0
SEC_RD_ERR1_MSG: DB BELL,'Sec. read error. No 0FEH Flag. (Status = ',0
CONTINUE_MSG: DB 'Type any char. to continue.',0
ENTER_SEC_NUM: DB 'Enter Sec. No. (XXXXH): ',0
SEC_WR_ERR0_MSG: DB BELL,'Sec. write err., CMD24. (Status = ',0
SEC_WR_ERR1_MSG: DB BELL,'Error writing Sec. bytes, CMD24. (Status = ',0
SEC_WR_ERR2_MSG: DB BELL,'Error waiting for sec. write. (Status = ',0
SEC_WR_ERR3_MSG: DB BELL,'Error resetting sec. write, CMD0. (Status = ',0
SEC_WR_ERR4_MSG: DB BELL,'Error getting Card type, CMD8. (Status = ',0
SEC_WR_ERR5_MSG: DB BELL,'Error re-activating Type 2 Card, CMD55+CMD41. (Status = ',0
DATA_ERROR_MSG: DB BELL,CR,LF,'Data entry error.$'
SPEAKCPM_SP: DB 'LOADING CPM $'
DRIVE_NR_ERR: DB BELL,'Drive not Ready.',LF,'$'
BOOT_LD1_ERR: DB BELL,'BOOT error.',LF,'$'
BOOT_LD_ERR: DB BELL,'Read Error.',LF,'$'
IDE_RW_ERROR: DB BELL,'IDE Drive R/W Error',LF,'$'
CMD_0: DB 40H,00H,00H,00H,00H,95H,0FFH ; (0+64) To Reset the SD Card interface,
CMD_1: DB 41H,00H,00H,00H,00H,0F9H,0FFH ; (1+64) Activate Init Process
CMD_8: DB 48H,00H,00H,01H,0AAH,87H,0FFH ; (8+64) To check Card Voltage
CMD_9: DB 49H,00H,00H,00H,00H,8FH,0FFH ; (9+64) Read SD Register (CSD)
CMD_13: DB 4DH,00H,00H,00H,00H,081H,0FFH ; (13+64) get SD card status
CMD_16: DB 50H,00H,00H,02H,00H,081H,0FFH ; (16+64) Set Sector size to 512 Bytes
CMD_17: DB 51H,00H,00H,00H,00H,0FFH,0FFH ; (17+64) Read a single block (Block 0, Used to load boot sector only)
CMD_41: DB 69H,40H,00H,00H,00H,077H,0FFH ; (41+64) Activates the card's init. process.
;CMD_41: DB 69H,00H,00H,00H,000H,0E5H,0FFH ; (41+64) Activates the card's init. process.
CMD_55: DB 77H,00H,00H,00H,00H,065H,0FFH ; (55+64) Application specific command NEXT
CMD_58: DB 7AH,00H,00H,00H,00H,0FDH,0FFH ; (58+64) Read SD Cards OCR register
CMD_59: DB 7BH,00H,00H,00H,00H,0FDH,0FFH ; (59+64) Turn off CRC checking
;----------------- LOCAL DATA STORAGE ----------------------------------------------------------
@DELAYStore DB 0
@SEC DW 0
@TRK DW 0 ; +2H
@SEC_COUNT DW 0 ; +4H
@RAM_ADDRESS DW 0 ; +6H
@StartLineHex DW 0 ; +8H
@BYTE$COUNT DW 0 ; +0AH
@DRIVE$SEC DW 0 ; +0CH
@DRIVE$TRK DW 0 ; +0EH
@StartLineASCII DW 0 ; +10H
@NEXT_ADDRESS DW 0 ; +12H
@INTS_FLAG DW 0 ; +14H ;Flag to indicate if Interrupts are on = 1 or off = 0.
@CARD_TYPE DW 0 ; +16H ;For SD Cards
@SPARE DW 0 ; +18H
RAM_STORE_SIZE equ 18H
str_goodbye db CR,LF,'Goodbye, CPU Halted$'
@FINAL_BYTE DW 0 ; ;Last usable byte in RAM (must be less than 0FFFFH.
ROM_EMPTY equ (0FFFFH - $)
mon_len equ ($ - mon_start)
;
.dephase
end