diff --git a/doug/Makefile b/doug/Makefile new file mode 100755 index 00000000..3b1125ee --- /dev/null +++ b/doug/Makefile @@ -0,0 +1,692 @@ +######################################################## +# Makefile for Doug's Unified BIOS 8/07/2011 # +# The BIOS and associated utilities are generated # +# using the Small Device C Compiler (SDCC) & tools # +# With multiplatform enhancements by John Coffman # +# # +# sdcc.l00 added because stupid Windoze 'echo' appends # +# a confusing SPACE to the end of every line. # +######################################################## + +##################################################### +# SPREFIX tells where the SDCC package in installed # +# The SDCC package is used to assemble Z80 portions # +# of the software such as the ROM and perhaps some # +# .COM files such as FDISK. # +##################################################### + +################################################################# +# TPREFIX tells where the host development tools are installed. # +# The host tools are used to manipulate the Z80 objects after # +# the basic assemblies and compilations have been completed. # +################################################################# + +################################################################### +# SDCC is not available on the DOS host, so something else may be # +# used at the descretion of the builder. (TASM for instance). # +################################################################### + +################################################################### +# The COPY, DEL and RENAME macros are used to customize the build # +# rules for the host enviroonment. # +################################################################### + +#------------------------------------------- +# Choose one only, then Make will work for +# your platform. + +CFG = $(shell uname) +# Mac OS X returns 'Darwin' +# Linux returns 'Linux' + +#CFG = dos +#CFG = linux +#CFG = macosx +#CFG = windows + +#------------------------------------------- +ifeq ($(CFG),Darwin) +DELIM = / +SPREFIX = /Developer/sdcc +SDAS = $(SPREFIX)/bin/sdasz80 +SDASFLG = -plosff -Iinc +SDCC = $(SPREFIX)/bin/sdcc +SDCCFLG = -c -mz80 -D__SDCC__=1 -I inc +SDCCLIB = $(SPREFIX)/share/sdcc/lib/z80 +SDLD = $(SPREFIX)/bin/sdldz80 +SDLDFLG = +TPREFIX = +TCC = gcc +TCCFLG = -I inc +COPY = cp +DEL = rm +DELFLG = -f +# use native ECHO o Mac OS X +ECHO = echo +REN = mv +EXE = +endif +#------------------------------------------- +ifeq ($(CFG),windows) +DELIM = \ +SDRIVE = C: +SPREFIX = $(SDRIVE)\Program Files (x86)\sdcc +SDAS = $(SPREFIX)\bin\sdasz80 +SDASFLG = -plosff +SDCC = $(SPREFIX)\bin\sdcc +SDCCFLG = -c -mz80 -D__SDCC__=1 -I inc +SDCCLIB = $(SPREFIX)\lib\z80 +SDLD = $(SPREFIX)\bin\sdldz80 +SDLDFLG = +TPREFIX = +TCC = gcc +TCCOPT = -I inc +COPY = copy +DEL = erase +DELFLG = +REN = rename + +# This is special handling for John Coffman to get around funky windows +# behavior where echo adds spurious space o end f line +# ECHO = { lecho | lechocr | lecholf | lechocrlf | lecholfcr } + +#ECHO = $(BIN)$(DELIM)lechocr +#ECHO = $(BIN)$(DELIM)lecho + +EXE = .exe +endif + +#------------------------------------------- +ifeq ($(CFG),Linux) +DELIM = / +SPREFIX = /home/$(USER) +SDAS = $(SPREFIX)/bin/sdasz80 +SDASFLG = -plosff +SDCC = $(SPREFIX)/bin/sdcc +SDCCFLG = -c -mz80 -D__SDCC__=1 -I inc +SDCCLIB = /usr/local/share/sdcc/lib/z80 +SDLD = $(SPREFIX)/bin/sdldz80 +SDLDFLG = +TPREFIX = +TCC = gcc +TCCFLG = -I inc +COPY = cp +DEL = rm +DELFLG = -f +REN = mv +# Use native 'echo' on Linux +ECHO = echo +EXE = +endif +#------------------------------------------- +ifeq ($(CFG),dos) +DELIM = \ +SPREFIX = +SDAS = +SDASFLG = +SDCC = +SDCCFLG = +SDCCLIB = +SDLD = +SDLDFLG = +TPREFIX = +TCC = wcl +TCCOPT = +COPY = copy +DEL = erase +DELFLG = +REN = rename +EXE = .exe +endif +############################################################ + +# Misc other macros + +BIN = bin$(DELIM) +COM = com$(DELIM) +INC = inc$(DELIM) +LIB = lib$(DELIM) +LST = lst$(DELIM) +MAP = map$(DELIM) +OBJ = obj$(DELIM) +REF = ref$(DELIM) +ROM = rom$(DELIM) +SRC = src$(DELIM) +TMP = tmp$(DELIM) + +# CP/M-80 v2.2 Command files written in SDCC +COMFILES = $(COM)copyfile.com $(COM)fdisk.com + +# Components used by CP/M-80 v2.2 Command files +COMRELS = $(OBJ)cpm0.rel $(OBJ)cpmbdos.rel $(OBJ)cprintf.rel + +# Components of ROM image containing CP/M for SBC V2 +CPMRELS = $(OBJ)crt0.rel $(OBJ)dbgmon.rel $(OBJ)bdosb01.rel \ + $(OBJ)ccpb03.rel $(OBJ)cbios.rel + +# Components of ROM image used in test protocols +ROMRELS = $(OBJ)crt0jplp.rel $(OBJ)crt0scrm.rel + +# Components that control hardware in SBC V2 +SBCV2HW = + +# Components that control hardware in the SCSI2IDE +SCSI2IDEHW = $(OBJ)z53c80.rel + +FDISK = $(BIN)fdisk$(EXE) +DWGH2B = $(BIN)dwgh2b$(EXE) +INCFILES = $(INC)cpmbdos.h $(INC)cprintf.h $(INC)portab.h +JRCH2B = $(BIN)jrch2b$(EXE) +LOAD = $(BIN)load$(EXE) +MK = Makefile +#QUIET = @ + +# ROM images for SBC V2 and N8 +ROMFILES = $(ROM)scsiscrm.rom $(ROM)scsijplp.rom $(ROM)scsi2ide.rom $(ROM)baseline.rom $(ROM)n8.rom +SCSI2IDE = $(ROM)scsi2ide.rom + +SYSGEN = $(BIN)sysgen$(EXE) +VERIFY = $(BIN)verify$(EXE) + +# C programs compiled on host system used in build +TOOLS = $(FDISK) $(DWGH2B) $(LOAD) $(JRCH2B) $(SYSGEN) + +# Versions of 'echo' compiled on host system +ETOOLS = $(BIN)lechocr $(BIN)lecholf $(BIN)lechocrlf $(BIN)lecholfcr + +# dribdos.rel is not part of the production set yet +##TEST = dribdos.rel + +############################################################ + +#all: $(ETOOLS) $(TOOLS) $(BINFILES) $(COMFILES) $(CPMFILES) $(ROMFILES) + +#all: $(TEST) $(ROMFILES) $(COMFILES) + +roms: $(ROMFILES) +scsi2ide: $(SCSI2IDE) + +############################################################ + +# A test assembly of DRI source code for BDOS (from SIMH) +dribdos.rel: $(SRC)dribdos.s + $(QUIET)$(SDAS) $(SDASFLG) dribdos.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)dribdos.lst $(LST) + +############################################################ +############################################################ + +# Build SCSIJPLP ROM image + +$(ROM)scsijplp.rom: $(OBJ)scsijplp.bin $(MK) + $(QUIET)$(COPY) $(OBJ)scsijplp.bin $(ROM)scsijplp.rom + $(QUIET)$(DEL) $(DELFLG) scsijplp.* + +$(OBJ)scsijplp.bin: $(OBJ)scsijplp.hex $(DWGH2B) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)scsijplp + +$(OBJ)scsijplp.hex: $(OBJ)scsijplp.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)scsijplp.ihx $(OBJ)scsijplp.hex + +$(OBJ)scsijplp.ihx: $(OBJ)crt0jplp.rel $(TMP)scsijplp.arf $(MK) + $(QUIET)$(COPY) $(TMP)scsijplp.arf $(TMP)scsijplp.lk + $(QUIET)$(COPY) $(TMP)scsijplp.arf $(TMP)scsijplp.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)scsijplp.lnk + $(QUIET)$(COPY) $(COPYFLG) scsijplp.ihx $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) scsijplp.map $(MAP) + +######################################################### +# Dynamically generate linker control file for scsi2ide # +# (now uses the macro controlled ECHO feature # +######################################################### +$(TMP)scsijplp.arf: $(MK) + $(ECHO) -mjx > $(TMP)scsijplp.arf + $(ECHO) -i scsijplp.ihx >> $(TMP)scsijplp.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)scsijplp.arf + $(ECHO) -l z80 >> $(TMP)scsijplp.arf + $(ECHO) $(OBJ)crt0jplp.rel >> $(TMP)scsijplp.arf + $(ECHO) -e >> $(TMP)scsijplp.arf + +############################################################ +############################################################ + +# Build SCSISCRM ROM image + +$(ROM)scsiscrm.rom: $(OBJ)scsiscrm.bin $(MK) + $(QUIET)$(COPY) $(OBJ)scsiscrm.bin $(ROM)scsiscrm.rom + $(QUIET)$(DEL) $(DELFLG) scsiscrm.* + +$(OBJ)scsiscrm.bin: $(OBJ)scsiscrm.hex $(DWGH2B) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)scsiscrm + +$(OBJ)scsiscrm.hex: $(OBJ)scsiscrm.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)scsiscrm.ihx $(OBJ)scsiscrm.hex + +$(OBJ)scsiscrm.ihx: $(OBJ)crt0scrm.rel $(TMP)scsiscrm.arf $(MK) + $(QUIET)$(COPY) $(TMP)scsiscrm.arf $(TMP)scsiscrm.lk + $(QUIET)$(COPY) $(TMP)scsiscrm.arf $(TMP)scsiscrm.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)scsiscrm.lnk + $(QUIET)$(COPY) $(COPYFLG) scsiscrm.ihx $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) scsiscrm.map $(MAP) + +######################################################### +# Dynamically generate linker control file for scsiscrm # +# (now uses the macro controlled ECHO feature # +######################################################### +$(TMP)scsiscrm.arf: $(MK) + $(ECHO) -mjx > $(TMP)scsiscrm.arf + $(ECHO) -i scsiscrm.ihx >> $(TMP)scsiscrm.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)scsiscrm.arf + $(ECHO) -l z80 >> $(TMP)scsiscrm.arf + $(ECHO) $(OBJ)crt0scrm.rel >> $(TMP)scsiscrm.arf + $(ECHO) -e >> $(TMP)scsiscrm.arf + +############################################################ +############################################################ + +# Build SCSI2IDE ROM image + +$(ROM)scsi2ide.rom: $(OBJ)scsi2ide.bin $(MK) + $(QUIET)$(COPY) $(OBJ)scsi2ide.bin $(ROM)scsi2ide.rom + $(QUIET)$(DEL) $(DELFLG) scsi2ide.* + +$(OBJ)scsi2ide.bin: $(OBJ)scsi2ide.hex $(DWGH2B) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)scsi2ide + +$(OBJ)scsi2ide.hex: $(OBJ)scsi2ide.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)scsi2ide.ihx $(OBJ)scsi2ide.hex + +$(OBJ)scsi2ide.ihx: $(CPMRELS) $(SCSI2IDEHW) $(OBJ)scsi2ide.rel $(TMP)scsi2ide.arf $(MK) + $(QUIET)$(COPY) $(TMP)scsi2ide.arf $(TMP)scsi2ide.lk + $(QUIET)$(COPY) $(TMP)scsi2ide.arf $(TMP)scsi2ide.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)scsi2ide.lnk + $(QUIET)$(COPY) $(COPYFLG) scsi2ide.ihx $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) scsi2ide.map $(MAP) + +######################################################### +# Dynamically generate linker control file for scsi2ide # +# (now uses the macro controlled ECHO feature # +######################################################### +$(TMP)scsi2ide.arf: $(MK) + $(ECHO) -mjx > $(TMP)scsi2ide.arf + $(ECHO) -i scsi2ide.ihx >> $(TMP)scsi2ide.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)scsi2ide.arf + $(ECHO) -l z80 >> $(TMP)scsi2ide.arf +# $(ECHO) -b _CCPB03 = 0xD000 >> $(TMP)scsi2ide.arf +# $(ECHO) -b _BDOSB01 = 0xD800 >> $(TMP)scsi2ide.arf +# $(ECHO) -b _CBIOS = 0xE600 >> $(TMP)scsi2ide.arf +# $(ECHO) -b _DBGMON = 0x8000 >> $(TMP)scsi2ide.arf + $(ECHO) $(OBJ)crt0.rel >> $(TMP)scsi2ide.arf + $(ECHO) $(OBJ)scsi2ide.rel >> $(TMP)scsi2ide.arf +# $(ECHO) $(OBJ)dbgmon.rel >> $(TMP)scsi2ide.arf +# $(ECHO) $(OBJ)ccpb03.rel >> $(TMP)scsi2ide.arf +# $(ECHO) $(OBJ)bdosb01.rel >> $(TMP)scsi2ide.arf +# $(ECHO) $(OBJ)cbios.rel >> $(TMP)scsi2ide.arf + $(ECHO) -e >> $(TMP)scsi2ide.arf + +######################################################## +# Compile C portion of the scsi2ide EEPROM Image +$(OBJ)scsi2ide.rel: $(SRC)scsi2ide.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) -c $(SRC)scsi2ide.c + $(QUIET)$(COPY) $(COPYFLG) scsi2ide.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) scsi2ide.lst $(LST) + + +############################################################ +############################################################ + +# Build SBC V2 ROM image + +$(ROM)baseline.rom: $(OBJ)baseline.bin $(MK) + $(QUIET)$(COPY) $(OBJ)baseline.bin $(ROM)baseline.rom + $(QUIET)$(DEL) $(DELFLG) baseline.* + +$(OBJ)baseline.bin: $(OBJ)baseline.hex $(DWGH2B) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)baseline + +$(OBJ)baseline.hex: $(OBJ)baseline.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)baseline.ihx $(OBJ)baseline.hex + +$(OBJ)baseline.ihx: $(CPMRELS) $(SBCV2HW) $(OBJ)baseline.rel $(TMP)baseline.arf $(MK) + $(QUIET)$(COPY) $(TMP)baseline.arf $(TMP)baseline.lk + $(QUIET)$(COPY) $(TMP)baseline.arf $(TMP)baseline.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)baseline.lnk + $(QUIET)$(COPY) $(COPYFLG) baseline.ihx $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) baseline.map $(MAP) + +######################################################### +# Dynamically generate linker control file for baseline # +# (now uses the macro controlled ECHO feature # +######################################################### +$(TMP)baseline.arf: $(MK) + $(ECHO) -mjx > $(TMP)baseline.arf + $(ECHO) -i baseline.ihx >> $(TMP)baseline.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)baseline.arf + $(ECHO) -l z80 >> $(TMP)baseline.arf + $(ECHO) -b _CCPB03 = 0xD000 >> $(TMP)baseline.arf + $(ECHO) -b _BDOSB01 = 0xD800 >> $(TMP)baseline.arf + $(ECHO) -b _CBIOS = 0xE600 >> $(TMP)baseline.arf + $(ECHO) -b _DBGMON = 0x8000 >> $(TMP)baseline.arf + $(ECHO) $(OBJ)crt0.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)baseline.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)dbgmon.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)ccpb03.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)bdosb01.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)cbios.rel >> $(TMP)baseline.arf + $(ECHO) -e >> $(TMP)baseline.arf + +######################################################## +# Compile C portion of the Baseline PROM Image +$(OBJ)baseline.rel: $(SRC)baseline.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) -c $(SRC)baseline.c + $(QUIET)$(COPY) $(COPYFLG) baseline.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) baseline.lst $(LST) + +############################################################ + +# Build N8 ROM image + +# +# Save the resulting merged image in the Rom folder +# +$(ROM)n8.rom: $(OBJ)n8-romim.bin $(MK) + $(QUIET)$(COPY) $(OBJ)n8-romim.bin $(ROM)n8.rom + $(QUIET)$(DEL) $(DELFLG) n8.* + +# +# Convert the Intel hex file into a binary, similar +# to the results of the "copy /B ..." +# +$(OBJ)n8-romim.bin: $(OBJ)sysimage.hex $(REF)n8-romim.ref $(SYSGEN) $(HEX2BIN) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)sysimage + $(QUIET)$(COPY) $(REF)n8-romim.ref $(OBJ)n8-romim.bin + $(QUIET)$(SYSGEN) -i $(OBJ)sysimage.bin $(OBJ)n8-romim.bin + +# +# Take the output of the linker and rename to the more +# recognizable .hex form and the expected name "sysimage.hex" +# +$(OBJ)sysimage.hex: $(OBJ)n8.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)n8.ihx $(OBJ)sysimage.hex + +# +# Combine the independently assembled components into one piece +# and output Intel hex file (ihx) +# +$(OBJ)n8.ihx: $(OBJ)loadern8.rel $(OBJ)dbgmon.rel $(OBJ)ccpb03.rel $(OBJ)bdosb01.rel $(OBJ)cbiosn8.rel $(TMP)n8.arf $(MK) + $(QUIET)$(COPY) $(TMP)n8.arf $(TMP)n8.lk + $(QUIET)$(COPY) $(TMP)n8.arf $(TMP)n8.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)n8.lnk + $(QUIET)$(COPY) $(COPYFLG) n8.ihx $(OBJ)n8.ihx + $(QUIET)$(COPY) $(COPYFLG) n8.map $(MAP) + +$(OBJ)cbiosn8.rel: $(SRC)cbiosn8.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)cbiosn8.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cbiosn8.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cbiosn8.lst $(LST) + +$(OBJ)loadern8.rel: $(SRC)loadern8.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)loadern8.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)loadern8.rel $(OBJ) + $(QUIET)$(COPY $(COPYFLG) $(SRC)loadern8.lst $(LST) + +######################################################## +# Dynamically generate the linker control file for N8 # +# Now uses the macro controlled ECHO feature # +######################################################## +$(TMP)n8.arf: Makefile + $(ECHO) -mjx > $(TMP)n8.arf + $(ECHO) -i n8.ihx >> $(TMP)n8.arf + $(ECHO) -k /usr/local/share/sdcc/lib/z80 >> $(TMP)n8.arf + $(ECHO) -l z80 >> $(TMP)n8.arf + $(ECHO) -b _CCPB03 = 0x0900 >> $(TMP)n8.arf + $(ECHO) -b _BDOSB01 = 0x1100 >> $(TMP)n8.arf + $(ECHO) -b _CBIOS = 0x1f00 >> $(TMP)n8.arf + $(ECHO) $(OBJ)loadern8.rel >> $(TMP)n8.arf + $(ECHO) $(OBJ)dbgmon.rel >> $(TMP)n8.arf + $(ECHO) $(OBJ)ccpb03.rel >> $(TMP)n8.arf + $(ECHO) $(OBJ)bdosb01.rel >> $(TMP)n8.arf + $(ECHO) $(OBJ)cbiosn8.rel >> $(TMP)n8.arf + $(ECHO) -e >> $(TMP)n8.arf + +############################################################ + +# Hardware specific assemblies (most likely used by BIOS's) + +# +# Assemble hardware control code for the Zilog Z53C8003V5C +# +$(OBJ)z53c80.rel: $(SRC)z53c80.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) $(SRC)z53c80.c + $(QUIET)$(COPY) $(COPYFLG) z53c80.rel $(OBJ) + $(QUIET)$(DEL) $(DELFLG) z53c80.* + +# +# Compile ersatz printf routine for use in CP/M-80 command files +# +$(OBJ)cprintf.rel: $(SRC)cprintf.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) $(SRC)cprintf.c + $(QUIET)$(COPY) $(COPYFLG) cprintf.rel obj + $(QUIET)$(DEL) $(DELFLG) cprintf.* + +############################################################ + +# Build CP/M 2.2 command files (copyfile.com, fdisk.com) + +#----------------------------------------------------------- + +$(COM)copyfile.com: $(OBJ)copyfile.com $(MK) + $(QUIET)$(COPY) $(OBJ)copyfile.com $(COM)copyfile.com + $(QUIET)$(DEL) $(DELFLG) copyfile.* + +$(OBJ)copyfile.com: $(OBJ)copyfile.hex $(LOAD) $(BINFILES) $(MK) + $(QUIET)$(LOAD) $(OBJ)copyfile + +$(OBJ)copyfile.hex: $(OBJ)copyfile.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)copyfile.ihx $(OBJ)copyfile.hex + +$(OBJ)copyfile.ihx: $(OBJ)copyfile.rel $(COMRELS) $(TMP)copyfile.arf $(MK) + $(QUIET)$(COPY) $(TMP)copyfile.arf $(TMP)copyfile.lnk + + $(QUIET)$(SDLD) $(LOPTS) -nf $(TMP)copyfile.lnk + $(QUIET)$(COPY) $(COPYFLG) copyfile.ihx obj + $(QUIET)$(COPY) $(COPYFLG) copyfile.map map + +############################################################## +# Dynamicaly create linker command file for copyfile utility # +# Now uses the macro controlled ECHO feature # +############################################################## +$(TMP)copyfile.arf: Makefile + $(ECHO) -mjx > $(TMP)copyfile.arf + $(ECHO) -i copyfile.ihx >> $(TMP)copyfile.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)copyfile.arf + $(ECHO) -l z80 >> $(TMP)copyfile.arf + $(ECHO) $(OBJ)cpm0.rel >> $(TMP)copyfile.arf + $(ECHO) $(OBJ)copyfile.rel >> $(TMP)copyfile.arf + $(ECHO) $(OBJ)cpmbdos.rel >> $(TMP)copyfile.arf + $(ECHO) $(OBJ)cprintf.rel >> $(TMP)copyfile.arf + $(ECHO) -e >> $(TMP)copyfile.arf + +$(OBJ)copyfile.rel: $(SRC)copyfile.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) $(SRC)copyfile.c + $(QUIET)$(COPY) copyfile.rel obj + $(QUIET)$(DEL) $(DELFLG) copyfile.rel + ls obj + +#----------------------------------------------------------- + +# +# Use locally compiled 'load' command to covert Intel +# hex formal file to a binary CP/M-80 command file. +# +$(COM)fdisk.com: $(OBJ)fdisk.hex $(TOOLS) $(MK) + $(QUIET)$(BIN)load $(OBJ)fdisk + $(QUIET)$(COPY) $(COPYFLG) $(OBJ)fdisk.com com + $(QUIET)$(DEL) $(DELFLG) fdisk.* + +# +# rename 'ihx' output of linker to 'hex' + +$(OBJ)fdisk.hex: $(OBJ)fdisk.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)fdisk.ihx $(OBJ)fdisk.hex + +$(OBJ)fdisk.ihx: $(OBJ)fdisk.rel $(TMP)fdisk.arf $(MK) + $(QUIET)$(COPY) $(TMP)fdisk.arf $(TMP)fdisk.lnk + $(QUIET)$(COPY) $(TMP)fdisk.arf $(TMP)fdisk.lk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)fdisk.lnk + $(QUIET)$(COPY) $(COPYFLG) fdisk.ihx $(OBJ)fdisk.ihx + $(QUIET)$(COPY) $(COPYFLG) fdisk.map map + +$(OBJ)fdisk.rel: $(SRC)fdisk.c $(INCFILES) $(MK) + $(QUIET)$(SDCC) -I inc $(SDCCFLG) $(SRC)fdisk.c + $(QUIET)$(COPY) $(COPYFLG) fdisk.rel $(OBJ) + +############################################################################ +# Dynamically created linker command file for fdisk utility (CP/M version) # +# Now uses macro controlled ECHO feature # +############################################################################ +$(TMP)fdisk.arf: $(MK) + $(ECHO) -mjx > $(TMP)fdisk.arf + $(ECHO) -i fdisk.ihx >> $(TMP)fdisk.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)fdisk.arf + $(ECHO) -l z80 >> $(TMP)fdisk.arf + $(ECHO) $(OBJ)cpm0.rel >> $(TMP)fdisk.arf + $(ECHO) $(OBJ)fdisk.rel >> $(TMP)fdisk.arf + $(ECHO) $(OBJ)cpmbdos.rel >> $(TMP)fdisk.arf + $(ECHO) $(OBJ)cprintf.rel >> $(TMP)fdisk.arf + $(ECHO) -e >> $(TMP)fdisk.arf + + +#----------------------------------------------------------- + +# Also build host version of fdisk for testing purposes + +$(BIN)fdisk$(EXE): $(SRC)fdisk.c $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)fdisk.c -o $(BIN)fdisk + +############################################################ + +# Build CP/M-80 Command File Structure Files + +$(OBJ)cpm0.rel: $(SRC)cpm0.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)cpm0.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cpm0.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cpm0.lst $(LST) + +$(OBJ)cpmbdos.rel: $(SRC)cpmbdos.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)cpmbdos.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cpmbdos.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cpmbdos.lst $(LST) + +############################################################ + +# Build ROM Image structure files + +$(OBJ)crt0.rel: $(SRC)crt0.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)crt0.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0.lst $(LST) + +$(OBJ)crt0jplp.rel: $(SRC)crt0jplp.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)crt0jplp.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0jplp.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0jplp.lst $(LST) + +$(OBJ)crt0scrm.rel: $(SRC)crt0scrm.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)crt0scrm.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0scrm.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0scrm.lst $(LST) + +$(OBJ)bdosb01.rel: $(SRC)bdosb01.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)bdosb01.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)bdosb01.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)bdosb01.lst $(LST) + +$(OBJ)ccpb03.rel: $(SRC)ccpb03.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)ccpb03.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)ccpb03.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)ccpb03.lst $(LST) + +# +# Assemble hardware control code for SBC V2 +# +$(OBJ)cbios.rel: $(SRC)cbios.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)cbios.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cbios.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cbios.lst $(LST) + +# +# Assemble a monitor program for the SBC V2 +# +$(OBJ)dbgmon.rel: $(SRC)dbgmon.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)dbgmon.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)dbgmon.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)dbgmon.lst $(LST) + +########################################################### + +# Build host based tools ( dwgh2b, jrch2b, load, verify) + +$(DWGH2B): $(SRC)dwgh2b.c $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)dwgh2b.c -o $(BIN)dwgh2b$(EXE) + +# +# Compile John Coffman's hex2bin program +# +$(JRCH2B): $(SRC)jrch2b.c $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)jrch2b.c -o $(BIN)jrch2b$(EXE) + $(QUIET)$(COPY) $(COPYFLG) $(BIN)jrch2b $(BIN)jrcb2h + +# +# Compile Doug's "load" program +# +$(LOAD): $(SRC)load.c $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)load.c -o $(BIN)load$(EXE) + +$(SYSGEN): $(SRC)sysgen.c $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)sysgen.c -o $(BIN)sysgen$(EXE) + +# +# Compile Doug's verif program that compares binary file regions +# +$(VERIFY): $(SRC)verify.c Makefile $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)verify.c -o $(BIN)verify + +$(BIN)lechocr: $(SRC)lechocr.c $(MK) +# $(QUIET)$(TCC) $(TCCFLG) $(SRC)lechocr.c -o $(BIN)lechocr + $(QUIET)$(TCC) $(TCCFLG) $(SRC)lechocr.c + $(QUIET)$(COPY) lechocr.exe $(BIN) + +$(BIN)lecholf: $(SRC)lecholf.c $(MK) +# $(QUIET)$(TCC) $(TCCFLG) $(SRC)lecholf.c -o $(BIN)lecholf + $(QUIET)$(TCC) $(TCCFLG) $(SRC)lecholf.c + $(COPY) lecholf.exe $(BIN) + +$(BIN)lechocrlf: $(SRC)lechocrlf.c $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)lechocrlf.c -o $(BIN)lechocrlf + +$(BIN)lecholfcr: $(SRC)lecholfcr.c $(MK) +# $(QUIET)$(TCC) $(TCCFLG) $(SRC)lecholfcr.c -o $(BIN)lecholfcr + $(QUIET)$(TCC) $(TCCFLG) $(SRC)lecholfcr.c -o $(BIN)lecholfcr + +############################################################ + +# Builder specific utility rules + +dwginstall: + $(COPY) $(COMFILES) ~/Documents/devobox/cdrive + +############################################################ + +# +# Delete all dynamically generated files that don't need to be +# saved. +# +clean: + $(QUIET)$(DEL) $(DELFLG) *.hex *.ihx *.lst *.rel *.rst *.lnk *.lk + $(QUIET)$(DEL) $(DELFLG) *.sym *.map *.noi *.asm *.com *.ini *.bin + $(QUIET)$(DEL) $(DELFLG) obj/* bin/* com/* rom/* tmp/* map/* lst/* + +################## +# eof - Makefile # +################## diff --git a/doug/doc/agm1264f.pdf b/doug/doc/agm1264f.pdf new file mode 100755 index 00000000..60eec3d9 Binary files /dev/null and b/doug/doc/agm1264f.pdf differ diff --git a/doug/doc/bdoscalls.webarchive b/doug/doc/bdoscalls.webarchive new file mode 100755 index 00000000..30b4faad Binary files /dev/null and b/doug/doc/bdoscalls.webarchive differ diff --git a/doug/doc/bios.webarchive b/doug/doc/bios.webarchive new file mode 100755 index 00000000..ede74cc5 Binary files /dev/null and b/doug/doc/bios.webarchive differ diff --git a/doug/doc/fcb.webarchive b/doug/doc/fcb.webarchive new file mode 100755 index 00000000..d8468620 Binary files /dev/null and b/doug/doc/fcb.webarchive differ diff --git a/doug/doc/jrch2b.doc b/doug/doc/jrch2b.doc new file mode 100755 index 00000000..6231b4db --- /dev/null +++ b/doug/doc/jrch2b.doc @@ -0,0 +1,92 @@ +Usage: + hex2bin [ ]+ + bin2hex + + Options: + -o -- default is 'out.bin' or 'out.hex' + No suffix is added to the filename, so the full + file name must be specified. + + -p -- default is 0xFF, which is the erased + value for most ROM's. Pad bytes are not explicitly + written out when 'bin2hex' is used. This reduces + the size of sparse ROM images. + + -R -- may be any value. Normally this will be + specified as '128k' or 0x10000. The suffixes 'k' + and 'M' are recognized. The default value is 64k + for 'hex2bin' and 1M for 'bin2hex'. + + -v [] -- used primarily for debugging. A + verbosity level of 3 will print each line as it is + processed. + + Options are global, and may be specified anywhere on the command + line. Only 'flags', below, are position sensitive. Flags must + be specified immediately before the file name they are to affect. + They do not affect more that a single file. They reset to their + default values before the next input file, scanning left to + right, is processed. + + Flags: + Flag values apply only to the following file, and are reset + to the default values before the next file is processed. The + source and destination flags allow code to be relocated + within the ROM so that code may be loaded at a different + location than where it will ultimately be run. + + -d -- default is 0. + data will only be loaded between the limits of + the -d address and the -D address + minus 1. + + -D -- default is 16M. No data + will be loaded at or above this address. + + -s -- default is 0. Hex input + is only processed if it falls at addresses in the + .hex input file between the -s address and the + -S address minus 1. Likewise, Bin input + is only processed if it falls between similar limits + in the input ROM image. + + -S -- default is 16M. No input + data at or above this address will be processed. + + Numeric values on the command line may be specified in any C-like + syntax: 0x0000 is hexadecimal, 1234 is decimal, and 0177 is + octal. In addition the suffixes 'k' for kilo- and 'M' for mega- + cause the preceding values to be multiplied by 1024 or 1048576, + respectively. + + Examples: + hex2bin -p 0xFF -R32k cpm22.hex -o cpmtest.bin + hex2bin -o cpmtest.bin cpm22.hex -R 0x8000 -p255 + + The preceding two lines have identical effects in all + respects. + + hex2bin -R 1M -s 0xd000 -d 0x0800 -D0x2800 image.hex \ + pagezero.hex -oROMIMAGE.bin + + The above line loads the 'pagezero.hex' file at the exact + addresses specified in the file; however, the 'image.hex' file + is assembled at 0xD000, must run at 0xD000, but is loaded + between 0x800 <= addr < 0x2800. It is presumed that the + code will be relocated to the correct address before it is + executed. + + bin2hex -R128k romimage.bin -o image.hex + + Simple conversion from a BIN file to a HEX file. The ROM + data is limited to 128k. + + bin2hex -s 0x1000 -S 0x2000 -d 0x21000 romimage.bin \ + -o Relocated.hex + + Extract from a ROM image file all of the data between 0x1000 + and 0x1FFF, inclusive, and write to an Intel hex file for + re-loading two 64k segments higher in a future ROM. + + +(end) diff --git a/doug/doc/make.pdf b/doug/doc/make.pdf new file mode 100755 index 00000000..3e18161c Binary files /dev/null and b/doug/doc/make.pdf differ diff --git a/doug/doc/sdcc-z80-mode.png b/doug/doc/sdcc-z80-mode.png new file mode 100644 index 00000000..064b32b1 Binary files /dev/null and b/doug/doc/sdcc-z80-mode.png differ diff --git a/doug/doc/watcom-tools.pdf b/doug/doc/watcom-tools.pdf new file mode 100644 index 00000000..6d3f38c9 Binary files /dev/null and b/doug/doc/watcom-tools.pdf differ diff --git a/doug/exp/common.mak b/doug/exp/common.mak new file mode 100755 index 00000000..7430e334 --- /dev/null +++ b/doug/exp/common.mak @@ -0,0 +1,558 @@ +# mak/makebody.mfi 8/8/2011 dwg - + +# Misc other macros + +BIN = bin$(DELIM) +COM = com$(DELIM) +INC = inc$(DELIM) +LIB = lib$(DELIM) +LST = lst$(DELIM) +MAP = map$(DELIM) +OBJ = obj$(DELIM) +REF = ref$(DELIM) +ROM = rom$(DELIM) +SRC = src$(DELIM) +TMP = tmp$(DELIM) + +# CP/M-80 v2.2 Command files written in SDCC +COMFILES = $(COM)copyfile.com $(COM)fdisk.com + +# Components used by CP/M-80 v2.2 Command files +COMRELS = $(OBJ)cpm0.rel $(OBJ)cpmbdos.rel $(OBJ)cprintf.rel + +# Components of ROM image containing CP/M for SBC V2 +CPMRELS = $(OBJ)crt0.rel $(OBJ)dbgmon.rel $(OBJ)bdosb01.rel \ + $(OBJ)ccpb03.rel $(OBJ)cbios.rel + +# Components of ROM image used in test protocols +ROMRELS = $(OBJ)crt0jplp.rel $(OBJ)crt0scrm.rel + +# Components that control hardware in SBC V2 +SBCV2HW = + +# Components that control hardware in the SCSI2IDE +SCSI2IDEHW = $(OBJ)z53c80.rel + +FDISK = $(BIN)fdisk$(EXE) +DWGH2B = $(BIN)dwgh2b$(EXE) +INCFILES = $(INC)cpmbdos.h $(INC)cprintf.h $(INC)portab.h +JRCH2B = $(BIN)jrch2b$(EXE) +LOAD = $(BIN)load$(EXE) +MK = Makefile +#QUIET = @ + +# ROM images for SBC V2 and N8 +ROMFILES = $(ROM)scsiscrm.rom $(ROM)scsijplp.rom $(ROM)scsi2ide.rom $(ROM)baseline.rom $(ROM)n8.rom +SCSI2IDE = $(ROM)scsi2ide.rom + +SYSGEN = $(BIN)sysgen$(EXE) +VERIFY = $(BIN)verify$(EXE) + +# C programs compiled on host system used in build +TOOLS = $(FDISK) $(DWGH2B) $(LOAD) $(JRCH2B) $(SYSGEN) + +# Versions of 'echo' compiled on host system +ETOOLS = $(BIN)lechocr $(BIN)lecholf $(BIN)lechocrlf $(BIN)lecholfcr + +# dribdos.rel is not part of the production set yet +##TEST = dribdos.rel + +############################################################ + +#all: $(ETOOLS) $(TOOLS) $(BINFILES) $(COMFILES) $(CPMFILES) $(ROMFILES) + +#all: $(TEST) $(ROMFILES) $(COMFILES) + +roms: $(ROMFILES) +scsi2ide: $(SCSI2IDE) + +############################################################ + +# A test assembly of DRI source code for BDOS (from SIMH) +dribdos.rel: $(SRC)dribdos.s + $(QUIET)$(SDAS) $(SDASFLG) dribdos.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)dribdos.lst $(LST) + +############################################################ +############################################################ + +# Build SCSIJPLP ROM image + +$(ROM)scsijplp.rom: $(OBJ)scsijplp.bin $(MK) + $(QUIET)$(COPY) $(OBJ)scsijplp.bin $(ROM)scsijplp.rom + $(QUIET)$(DEL) $(DELFLG) scsijplp.* + +$(OBJ)scsijplp.bin: $(OBJ)scsijplp.hex $(DWGH2B) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)scsijplp + +$(OBJ)scsijplp.hex: $(OBJ)scsijplp.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)scsijplp.ihx $(OBJ)scsijplp.hex + +$(OBJ)scsijplp.ihx: $(OBJ)crt0jplp.rel $(TMP)scsijplp.arf $(MK) + $(QUIET)$(COPY) $(TMP)scsijplp.arf $(TMP)scsijplp.lk + $(QUIET)$(COPY) $(TMP)scsijplp.arf $(TMP)scsijplp.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)scsijplp.lnk + $(QUIET)$(COPY) $(COPYFLG) scsijplp.ihx $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) scsijplp.map $(MAP) + +######################################################### +# Dynamically generate linker control file for scsi2ide # +# (now uses the macro controlled ECHO feature # +######################################################### +$(TMP)scsijplp.arf: $(MK) + $(ECHO) -mjx > $(TMP)scsijplp.arf + $(ECHO) -i scsijplp.ihx >> $(TMP)scsijplp.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)scsijplp.arf + $(ECHO) -l z80 >> $(TMP)scsijplp.arf + $(ECHO) $(OBJ)crt0jplp.rel >> $(TMP)scsijplp.arf + $(ECHO) -e >> $(TMP)scsijplp.arf + +############################################################ +############################################################ + +# Build SCSISCRM ROM image + +$(ROM)scsiscrm.rom: $(OBJ)scsiscrm.bin $(MK) + $(QUIET)$(COPY) $(OBJ)scsiscrm.bin $(ROM)scsiscrm.rom + $(QUIET)$(DEL) $(DELFLG) scsiscrm.* + +$(OBJ)scsiscrm.bin: $(OBJ)scsiscrm.hex $(DWGH2B) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)scsiscrm + +$(OBJ)scsiscrm.hex: $(OBJ)scsiscrm.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)scsiscrm.ihx $(OBJ)scsiscrm.hex + +$(OBJ)scsiscrm.ihx: $(OBJ)crt0scrm.rel $(TMP)scsiscrm.arf $(MK) + $(QUIET)$(COPY) $(TMP)scsiscrm.arf $(TMP)scsiscrm.lk + $(QUIET)$(COPY) $(TMP)scsiscrm.arf $(TMP)scsiscrm.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)scsiscrm.lnk + $(QUIET)$(COPY) $(COPYFLG) scsiscrm.ihx $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) scsiscrm.map $(MAP) + +######################################################### +# Dynamically generate linker control file for scsiscrm # +# (now uses the macro controlled ECHO feature # +######################################################### +$(TMP)scsiscrm.arf: $(MK) + $(ECHO) -mjx > $(TMP)scsiscrm.arf + $(ECHO) -i scsiscrm.ihx >> $(TMP)scsiscrm.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)scsiscrm.arf + $(ECHO) -l z80 >> $(TMP)scsiscrm.arf + $(ECHO) $(OBJ)crt0scrm.rel >> $(TMP)scsiscrm.arf + $(ECHO) -e >> $(TMP)scsiscrm.arf + +############################################################ +############################################################ + +# Build SCSI2IDE ROM image + +$(ROM)scsi2ide.rom: $(OBJ)scsi2ide.bin $(MK) + $(QUIET)$(COPY) $(OBJ)scsi2ide.bin $(ROM)scsi2ide.rom + $(QUIET)$(DEL) $(DELFLG) scsi2ide.* + +$(OBJ)scsi2ide.bin: $(OBJ)scsi2ide.hex $(DWGH2B) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)scsi2ide + +$(OBJ)scsi2ide.hex: $(OBJ)scsi2ide.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)scsi2ide.ihx $(OBJ)scsi2ide.hex + +$(OBJ)scsi2ide.ihx: $(CPMRELS) $(SCSI2IDEHW) $(OBJ)scsi2ide.rel $(TMP)scsi2ide.arf $(MK) + $(QUIET)$(COPY) $(TMP)scsi2ide.arf $(TMP)scsi2ide.lk + $(QUIET)$(COPY) $(TMP)scsi2ide.arf $(TMP)scsi2ide.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)scsi2ide.lnk + $(QUIET)$(COPY) $(COPYFLG) scsi2ide.ihx $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) scsi2ide.map $(MAP) + +######################################################### +# Dynamically generate linker control file for scsi2ide # +# (now uses the macro controlled ECHO feature # +######################################################### +$(TMP)scsi2ide.arf: $(MK) + $(ECHO) -mjx > $(TMP)scsi2ide.arf + $(ECHO) -i scsi2ide.ihx >> $(TMP)scsi2ide.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)scsi2ide.arf + $(ECHO) -l z80 >> $(TMP)scsi2ide.arf +# $(ECHO) -b _CCPB03 = 0xD000 >> $(TMP)scsi2ide.arf +# $(ECHO) -b _BDOSB01 = 0xD800 >> $(TMP)scsi2ide.arf +# $(ECHO) -b _CBIOS = 0xE600 >> $(TMP)scsi2ide.arf +# $(ECHO) -b _DBGMON = 0x8000 >> $(TMP)scsi2ide.arf + $(ECHO) $(OBJ)crt0.rel >> $(TMP)scsi2ide.arf + $(ECHO) $(OBJ)scsi2ide.rel >> $(TMP)scsi2ide.arf +# $(ECHO) $(OBJ)dbgmon.rel >> $(TMP)scsi2ide.arf +# $(ECHO) $(OBJ)ccpb03.rel >> $(TMP)scsi2ide.arf +# $(ECHO) $(OBJ)bdosb01.rel >> $(TMP)scsi2ide.arf +# $(ECHO) $(OBJ)cbios.rel >> $(TMP)scsi2ide.arf + $(ECHO) -e >> $(TMP)scsi2ide.arf + +######################################################## +# Compile C portion of the scsi2ide EEPROM Image +$(OBJ)scsi2ide.rel: $(SRC)scsi2ide.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) -c $(SRC)scsi2ide.c + $(QUIET)$(COPY) $(COPYFLG) scsi2ide.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) scsi2ide.lst $(LST) + + +############################################################ +############################################################ + +# Build SBC V2 ROM image + +$(ROM)baseline.rom: $(OBJ)baseline.bin $(MK) + $(QUIET)$(COPY) $(OBJ)baseline.bin $(ROM)baseline.rom + $(QUIET)$(DEL) $(DELFLG) baseline.* + +$(OBJ)baseline.bin: $(OBJ)baseline.hex $(DWGH2B) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)baseline + +$(OBJ)baseline.hex: $(OBJ)baseline.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)baseline.ihx $(OBJ)baseline.hex + +$(OBJ)baseline.ihx: $(CPMRELS) $(SBCV2HW) $(OBJ)baseline.rel $(TMP)baseline.arf $(MK) + $(QUIET)$(COPY) $(TMP)baseline.arf $(TMP)baseline.lk + $(QUIET)$(COPY) $(TMP)baseline.arf $(TMP)baseline.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)baseline.lnk + $(QUIET)$(COPY) $(COPYFLG) baseline.ihx $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) baseline.map $(MAP) + +######################################################### +# Dynamically generate linker control file for baseline # +# (now uses the macro controlled ECHO feature # +######################################################### +$(TMP)baseline.arf: $(MK) + $(ECHO) -mjx > $(TMP)baseline.arf + $(ECHO) -i baseline.ihx >> $(TMP)baseline.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)baseline.arf + $(ECHO) -l z80 >> $(TMP)baseline.arf + $(ECHO) -b _CCPB03 = 0xD000 >> $(TMP)baseline.arf + $(ECHO) -b _BDOSB01 = 0xD800 >> $(TMP)baseline.arf + $(ECHO) -b _CBIOS = 0xE600 >> $(TMP)baseline.arf + $(ECHO) -b _DBGMON = 0x8000 >> $(TMP)baseline.arf + $(ECHO) $(OBJ)crt0.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)baseline.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)dbgmon.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)ccpb03.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)bdosb01.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)cbios.rel >> $(TMP)baseline.arf + $(ECHO) -e >> $(TMP)baseline.arf + +######################################################## +# Compile C portion of the Baseline PROM Image +$(OBJ)baseline.rel: $(SRC)baseline.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) -c $(SRC)baseline.c + $(QUIET)$(COPY) $(COPYFLG) baseline.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) baseline.lst $(LST) + +############################################################ + +# Build N8 ROM image + +# +# Save the resulting merged image in the Rom folder +# +$(ROM)n8.rom: $(OBJ)n8-romim.bin $(MK) + $(QUIET)$(COPY) $(OBJ)n8-romim.bin $(ROM)n8.rom + $(QUIET)$(DEL) $(DELFLG) n8.* + +# +# Convert the Intel hex file into a binary, similar +# to the results of the "copy /B ..." +# +$(OBJ)n8-romim.bin: $(OBJ)sysimage.hex $(REF)n8-romim.ref $(SYSGEN) $(HEX2BIN) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)sysimage + $(QUIET)$(COPY) $(REF)n8-romim.ref $(OBJ)n8-romim.bin + $(QUIET)$(SYSGEN) -i $(OBJ)sysimage.bin $(OBJ)n8-romim.bin + +# +# Take the output of the linker and rename to the more +# recognizable .hex form and the expected name "sysimage.hex" +# +$(OBJ)sysimage.hex: $(OBJ)n8.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)n8.ihx $(OBJ)sysimage.hex + +# +# Combine the independently assembled components into one piece +# and output Intel hex file (ihx) +# +$(OBJ)n8.ihx: $(OBJ)loadern8.rel $(OBJ)dbgmon.rel $(OBJ)ccpb03.rel $(OBJ)bdosb01.rel $(OBJ)cbiosn8.rel $(TMP)n8.arf $(MK) + $(QUIET)$(COPY) $(TMP)n8.arf $(TMP)n8.lk + $(QUIET)$(COPY) $(TMP)n8.arf $(TMP)n8.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)n8.lnk + $(QUIET)$(COPY) $(COPYFLG) n8.ihx $(OBJ)n8.ihx + $(QUIET)$(COPY) $(COPYFLG) n8.map $(MAP) + +$(OBJ)cbiosn8.rel: $(SRC)cbiosn8.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)cbiosn8.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cbiosn8.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cbiosn8.lst $(LST) + +$(OBJ)loadern8.rel: $(SRC)loadern8.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)loadern8.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)loadern8.rel $(OBJ) + $(QUIET)$(COPY $(COPYFLG) $(SRC)loadern8.lst $(LST) + +######################################################## +# Dynamically generate the linker control file for N8 # +# Now uses the macro controlled ECHO feature # +######################################################## +$(TMP)n8.arf: Makefile + $(ECHO) -mjx > $(TMP)n8.arf + $(ECHO) -i n8.ihx >> $(TMP)n8.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)n8.arf + $(ECHO) -l z80 >> $(TMP)n8.arf + $(ECHO) -b _CCPB03 = 0x0900 >> $(TMP)n8.arf + $(ECHO) -b _BDOSB01 = 0x1100 >> $(TMP)n8.arf + $(ECHO) -b _CBIOS = 0x1f00 >> $(TMP)n8.arf + $(ECHO) $(OBJ)loadern8.rel >> $(TMP)n8.arf + $(ECHO) $(OBJ)dbgmon.rel >> $(TMP)n8.arf + $(ECHO) $(OBJ)ccpb03.rel >> $(TMP)n8.arf + $(ECHO) $(OBJ)bdosb01.rel >> $(TMP)n8.arf + $(ECHO) $(OBJ)cbiosn8.rel >> $(TMP)n8.arf + $(ECHO) -e >> $(TMP)n8.arf + +############################################################ + +# Hardware specific assemblies (most likely used by BIOS's) + +# +# Assemble hardware control code for the Zilog Z53C8003V5C +# +$(OBJ)z53c80.rel: $(SRC)z53c80.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) $(SRC)z53c80.c + $(QUIET)$(COPY) $(COPYFLG) z53c80.rel $(OBJ) + $(QUIET)$(DEL) $(DELFLG) z53c80.* + +# +# Compile ersatz printf routine for use in CP/M-80 command files +# +$(OBJ)cprintf.rel: $(SRC)cprintf.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) $(SRC)cprintf.c + $(QUIET)$(COPY) $(COPYFLG) cprintf.rel obj + $(QUIET)$(DEL) $(DELFLG) cprintf.* + +############################################################ + +# Build CP/M 2.2 command files (copyfile.com, fdisk.com) + +#----------------------------------------------------------- + +$(COM)copyfile.com: $(OBJ)copyfile.com $(MK) + $(QUIET)$(COPY) $(OBJ)copyfile.com $(COM)copyfile.com + $(QUIET)$(DEL) $(DELFLG) copyfile.* + +$(OBJ)copyfile.com: $(OBJ)copyfile.hex $(LOAD) $(BINFILES) $(MK) + $(QUIET)$(LOAD) $(OBJ)copyfile + +$(OBJ)copyfile.hex: $(OBJ)copyfile.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)copyfile.ihx $(OBJ)copyfile.hex + +$(OBJ)copyfile.ihx: $(OBJ)copyfile.rel $(COMRELS) $(TMP)copyfile.arf $(MK) + $(QUIET)$(COPY) $(TMP)copyfile.arf $(TMP)copyfile.lnk + + $(QUIET)$(SDLD) $(LOPTS) -nf $(TMP)copyfile.lnk + $(QUIET)$(COPY) $(COPYFLG) copyfile.ihx obj + $(QUIET)$(COPY) $(COPYFLG) copyfile.map map + +############################################################## +# Dynamicaly create linker command file for copyfile utility # +# Now uses the macro controlled ECHO feature # +############################################################## +$(TMP)copyfile.arf: Makefile + $(ECHO) -mjx > $(TMP)copyfile.arf + $(ECHO) -i copyfile.ihx >> $(TMP)copyfile.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)copyfile.arf + $(ECHO) -l z80 >> $(TMP)copyfile.arf + $(ECHO) $(OBJ)cpm0.rel >> $(TMP)copyfile.arf + $(ECHO) $(OBJ)copyfile.rel >> $(TMP)copyfile.arf + $(ECHO) $(OBJ)cpmbdos.rel >> $(TMP)copyfile.arf + $(ECHO) $(OBJ)cprintf.rel >> $(TMP)copyfile.arf + $(ECHO) -e >> $(TMP)copyfile.arf + +$(OBJ)copyfile.rel: $(SRC)copyfile.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) $(SRC)copyfile.c + $(QUIET)$(COPY) copyfile.rel obj + $(QUIET)$(DEL) $(DELFLG) copyfile.rel + ls obj + +#----------------------------------------------------------- + +# +# Use locally compiled 'load' command to covert Intel +# hex formal file to a binary CP/M-80 command file. +# +$(COM)fdisk.com: $(OBJ)fdisk.hex $(TOOLS) $(MK) + $(QUIET)$(BIN)load $(OBJ)fdisk + $(QUIET)$(COPY) $(COPYFLG) $(OBJ)fdisk.com com + $(QUIET)$(DEL) $(DELFLG) fdisk.* + +# +# rename 'ihx' output of linker to 'hex' + +$(OBJ)fdisk.hex: $(OBJ)fdisk.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)fdisk.ihx $(OBJ)fdisk.hex + +$(OBJ)fdisk.ihx: $(OBJ)fdisk.rel $(TMP)fdisk.arf $(MK) + $(QUIET)$(COPY) $(TMP)fdisk.arf $(TMP)fdisk.lnk + $(QUIET)$(COPY) $(TMP)fdisk.arf $(TMP)fdisk.lk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)fdisk.lnk + $(QUIET)$(COPY) $(COPYFLG) fdisk.ihx $(OBJ)fdisk.ihx + $(QUIET)$(COPY) $(COPYFLG) fdisk.map map + +$(OBJ)fdisk.rel: $(SRC)fdisk.c $(INCFILES) $(MK) + $(QUIET)$(SDCC) -I inc $(SDCCFLG) $(SRC)fdisk.c + $(QUIET)$(COPY) $(COPYFLG) fdisk.rel $(OBJ) + +############################################################################ +# Dynamically created linker command file for fdisk utility (CP/M version) # +# Now uses macro controlled ECHO feature # +############################################################################ +$(TMP)fdisk.arf: $(MK) + $(ECHO) -mjx > $(TMP)fdisk.arf + $(ECHO) -i fdisk.ihx >> $(TMP)fdisk.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)fdisk.arf + $(ECHO) -l z80 >> $(TMP)fdisk.arf + $(ECHO) $(OBJ)cpm0.rel >> $(TMP)fdisk.arf + $(ECHO) $(OBJ)fdisk.rel >> $(TMP)fdisk.arf + $(ECHO) $(OBJ)cpmbdos.rel >> $(TMP)fdisk.arf + $(ECHO) $(OBJ)cprintf.rel >> $(TMP)fdisk.arf + $(ECHO) -e >> $(TMP)fdisk.arf + + +#----------------------------------------------------------- + +# Also build host version of fdisk for testing purposes + +$(BIN)fdisk$(EXE): $(SRC)fdisk.c $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)fdisk.c -o $(BIN)fdisk + +############################################################ + +# Build CP/M-80 Command File Structure Files + +$(OBJ)cpm0.rel: $(SRC)cpm0.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)cpm0.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cpm0.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cpm0.lst $(LST) + +$(OBJ)cpmbdos.rel: $(SRC)cpmbdos.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)cpmbdos.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cpmbdos.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cpmbdos.lst $(LST) + +############################################################ + +# Build ROM Image structure files + +$(OBJ)crt0.rel: $(SRC)crt0.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)crt0.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0.lst $(LST) + +$(OBJ)crt0jplp.rel: $(SRC)crt0jplp.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)crt0jplp.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0jplp.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0jplp.lst $(LST) + +$(OBJ)crt0scrm.rel: $(SRC)crt0scrm.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)crt0scrm.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0scrm.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0scrm.lst $(LST) + +$(OBJ)bdosb01.rel: $(SRC)bdosb01.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)bdosb01.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)bdosb01.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)bdosb01.lst $(LST) + +$(OBJ)ccpb03.rel: $(SRC)ccpb03.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)ccpb03.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)ccpb03.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)ccpb03.lst $(LST) + +# +# Assemble hardware control code for SBC V2 +# +$(OBJ)cbios.rel: $(SRC)cbios.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)cbios.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cbios.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cbios.lst $(LST) + +# +# Assemble a monitor program for the SBC V2 +# +$(OBJ)dbgmon.rel: $(SRC)dbgmon.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)dbgmon.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)dbgmon.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)dbgmon.lst $(LST) + +########################################################### + +# Build host based tools ( dwgh2b, jrch2b, load, verify) + +$(DWGH2B): $(SRC)dwgh2b.c $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)dwgh2b.c -o $(BIN)dwgh2b$(EXE) + +# +# Compile John Coffman's hex2bin program +# +$(JRCH2B): $(SRC)jrch2b.c $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)jrch2b.c -o $(BIN)jrch2b$(EXE) + $(QUIET)$(COPY) $(COPYFLG) $(BIN)jrch2b $(BIN)jrcb2h + +# +# Compile Doug's "load" program +# +$(LOAD): $(SRC)load.c $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)load.c -o $(BIN)load$(EXE) + +$(SYSGEN): $(SRC)sysgen.c $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)sysgen.c -o $(BIN)sysgen$(EXE) + +# +# Compile Doug's verif program that compares binary file regions +# +$(VERIFY): $(SRC)verify.c Makefile $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)verify.c -o $(BIN)verify + +$(BIN)lechocr: $(SRC)lechocr.c $(MK) +# $(QUIET)$(TCC) $(TCCFLG) $(SRC)lechocr.c -o $(BIN)lechocr + $(QUIET)$(TCC) $(TCCFLG) $(SRC)lechocr.c + $(QUIET)$(COPY) lechocr.exe $(BIN) + +$(BIN)lecholf: $(SRC)lecholf.c $(MK) +# $(QUIET)$(TCC) $(TCCFLG) $(SRC)lecholf.c -o $(BIN)lecholf + $(QUIET)$(TCC) $(TCCFLG) $(SRC)lecholf.c + $(COPY) lecholf.exe $(BIN) + +$(BIN)lechocrlf: $(SRC)lechocrlf.c $(MK) + $(QUIET)$(TCC) $(TCCFLG) $(SRC)lechocrlf.c -o $(BIN)lechocrlf + +$(BIN)lecholfcr: $(SRC)lecholfcr.c $(MK) +# $(QUIET)$(TCC) $(TCCFLG) $(SRC)lecholfcr.c -o $(BIN)lecholfcr + $(QUIET)$(TCC) $(TCCFLG) $(SRC)lecholfcr.c -o $(BIN)lecholfcr + +############################################################ + +# Builder specific utility rules + +dwginstall: + $(COPY) $(COMFILES) ~/Documents/devobox/cdrive + +############################################################ + +# +# Delete all dynamically generated files that don't need to be +# saved. +# +clean: + $(QUIET)$(DEL) $(DELFLG) *.hex *.ihx *.lst *.rel *.rst *.lnk *.lk + $(QUIET)$(DEL) $(DELFLG) *.sym *.map *.noi *.asm *.com *.ini *.bin + $(QUIET)$(DEL) $(DELFLG) obj$(DELIM)*.* + $(QUIET)$(DEL) $(DELFLG) bin$(DELIM)*.* + $(QUIET)$(DEL) $(DELFLG) com$(DELIM)*.* + $(QUIET)$(DEL) $(DELFLG) rom$(DELIM)*.* + $(QUIET)$(DEL) $(DELFLG) tmp$(DELIM)*.* + $(QUIET)$(DEL) $(DELFLG) map$(DELIM)*.* + $(QUIET)$(DEL) $(DELFLG) lst$(DELIM)*.* + +################## +# eof - Makefile # +################## diff --git a/doug/exp/makefile.mac b/doug/exp/makefile.mac new file mode 100755 index 00000000..506bc8c0 --- /dev/null +++ b/doug/exp/makefile.mac @@ -0,0 +1,26 @@ +# ubios/makefile.mac 8/8/2011 dwg - + +DELIM = / +SPREFIX = /Developer/sdcc +SDAS = $(SPREFIX)/bin/sdasz80 +SDASFLG = -plosff -Iinc +SDCC = $(SPREFIX)/bin/sdcc +SDCCFLG = -c -mz80 -D__SDCC__=1 -I inc +SDCCLIB = $(SPREFIX)/share/sdcc/lib/z80 +SDLD = $(SPREFIX)/bin/sdldz80 +SDLDFLG = +TPREFIX = +TCC = gcc +TCCFLG = -I inc +COPY = cp +DEL = rm +DELFLG = -f +# use native ECHO o Mac OS X +ECHO = echo +REN = mv +EXE = + +include common.mak + + + diff --git a/doug/exp/makefile.win b/doug/exp/makefile.win new file mode 100755 index 00000000..c324b33d --- /dev/null +++ b/doug/exp/makefile.win @@ -0,0 +1,24 @@ + +DELIM = \ +SDRIVE = C: +SPREFIX = $(SDRIVE)\sdcc +SDAS = $(SPREFIX)\bin\sdasz80 +SDASFLG = -plosff +SDCC = $(SPREFIX)\bin\sdcc +SDCCFLG = -c -mz80 -D__SDCC__=1 -I inc +SDCCLIB = $(SPREFIX)\lib\z80 +SDLD = $(SPREFIX)\bin\sdldz80 +SDLDFLG = +TPREFIX = +TCC = gcc +TCCOPT = -I inc +COPY = copy +DEL = erase +DELFLG = /Q +REN = rename +ECHO = $(BIN)lecholf +EXE = .exe + +.include common.mak + + diff --git a/doug/inc/agm1264f.h b/doug/inc/agm1264f.h new file mode 100755 index 00000000..0adab14d --- /dev/null +++ b/doug/inc/agm1264f.h @@ -0,0 +1,95 @@ +/* + * + * agm1264f.h 5/14/2011 dwg - + * 8 lines of 21 characters + * + */ + +/* + + 1 2 + 123456789012345678901 + --------------------- +1 |1234 11223344 1234 | +2 | | +3 | | +4 | | +5 | | +6 | | +7 | | +8 | | + --------------------- + +/* This is a 7x5 character layout showing how much text data can be display on the agm1264f + 1 1 1 + 1 2 3 4 5 6 7 8 9 0 1 2 + 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567 + --------------------------------------------------------------------------------------------------------------------------------- + 0 | 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 1 | 2 | + 2 | 3 | + 3 | 4 | + 4 | 5 | + 5 | 6 | + 6 | 72345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 7 | | + 8 | 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 9 | 2 | +10 | 3 | + 1 | 4 | + 2 | 5 | + 3 | 6 | + 4 | 72345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 5 | | + 6 | 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 7 | 2 | + 8 | 3 | + 9 | 4 | +20 | 5 | + 1 | 6 | + 2 | 72345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 3 | | + 4 | 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 5 | 2 | + 6 | 3 | | + 7 | 4 | + 8 | 5 | + 9 | 6 | +30 | 72345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 1 | | + 2 | 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 3 | 2 | + 4 | 3 | + 5 | 4 | + 6 | 5 | + 7 | 6 | + 8 | 72345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 9 | | +40 | 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 1 | 2 | + 2 | 3 | + 3 | 4 | + 4 | 5 | + 5 | 6 | + 6 | 72345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 7 | | + 8 | 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 9 | 2 | +50 | 3 | + 1 | 4 | + 2 | 5 | + 3 | 6 | + 4 | 72345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 5 | | + 6 | 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 7 | 2 | + 8 | 3 | + 9 | 4 | +60 | 5 | + 1 | 6 | + 2 | 72345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 | + 3 | | + --------------------------------------------------------------------------------------------------------------------------------- +*/ + + diff --git a/doug/inc/cpmbdos.h b/doug/inc/cpmbdos.h new file mode 100755 index 00000000..ce3f2451 --- /dev/null +++ b/doug/inc/cpmbdos.h @@ -0,0 +1,89 @@ +/* + * CP/M-80 v2.2 BDOS Interfaces + * Copyright (C) Douglas W. Goodall + * For Non-Commercial use by N8VEM + * 5/10/2011 dwg - initial version +*/ +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#define C_READ 1 +#define C_WRITE 2 +#define A_READ 3 +#define A_WRITE 4 +#define L_WRITE 5 +#define C_RAWIO 6 +#define GETIOBYTE 7 +#define SETIOBYTE 8 +#define C_WRITESTR 9 +#define C_READSTR 10 +#define F_OPEN 15 +#define F_CLOSE 16 +#define F_DELETE 19 +#define F_READ 20 +#define F_WRITE 21 +#define F_MAKE 22 +#define F_RENAME 23 +#define DRV_LOGINVEC 24 +#define DRV_GET 25 +#define F_DMAOFF 26 +#define DRV_ALLOCVEC 27 +#define DRV_SETRO 28 +#define DRV_ROVEC 29 +#define F_ATTRIB 30 +#define DRV_DPB 31 +#define F_USERNUM 32 +#define F_READRAND 33 +#define F_WRITERAND 34 +#define F_SIZE 35 +#define F_RANDREC 36 +#define DRV_RESET 37 +#define F_WRITEZF 40 + + +struct BDOSCALL { + unsigned char func8; + unsigned int parm16; +}; + +unsigned char cpmbdos(struct BDOSCALL *p); + +struct FCB { + unsigned char drive; + char filename[8]; + char filetype[3]; + unsigned char ex; + unsigned char s1; + unsigned char s2; + unsigned char rc; + unsigned char al[16]; + unsigned char cr; + unsigned char r0; + unsigned char r1; + unsigned char r2; +}; + +struct READSTR { + unsigned char size; + unsigned char len; + char bytes[80]; + } rsbuffer; + +struct BDOSCALL readstr = { C_READSTR, { (unsigned int)&rsbuffer } }; + +char * mygets(char *p) +{ + memset(rsbuffer.bytes,0,sizeof(rsbuffer.bytes)); + rsbuffer.size = sizeof(rsbuffer.bytes); + rsbuffer.len = 0; + cpmbdos(&readstr); + rsbuffer.bytes[rsbuffer.len] = '\n'; + strcpy(p,rsbuffer.bytes); + return p; +} + +#define gets mygets + +/*****************/ +/* eof - cpm80.h */ +/*****************/ diff --git a/doug/inc/cprintf.h b/doug/inc/cprintf.h new file mode 100755 index 00000000..925275e3 --- /dev/null +++ b/doug/inc/cprintf.h @@ -0,0 +1,7 @@ +/* cprintf.h */ + +int cprintf(const char * fmt, ...); + +#define printf cprintf + + diff --git a/doug/inc/diskio.h b/doug/inc/diskio.h new file mode 100755 index 00000000..2235f5b3 --- /dev/null +++ b/doug/inc/diskio.h @@ -0,0 +1,28 @@ +/* + * diskio.h + * + */ + +__sfr __at (DISKIO_IDE + 0x00) pIDELO; +__sfr __at (DISKIO_IDE + 0x01) pIDEERR; +__sfr __at (DISKIO_IDE + 0x02) pIDESECTC; +__sfr __at (DISKIO_IDE + 0x03) pIDESECTN; +__sfr __at (DISKIO_IDE + 0x04) pIDECYLLO; +__sfr __at (DISKIO_IDE + 0x05) pIDECYLHI; +__sfr __at (DISKIO_IDE + 0x06) pIDEHEAD; +__sfr __at (DISKIO_IDE + 0x07) pIDESTTS; +__sfr __at (DISKIO_IDE + 0x08) pIDEHI; +__sfr __at (DISKIO_IDE + 0x0E) pIDECTRL; + +__sfr __at (DISKIO_FLP + 0x06) pFMSR; +__sfr __at (DISKIO_FLP + 0x07) pFDATA; +__sfr __at (DISKIO_FLP + 0x0A) pFLATCH; +__sfr __at (DISKIO_FLP + 0x0C) pFDMA; + +/* + * + * eof - diskio.h + * + */ + + diff --git a/doug/inc/ds1302.h b/doug/inc/ds1302.h new file mode 100755 index 00000000..10ea3685 --- /dev/null +++ b/doug/inc/ds1302.h @@ -0,0 +1,7 @@ +/* + * + * ds1302 Dallas Real Time Clock module + * + */ + + diff --git a/doug/inc/i8255.h b/doug/inc/i8255.h new file mode 100755 index 00000000..458d8349 --- /dev/null +++ b/doug/inc/i8255.h @@ -0,0 +1,15 @@ +/* + * i8255.h Intel 8255 + * + */ + + +void uart_init(U8 baud); +U8 uart_conin(void); +void uart_conout(U8 data); + +/* + * + * eof - i8255.h + * + */ diff --git a/doug/inc/jrctypes.h b/doug/inc/jrctypes.h new file mode 100755 index 00000000..c97ed7eb --- /dev/null +++ b/doug/inc/jrctypes.h @@ -0,0 +1,16 @@ +#ifndef __MYTYPES_H +#define __MYTYPES_H 1 + +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned long dword; + + +#ifdef __SDCC__ +#define outp(port,byte) port = (byte) +#define inp(port) (port) +#endif + +#define nelem(x) (sizeof(x)/sizeof(x[0])) + +#endif /* __MYTYPES_H */ diff --git a/doug/inc/ns16550.h b/doug/inc/ns16550.h new file mode 100755 index 00000000..40298323 --- /dev/null +++ b/doug/inc/ns16550.h @@ -0,0 +1,15 @@ +/* + * n16550.h National 16550 + * + */ + +#define UART_DLAB 0x80 +#define UART_BAUD_9600 12 +#define UART_RDA 0x01 +#define UART_TBE 0x20 + +/* + * + * eof - n16550.h + * + */ diff --git a/doug/inc/ns16550.inc b/doug/inc/ns16550.inc new file mode 100755 index 00000000..ba166726 --- /dev/null +++ b/doug/inc/ns16550.inc @@ -0,0 +1,8 @@ +; ns16550.inc 8/7/2011 dwg - National 16550 + +UART_DLAB = 0x80 +UART_BAUD_9600 = 12 +UART_RDA = 0x01 +UART_TBE = 0x20 + +; eof - ns16550.inc diff --git a/doug/inc/portab.h b/doug/inc/portab.h new file mode 100755 index 00000000..5ad24e41 --- /dev/null +++ b/doug/inc/portab.h @@ -0,0 +1,12 @@ +/************/ +/* portab.h */ +/************/ + +#define TRUE 1 +#define FALSE 0 + +#define U8 unsigned char + +/******************/ +/* eof - portab.h */ +/******************/ diff --git a/doug/inc/sbcv2.h b/doug/inc/sbcv2.h new file mode 100755 index 00000000..d6607a5d --- /dev/null +++ b/doug/inc/sbcv2.h @@ -0,0 +1,52 @@ +/* + * sbcv2.h - Macros describing the N8VEM SBC V2 + * + */ + +#define SBCV2 + +/* set i/o base to first block of 32 addresses + possible are 0x00 0x20 0x40 0x60 0x80 0xA0 0xC0 0xE0 + depending oon setting of dip switches on board +*/ + +#define SBCV2_IO_BASE 0x00 +#define UART_IO_BASE ( SBCV2_IO_BASE + 0x68 ) + +__sfr __at (UART_IO_BASE+0) rUART_RBR; +__sfr __at (UART_IO_BASE+0) wUART_THR; +__sfr __at (UART_IO_BASE+0) wUART_DIV_LO; +__sfr __at (UART_IO_BASE+1) wUART_DIV_HI; + +__sfr __at (UART_IO_BASE+1) wUART_IER; +__sfr __at (UART_IO_BASE+2) rUART_IIR; +__sfr __at (UART_IO_BASE+3) wUART_LCR; +__sfr __at (UART_IO_BASE+4) wUART_MCR; +__sfr __at (UART_IO_BASE+5) rUART_LSR; +__sfr __at (UART_IO_BASE+6) rUART_MSR; +__sfr __at (UART_IO_BASE+7) wUART_FCR; + + +#define DISKIO_IDE 0x20 + +#define DISKIO_FLP 0x30 + +#define PPORT 0x60 + +#define MPCL 0x70 +__sfr __at (MPCL + 0x08) pMPCL_RAM; +__sfr __at (MPCL + 0x0c) pMPCL_ROM; + +#define RAMTARG_CPM 0x2000 +#define ROMSTART_CPM 0x0000 +#define CCPSIZ_CPM 0x2000 + +#define LOADER_ORG 0x0000 +#define CPM_ORG 0x0A00 +#define MON_ORG 0x3800 +#define ROM_G 0x5000 +#define ROM_F 0x8000 +/* +#define VDU_DRV 0xF8100 +*/ + diff --git a/doug/inc/scsi2ide.h b/doug/inc/scsi2ide.h new file mode 100755 index 00000000..6f8684c4 --- /dev/null +++ b/doug/inc/scsi2ide.h @@ -0,0 +1,47 @@ +/* + * + * scsi2ide.h - Macros describing the N8VEM SCSI2IDE + * Friday July 29, 2011 Douglas W. Goodall + * + */ + +#define SCSI2IDE + +/* set i/o base to first block of 32 addresses + possible are 0x00 0x20 0x40 0x60 0x80 0xA0 0xC0 0xE0 + depending oon setting of dip switches on board +*/ + +#define SCSI2IDE_IO_BASE 0x00 + +#define IDE_IO_BASE ( SCSI2IDE_IO_BASE + 0 ) +#define SCSI_IO_BASE ( SCSI2IDE_IO_BASE + 8 ) +#define UART_IO_BASE ( SCSI2IDE_IO_BASE + 16 ) +#define DACK_IO_BASE ( SCSI2IDE_IO_BASE + 24 ) + +__sfr __at (UART_IO_BASE+0) rUART_RDR; +__sfr __at (UART_IO_BASE+0) wUART_TDR; +__sfr __at (UART_IO_BASE+0) wUART_DIV_LO; +__sfr __at (UART_IO_BASE+1) wUART_DIV_HI; +__sfr __at (UART_IO_BASE+1) wUART_IER; +__sfr __at (UART_IO_BASE+2) rUART_IIR; +__sfr __at (UART_IO_BASE+3) wUART_LCR; +__sfr __at (UART_IO_BASE+4) wUART_MCR; +__sfr __at (UART_IO_BASE+5) rUART_LSR; +__sfr __at (UART_IO_BASE+6) rUART_MSR; +__sfr __at (UART_IO_BASE+7) wUART_FCR; + +__sfr __at (SCSI_IO_BASE+0) rSCSI_CSCSID; +__sfr __at (SCSI_IO_BASE+0) wSCSI_OD; +__sfr __at (SCSI_IO_BASE+1) rwSCSI_IC; +__sfr __at (SCSI_IO_BASE+2) rwSCSI_M; +__sfr __at (SCSI_IO_BASE+3) rwSCSI_TC; +__sfr __at (SCSI_IO_BASE+4) rSCSI_CSCSIBS; +__sfr __at (SCSI_IO_BASE+4) wSCSI_SE; +__sfr __at (SCSI_IO_BASE+5) rSCSI_BS; +__sfr __at (SCSI_IO_BASE+5) wSCSI_SDMAS; +__sfr __at (SCSI_IO_BASE+6) rSCSI_ID; +__sfr __at (SCSI_IO_BASE+6) wSCSI_SDMATR; +__sfr __at (SCSI_IO_BASE+7) rSCSI_RPI; +__sfr __at (SCSI_IO_BASE+7) wSCSI_SDMAIR; + diff --git a/doug/inc/scsi2ide.inc b/doug/inc/scsi2ide.inc new file mode 100755 index 00000000..a3eb74af --- /dev/null +++ b/doug/inc/scsi2ide.inc @@ -0,0 +1,20 @@ +; scsi2ide.inc 8/7/2011 dwg - macros describing the N8VEM SCSI2IDE + +SCSI2IDE_IO_BASE = 0 + +UART_IO_BASE = SCSI2IDE_IO_BASE+16 + +rUART_RDR = UART_IO_BASE + 0 +wUART_TDR = UART_IO_BASE + 0 +wUART_DIV_LO = UART_IO_BASE + 0 +wUART_DIV_HI = UART_IO_BASE + 1 +wUART_IER = UART_IO_BASE + 1 +rUART_IIR = UART_IO_BASE + 2 +wUART_LCR = UART_IO_BASE + 3 +wUART_MCR = UART_IO_BASE + 4 +rUART_LSR = UART_IO_BASE + 5 +rUART_MSR = UART_IO_BASE + 6 +wUART_FCR = UART_IO_BASE + 7 + +; eof - scsi2ide.inc + diff --git a/doug/inc/z53c80.h b/doug/inc/z53c80.h new file mode 100755 index 00000000..7ef720ef --- /dev/null +++ b/doug/inc/z53c80.h @@ -0,0 +1,24 @@ +/* + * z53c80.h Zilog Z53C8003VSC + * + */ + +/* +__sfr __at (UART + 0) pPORTA; +__sfr __at (UART + 1) pPORTB; +__sfr __at (UART + 2) pPORTC; +__sfr __at (UART + 3) pCNTRL; +*/ + +void scsi_init(void); + +/* +U8 uart_conin(void); +void uart_conout(U8 data); +*/ + +/* + * + * eof - z53c80.h + * + */ diff --git a/doug/makefile.w64 b/doug/makefile.w64 new file mode 100755 index 00000000..675067bc --- /dev/null +++ b/doug/makefile.w64 @@ -0,0 +1,550 @@ +######################################################## +# Makefile for Doug's Unified BIOS 5/30/2011 # +# The BIOS and associated utilities are generated # +# using the Small Device C Compiler (SDCC) & tools # +# With multiplatform enhancements by John Coffman # +# # +# sdcc.l00 added because stupid Windoze 'echo' appends # +# a confusing SPACE to the end of every line. # +######################################################## + +##################################################### +# SPREFIX tells where the SDCC package in installed # +# The SDCC package is used to assemble Z80 portions # +# of the software such as the ROM and perhaps some # +# .COM files such as FDISK. # +##################################################### + +################################################################# +# TPREFIX tells where the host development tools are installed. # +# The host tools are used to manipulate the Z80 objects after # +# the basic assemblies and compilations have been completed. # +################################################################# + +################################################################### +# SDCC is not available on the DOS host, so something else may be # +# used at the descretion of the builder. (TASM for instance). # +################################################################### + +################################################################### +# The COPY, DEL and RENAME macros are used to customize the build # +# rules for the host enviroonment. # +################################################################### + +#------------------------------------------- +# Choose one only, then Make will work for +# your platform. + +#CFG = $(shell uname) +# Mac OS X returns 'Darwin' +# Linux returns 'Linux' + +#CFG = dos +#CFG = linux +#CFG = macosx +CFG = windows + +#------------------------------------------- + +DELIM = \ +SDRIVE = C: +SPREFIX = $(SDRIVE)\sdcc +SDAS = $(SPREFIX)\bin\sdasz80 +SDASFLG = -plosff +SDCC = $(SPREFIX)\bin\sdcc +SDCCFLG = -c -mz80 -D__SDCC__=1 -I inc +SDCCLIB = $(SPREFIX)\lib\z80 +SDLD = $(SPREFIX)\bin\sdldz80 +SDLDFLG = +TPREFIX = +TCC = gcc +TCCOPT = -I inc +COPY = copy +DEL = erase +DELFLG = /Q +REN = rename + +# This is special handling for John Coffman to get around funky windows +# behavior where echo adds spurious space o end f line +# ECHO = { lecho | lechocr | lecholf | lechocrlf | lecholfcr } + +#ECHO = $(BIN)$(DELIM)lechocr +ECHO = $(BIN)lecholf + +EXE = .exe + + +#------------------------------------------- +############################################################ + +# Misc other macros + +BIN = bin$(DELIM) +COM = com$(DELIM) +INC = inc$(DELIM) +LIB = lib$(DELIM) +LST = lst$(DELIM) +MAP = map$(DELIM) +OBJ = obj$(DELIM) +REF = ref$(DELIM) +ROM = rom$(DELIM) +SRC = src$(DELIM) +TMP = tmp$(DELIM) + +# CP/M-80 v2.2 Command files written in SDCC +COMFILES = $(COM)copyfile.com $(COM)fdisk.com + +# Components used by CP/M-80 v2.2 Command files +COMRELS = $(OBJ)cpm0.rel $(OBJ)cpmbdos.rel $(OBJ)cprintf.rel + +# Components of ROM image containing CP/M for SBC V2 +CPMRELS = $(OBJ)crt0.rel $(OBJ)dbgmon.rel $(OBJ)bdosb01.rel $(OBJ)ccpb03.rel $(OBJ)cbios.rel + +# Components that control hardware in SBC V2 +SBCV2HW = + +# Components that control hardware in the SCSI2IDE +SCSI2IDEHW = $(OBJ)z53c80.rel + +FDISK = $(BIN)fdisk$(EXE) +DWGH2B = $(BIN)dwgh2b$(EXE) +INCFILES = $(INC)cpmbdos.h $(INC)cprintf.h $(INC)portab.h +JRCH2B = $(BIN)jrch2b$(EXE) +LOAD = $(BIN)load$(EXE) +MK = Makefile +#QUIET = @ + +# ROM images for SBC V2 and N8 +ROMFILES = $(ROM)scsi2ide.rom $(ROM)baseline.rom $(ROM)n8.rom +SCSI2IDE = $(ROM)scsi2ide.rom + +SYSGEN = $(BIN)sysgen$(EXE) +VERIFY = $(BIN)verify$(EXE) + +# C programs compiled on host system used in build +TOOLS = $(FDISK) $(DWGH2B) $(LOAD) $(JRCH2B) $(SYSGEN) + +# Versions of 'echo' compiled on host system +ETOOLS = $(BIN)lechocr.exe $(BIN)lecholf.exe $(BIN)lechocrlf.exe $(BIN)lecholfcr.exe + +# dribdos.rel is not part of the production set yet +##TEST = dribdos.rel + +############################################################ + +all: $(ETOOLS) $(TOOLS) $(BINFILES) $(COMFILES) $(CPMFILES) $(ROMFILES) + +#all: $(TEST) $(ROMFILES) $(COMFILES) + +etools: $(ETOOLS) +roms: $(ROMFILES) +scsi2ide: $(SCSI2IDE) + +############################################################ + +# A test assembly of DRI source code for BDOS (from SIMH) +dribdos.rel: $(SRC)dribdos.s + $(QUIET)$(SDAS) $(SDASFLG) dribdos.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)dribdos.lst $(LST) + +############################################################ +############################################################ + +# Build SCSI2IDE ROM image + +$(ROM)scsi2ide.rom: $(OBJ)scsi2ide.bin $(MK) + $(QUIET)$(COPY) $(OBJ)scsi2ide.bin $(ROM)scsi2ide.rom + $(QUIET)$(DEL) $(DELFLG) scsi2ide.* + +$(OBJ)scsi2ide.bin: $(OBJ)scsi2ide.hex $(DWGH2B) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)scsi2ide + +$(OBJ)scsi2ide.hex: $(OBJ)scsi2ide.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)scsi2ide.ihx $(OBJ)scsi2ide.hex + +$(OBJ)scsi2ide.ihx: $(CPMRELS) $(SCSI2IDEHW) $(OBJ)scsi2ide.rel $(TMP)scsi2ide.arf $(MK) + $(QUIET)$(COPY) $(TMP)scsi2ide.arf $(TMP)scsi2ide.lk + $(QUIET)$(COPY) $(TMP)scsi2ide.arf $(TMP)scsi2ide.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)scsi2ide.lnk + $(QUIET)$(COPY) $(COPYFLG) scsi2ide.ihx $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) scsi2ide.map $(MAP) + +######################################################### +# Dynamically generate linker control file for scsi2ide # +# (now uses the macro controlled ECHO feature # +######################################################### +$(TMP)scsi2ide.arf: $(MK) + $(ECHO) -mjx > $(TMP)scsi2ide.arf + $(ECHO) -i scsi2ide.ihx >> $(TMP)scsi2ide.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)scsi2ide.arf + $(ECHO) -l z80 >> $(TMP)scsi2ide.arf +# $(ECHO) -b _CCPB03 = 0xD000 >> $(TMP)scsi2ide.arf +# $(ECHO) -b _BDOSB01 = 0xD800 >> $(TMP)scsi2ide.arf +# $(ECHO) -b _CBIOS = 0xE600 >> $(TMP)scsi2ide.arf +# $(ECHO) -b _DBGMON = 0x8000 >> $(TMP)scsi2ide.arf + $(ECHO) $(OBJ)crt0.rel >> $(TMP)scsi2ide.arf + $(ECHO) $(OBJ)scsi2ide.rel >> $(TMP)scsi2ide.arf +# $(ECHO) $(OBJ)dbgmon.rel >> $(TMP)scsi2ide.arf +# $(ECHO) $(OBJ)ccpb03.rel >> $(TMP)scsi2ide.arf +# $(ECHO) $(OBJ)bdosb01.rel >> $(TMP)scsi2ide.arf +# $(ECHO) $(OBJ)cbios.rel >> $(TMP)scsi2ide.arf + $(ECHO) -e >> $(TMP)scsi2ide.arf + +######################################################## +# Compile C portion of the scsi2ide EEPROM Image +$(OBJ)scsi2ide.rel: $(SRC)scsi2ide.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) -c $(SRC)scsi2ide.c + $(QUIET)$(COPY) $(COPYFLG) scsi2ide.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) scsi2ide.lst $(LST) + + +############################################################ +############################################################ + +# Build SBC V2 ROM image + +$(ROM)baseline.rom: $(OBJ)baseline.bin $(MK) + $(QUIET)$(COPY) $(OBJ)baseline.bin $(ROM)baseline.rom + $(QUIET)$(DEL) $(DELFLG) baseline.* + +$(OBJ)baseline.bin: $(OBJ)baseline.hex $(DWGH2B) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)baseline + +$(OBJ)baseline.hex: $(OBJ)baseline.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)baseline.ihx $(OBJ)baseline.hex + +$(OBJ)baseline.ihx: $(CPMRELS) $(SBCV2HW) $(OBJ)baseline.rel $(TMP)baseline.arf $(MK) + $(QUIET)$(COPY) $(TMP)baseline.arf $(TMP)baseline.lk + $(QUIET)$(COPY) $(TMP)baseline.arf $(TMP)baseline.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)baseline.lnk + $(QUIET)$(COPY) $(COPYFLG) baseline.ihx $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) baseline.map $(MAP) + +######################################################### +# Dynamically generate linker control file for baseline # +# (now uses the macro controlled ECHO feature # +######################################################### +$(TMP)baseline.arf: $(MK) + $(ECHO) -mjx > $(TMP)baseline.arf + $(ECHO) -i baseline.ihx >> $(TMP)baseline.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)baseline.arf + $(ECHO) -l z80 >> $(TMP)baseline.arf + $(ECHO) -b _CCPB03 = 0xD000 >> $(TMP)baseline.arf + $(ECHO) -b _BDOSB01 = 0xD800 >> $(TMP)baseline.arf + $(ECHO) -b _CBIOS = 0xE600 >> $(TMP)baseline.arf + $(ECHO) -b _DBGMON = 0x8000 >> $(TMP)baseline.arf + $(ECHO) $(OBJ)crt0.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)baseline.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)dbgmon.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)ccpb03.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)bdosb01.rel >> $(TMP)baseline.arf + $(ECHO) $(OBJ)cbios.rel >> $(TMP)baseline.arf + $(ECHO) -e >> $(TMP)baseline.arf + +######################################################## +# Compile C portion of the Baseline PROM Image +$(OBJ)baseline.rel: $(SRC)baseline.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) -c $(SRC)baseline.c + $(QUIET)$(COPY) $(COPYFLG) baseline.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) baseline.lst $(LST) + +############################################################ + +# Build N8 ROM image + +# +# Save the resulting merged image in the Rom folder +# +$(ROM)n8.rom: $(OBJ)n8-romim.bin $(MK) + $(QUIET)$(COPY) $(OBJ)n8-romim.bin $(ROM)n8.rom + $(QUIET)$(DEL) $(DELFLG) n8.* + +# +# Convert the Intel hex file into a binary, similar +# to the results of the "copy /B ..." +# +$(OBJ)n8-romim.bin: $(OBJ)sysimage.hex $(REF)n8-romim.ref $(SYSGEN) $(HEX2BIN) $(MK) + $(QUIET)$(DWGH2B) $(OBJ)sysimage + $(QUIET)$(COPY) $(REF)n8-romim.ref $(OBJ)n8-romim.bin + $(QUIET)$(SYSGEN) -i $(OBJ)sysimage.bin $(OBJ)n8-romim.bin + +# +# Take the output of the linker and rename to the more +# recognizable .hex form and the expected name "sysimage.hex" +# +$(OBJ)sysimage.hex: $(OBJ)n8.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)n8.ihx $(OBJ)sysimage.hex + +# +# Combine the independently assembled components into one piece +# and output Intel hex file (ihx) +# +$(OBJ)n8.ihx: $(OBJ)loadern8.rel $(OBJ)dbgmon.rel $(OBJ)ccpb03.rel $(OBJ)bdosb01.rel $(OBJ)cbiosn8.rel $(TMP)n8.arf $(MK) + $(QUIET)$(COPY) $(TMP)n8.arf $(TMP)n8.lk + $(QUIET)$(COPY) $(TMP)n8.arf $(TMP)n8.lnk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)n8.lnk + $(QUIET)$(COPY) $(COPYFLG) n8.ihx $(OBJ)n8.ihx + $(QUIET)$(COPY) $(COPYFLG) n8.map $(MAP) + +$(OBJ)cbiosn8.rel: $(SRC)cbiosn8.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)cbiosn8.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cbiosn8.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cbiosn8.lst $(LST) + +$(OBJ)loadern8.rel: $(SRC)loadern8.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)loadern8.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)loadern8.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)loadern8.lst $(LST) + +######################################################## +# Dynamically generate the linker control file for N8 # +# Now uses the macro controlled ECHO feature # +######################################################## +$(TMP)n8.arf: Makefile + $(ECHO) -mjx > $(TMP)n8.arf + $(ECHO) -i n8.ihx >> $(TMP)n8.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)n8.arf + $(ECHO) -l z80 >> $(TMP)n8.arf + $(ECHO) -b _CCPB03 = 0x0900 >> $(TMP)n8.arf + $(ECHO) -b _BDOSB01 = 0x1100 >> $(TMP)n8.arf + $(ECHO) -b _CBIOS = 0x1f00 >> $(TMP)n8.arf + $(ECHO) $(OBJ)loadern8.rel >> $(TMP)n8.arf + $(ECHO) $(OBJ)dbgmon.rel >> $(TMP)n8.arf + $(ECHO) $(OBJ)ccpb03.rel >> $(TMP)n8.arf + $(ECHO) $(OBJ)bdosb01.rel >> $(TMP)n8.arf + $(ECHO) $(OBJ)cbiosn8.rel >> $(TMP)n8.arf + $(ECHO) -e >> $(TMP)n8.arf + +############################################################ + +# Hardware specific assemblies (most likely used by BIOS's) + +# +# Assemble hardware control code for the Zilog Z53C8003V5C +# +$(OBJ)z53c80.rel: $(SRC)z53c80.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) $(SRC)z53c80.c + $(QUIET)$(COPY) $(COPYFLG) z53c80.rel $(OBJ) + $(QUIET)$(DEL) $(DELFLG) z53c80.* + +# +# Compile ersatz printf routine for use in CP/M-80 command files +# +$(OBJ)cprintf.rel: $(SRC)cprintf.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) $(SRC)cprintf.c + $(QUIET)$(COPY) $(COPYFLG) cprintf.rel obj + $(QUIET)$(DEL) $(DELFLG) cprintf.* + +############################################################ + +# Build CP/M 2.2 command files (copyfile.com, fdisk.com) + +#----------------------------------------------------------- + +$(COM)copyfile.com: $(OBJ)copyfile.com $(MK) + $(QUIET)$(COPY) $(OBJ)copyfile.com $(COM)copyfile.com + $(QUIET)$(DEL) $(DELFLG) copyfile.* + +$(OBJ)copyfile.com: $(OBJ)copyfile.hex $(LOAD) $(BINFILES) $(MK) + $(QUIET)$(LOAD) $(OBJ)copyfile + +$(OBJ)copyfile.hex: $(OBJ)copyfile.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)copyfile.ihx $(OBJ)copyfile.hex + +$(OBJ)copyfile.ihx: $(OBJ)copyfile.rel $(COMRELS) $(TMP)copyfile.arf $(MK) + $(QUIET)$(COPY) $(TMP)copyfile.arf $(TMP)copyfile.lnk + + $(QUIET)$(SDLD) $(LOPTS) -nf $(TMP)copyfile.lnk + $(QUIET)$(COPY) $(COPYFLG) copyfile.ihx obj + $(QUIET)$(COPY) $(COPYFLG) copyfile.map map + +############################################################## +# Dynamicaly create linker command file for copyfile utility # +# Now uses the macro controlled ECHO feature # +############################################################## +$(TMP)copyfile.arf: Makefile + $(ECHO) -mjx > $(TMP)copyfile.arf + $(ECHO) -i copyfile.ihx >> $(TMP)copyfile.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)copyfile.arf + $(ECHO) -l z80 >> $(TMP)copyfile.arf + $(ECHO) $(OBJ)cpm0.rel >> $(TMP)copyfile.arf + $(ECHO) $(OBJ)copyfile.rel >> $(TMP)copyfile.arf + $(ECHO) $(OBJ)cpmbdos.rel >> $(TMP)copyfile.arf + $(ECHO) $(OBJ)cprintf.rel >> $(TMP)copyfile.arf + $(ECHO) -e >> $(TMP)copyfile.arf + +$(OBJ)copyfile.rel: $(SRC)copyfile.c $(MK) + $(QUIET)$(SDCC) $(SDCCFLG) $(SRC)copyfile.c + $(QUIET)$(COPY) copyfile.rel obj + $(QUIET)$(DEL) $(DELFLG) copyfile.rel +# ls obj + +#----------------------------------------------------------- + +# +# Use locally compiled 'load' command to covert Intel +# hex formal file to a binary CP/M-80 command file. +# +$(COM)fdisk.com: $(OBJ)fdisk.hex $(TOOLS) $(MK) + $(QUIET)$(BIN)load $(OBJ)fdisk + $(QUIET)$(COPY) $(COPYFLG) $(OBJ)fdisk.com com + $(QUIET)$(DEL) $(DELFLG) fdisk.* + +# +# rename 'ihx' output of linker to 'hex' + +$(OBJ)fdisk.hex: $(OBJ)fdisk.ihx $(MK) + $(QUIET)$(COPY) $(OBJ)fdisk.ihx $(OBJ)fdisk.hex + +$(OBJ)fdisk.ihx: $(OBJ)fdisk.rel $(TMP)fdisk.arf $(MK) + $(QUIET)$(COPY) $(TMP)fdisk.arf $(TMP)fdisk.lnk + $(QUIET)$(COPY) $(TMP)fdisk.arf $(TMP)fdisk.lk + $(QUIET)$(SDLD) $(SDLDFLG) -nf $(TMP)fdisk.lnk + $(QUIET)$(COPY) $(COPYFLG) fdisk.ihx $(OBJ)fdisk.ihx + $(QUIET)$(COPY) $(COPYFLG) fdisk.map map + +$(OBJ)fdisk.rel: $(SRC)fdisk.c $(INCFILES) $(MK) + $(QUIET)$(SDCC) -I inc $(SDCCFLG) $(SRC)fdisk.c + $(QUIET)$(COPY) $(COPYFLG) fdisk.rel $(OBJ) + +############################################################################ +# Dynamically created linker command file for fdisk utility (CP/M version) # +# Now uses macro controlled ECHO feature # +############################################################################ +$(TMP)fdisk.arf: $(MK) + $(ECHO) -mjx > $(TMP)fdisk.arf + $(ECHO) -i fdisk.ihx >> $(TMP)fdisk.arf + $(ECHO) -k $(SDCCLIB) >> $(TMP)fdisk.arf + $(ECHO) -l z80 >> $(TMP)fdisk.arf + $(ECHO) $(OBJ)cpm0.rel >> $(TMP)fdisk.arf + $(ECHO) $(OBJ)fdisk.rel >> $(TMP)fdisk.arf + $(ECHO) $(OBJ)cpmbdos.rel >> $(TMP)fdisk.arf + $(ECHO) $(OBJ)cprintf.rel >> $(TMP)fdisk.arf + $(ECHO) -e >> $(TMP)fdisk.arf + + +#----------------------------------------------------------- + +# Also build host version of fdisk for testing purposes + +$(BIN)fdisk$(EXE): $(SRC)fdisk.c $(MK) + $(QUIET)$(TCC) $(TCCOPT) $(SRC)fdisk.c -o $(BIN)fdisk + +############################################################ + +# Build CP/M-80 Command File Structure Files + +$(OBJ)cpm0.rel: $(SRC)cpm0.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)cpm0.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cpm0.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cpm0.lst $(LST) + +$(OBJ)cpmbdos.rel: $(SRC)cpmbdos.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)cpmbdos.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cpmbdos.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cpmbdos.lst $(LST) + +############################################################ + +# Build ROM Image structure files + +$(OBJ)crt0.rel: $(SRC)crt0.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)crt0.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)crt0.lst $(LST) + +$(OBJ)bdosb01.rel: $(SRC)bdosb01.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)bdosb01.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)bdosb01.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)bdosb01.lst $(LST) + +$(OBJ)ccpb03.rel: $(SRC)ccpb03.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)ccpb03.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)ccpb03.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)ccpb03.lst $(LST) +# +# Assemble hardware control code for SBC V2 +# +$(OBJ)cbios.rel: $(SRC)cbios.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)cbios.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cbios.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)cbios.lst $(LST) + +# +# Assemble a monitor program for the SBC V2 +# +$(OBJ)dbgmon.rel: $(SRC)dbgmon.s $(MK) + $(QUIET)$(SDAS) $(SDASFLG) $(SRC)dbgmon.s + $(QUIET)$(COPY) $(COPYFLG) $(SRC)dbgmon.rel $(OBJ) + $(QUIET)$(COPY) $(COPYFLG) $(SRC)dbgmon.lst $(LST) + +########################################################### + +# Build host based tools ( dwgh2b, jrch2b, load, verify) + +$(DWGH2B): $(SRC)dwgh2b.c $(MK) + $(QUIET)$(TCC) $(TCCOPT) $(SRC)dwgh2b.c -o $(BIN)dwgh2b$(EXE) + +# +# Compile John Coffman's hex2bin program +# +$(JRCH2B): $(SRC)jrch2b.c $(MK) + $(QUIET)$(TCC) $(TCCOPT) $(SRC)jrch2b.c -o $(BIN)jrch2b$(EXE) +# $(QUIET)$(COPY) $(COPYFLG) $(BIN)jrch2b $(BIN)jrcb2h + +# +# Compile Doug's "load" program +# +$(LOAD): $(SRC)load.c $(MK) + $(QUIET)$(TCC) $(TCCOPT) $(SRC)load.c -o $(BIN)load$(EXE) + +$(SYSGEN): $(SRC)sysgen.c $(MK) + $(QUIET)$(TCC) $(TCCOPT) $(SRC)sysgen.c -o $(BIN)sysgen$(EXE) + +# +# Compile Doug's verif program that compares binary file regions +# +$(VERIFY): $(SRC)verify.c Makefile $(MK) + $(QUIET)$(TCC) $(TCCOPT) $(SRC)verify.c -o $(BIN)verify + +$(BIN)lechocr.exe: $(SRC)lechocr.c $(MK) +# $(QUIET)$(TCC) $(TCCOPT) $(SRC)lechocr.c -o $(BIN)lechocr + $(TCC) $(TCCOPT) $(SRC)lechocr.c -o lechocr.exe + $(COPY) lechocr.exe $(BIN) + +$(BIN)lecholf.exe: $(SRC)lecholf.c $(MK) +# $(QUIET)$(TCC) $(TCCFLG) $(SRC)lecholf.c -o $(BIN)lecholf + $(TCC) $(TCCOPT) $(SRC)lecholf.c -o lecholf.exe + $(COPY) lecholf.exe $(BIN) + +$(BIN)lechocrlf.exe: $(SRC)lechocrlf.c $(MK) +# $(QUIET)$(TCC) $(TCCOPT) $(SRC)lechocrlf.c -o $(BIN)lechocrlf + $(TCC) $(TCCOPT) $(SRC)lechocrlf.c -o lechocrlf.exe + $(COPY) lechocrlf.exe $(BIN) + +$(BIN)lecholfcr.exe: $(SRC)lecholfcr.c $(MK) +# $(QUIET)$(TCC) $(TCCFLG) $(SRC)lecholfcr.c -o $(BIN)lecholfcr + $(TCC) $(TCCOPT) $(SRC)lecholfcr.c -o lecholfcr.exe + $(COPY) lecholfcr.exe $(BIN) + +############################################################ + +# Builder specific utility rules + +dwginstall: + $(COPY) $(COMFILES) ~/Documents/devobox/cdrive + +############################################################ + +# +# Delete all dynamically generated files that don't need to be +# saved. +# +clean: + $(QUIET)$(DEL) $(DELFLG) *.hex *.ihx *.lst *.rel *.rst *.lnk *.lk + $(QUIET)$(DEL) $(DELFLG) *.sym *.map *.noi *.asm *.com *.ini *.bin + $(QUIET)$(DEL) $(DELFLG) obj$(DELIM)*.* bin$(DELIM)*.* com$(DELIM)*.* rom$(DELIM)*.* tmp$(DELIM)*.* map$(DELIM)*.* lst$(DELIM)*.* + +################## +# eof - Makefile # +################## diff --git a/doug/ref/JRC0521.ZIP b/doug/ref/JRC0521.ZIP new file mode 100755 index 00000000..55eb7806 Binary files /dev/null and b/doug/ref/JRC0521.ZIP differ diff --git a/doug/ref/bdosb01.asm b/doug/ref/bdosb01.asm new file mode 100755 index 00000000..b5883d94 --- /dev/null +++ b/doug/ref/bdosb01.asm @@ -0,0 +1,2587 @@ + .title "Digital Research BDOS, Version 2.2" + .page 49 + +ENDFIL .EQU 1 ;FILL FULL BDOS LENGTH +; +IOBYTE: .EQU 3 ; I/O DEFINITION BYTE. +TDRIVE: .EQU 4 ; CURRENT DRIVE NAME AND USER NUMBER. +ENTRY: .EQU 5 ; ENTRY POINT FOR THE CP/M BDOS. +TFCB: .EQU 5CH ; DEFAULT FILE CONTROL BLOCK. +TBUFF: .EQU 80H ; I/O BUFFER AND COMMAND LINE STORAGE. +TBASE: .EQU 100H ; TRANSIANT PROGRAM STORAGE AREA. +; +; SET CONTROL CHARACTER .EQUATES. +; +CNTRLC: .EQU 3 ; CONTROL-C +CNTRLE: .EQU 05H ; CONTROL-E +BS: .EQU 08H ; BACKSPACE +TAB: .EQU 09H ; TAB +LF: .EQU 0AH ; LINE FEED +FF: .EQU 0CH ; FORM FEED +CR: .EQU 0DH ; CARRIAGE RETURN +CNTRLP: .EQU 10H ; CONTROL-P +CNTRLR: .EQU 12H ; CONTROL-R +CNTRLS: .EQU 13H ; CONTROL-S +CNTRLU: .EQU 15H ; CONTROL-U +CNTRLX: .EQU 18H ; CONTROL-X +CNTRLZ: .EQU 1AH ; CONTROL-Z (END-OF-FILE MARK) +DEL: .EQU 7FH ; RUBOUT + +; CPM ORIGIN CALCULATE + +NK .EQU 59 ;SYSTEM SIZE +BASE .EQU (NK*1024)-5000H +CCPO .EQU BASE+3400H ;CCP ORIGIN +BDOSO .EQU BASE+3C00H ;BDOS ORIGIN +BIOSO .EQU BASE+4A00H ;BIOS ORIGIN + + .ORG BDOSO + .DB 0,0,0,0,0,0 ;OLD SERIAL NUMBER +; +;************************************************************** +;* +;* B D O S E N T R Y +;* +;************************************************************** +; +FBASE: JP FBASE1 +; +; BDOS ERROR TABLE. +; +BADSCTR:.DW ERROR1 ; BAD SECTOR ON READ OR WRITE. +BADSLCT:.DW ERROR2 ; BAD DISK SELECT. +RODISK: .DW ERROR3 ; DISK IS READ ONLY. +ROFILE: .DW ERROR4 ; FILE IS READ ONLY. +; +; ENTRY INTO BDOS. (DE) OR (E) ARE THE PARAMETERS PASSED. THE +; FUNCTION NUMBER DESIRED IS IN REGISTER (C). +; E contains drive number if passing this +FBASE1: EX DE,HL ; SAVE THE (DE) PARAMETERS. + LD (PARAMS),HL + EX DE,HL + LD A,E ; AND SAVE REGISTER (E) IN PARTICULAR. + LD (EPARAM),A + LD HL,0 + LD (STATUS),HL ; CLEAR RETURN STATUS. + ADD HL,SP + LD (USRSTACK),HL ; SAVE USERS STACK POINTER. + LD SP,STKAREA ; AND SET OUR OWN. + XOR A ; CLEAR AUTO SELECT STORAGE SPACE. + LD (AUTOFLAG),A + LD (AUTO),A + LD HL,GOBACK ; SET RETURN ADDRESS. + PUSH HL + LD A,C ; GET FUNCTION NUMBER. + CP NFUNCTS ; VALID FUNCTION NUMBER? + RET NC + LD C,E ; KEEP SINGLE REGISTER FUNCTION HERE. + LD HL,FUNCTNS ; NOW LOOK THRU THE FUNCTION TABLE. + LD E,A + LD D,0 ; (DE)=FUNCTION NUMBER. + ADD HL,DE + ADD HL,DE ; (HL)=(START OF TABLE)+2*(FUNCTION NUMBER). + LD E,(HL) + INC HL + LD D,(HL) ; NOW (DE)=ADDRESS FOR THIS FUNCTION. + LD HL,(PARAMS) ; RETRIEVE PARAMETERS. + EX DE,HL ; NOW (DE) HAS THE ORIGINAL PARAMETERS. + JP (HL) ; EXECUTE DESIRED FUNCTION. +; +; BDOS FUNCTION JUMP TABLE. +; +NFUNCTS:.EQU 41 ; NUMBER OF FUNCTIONS IN FOLLOWIN TABLE. +; +FUNCTNS:.DW WBOOT,GETCON,OUTCON,GETRDR,PUNCH,LIST,DIRCIO,GETIOB + .DW SETIOB,PRTSTR,R.DBUFF,GETCSTS,GETVER,RSTDSK,SETDSK,OPENFIL + .DW CLOSEFIL,GETFST,GETNXT,DELFILE,READSEQ,WRTSEQ,FCREATE + .DW RENFILE,GETLOG,GETCRNT,PUTDMA,GETALOC,WRTPRTD,GETROV,SETATTR + .DW GETPARM,GETUSER,RDRANDOM,WTRANDOM,FILESIZE,SETRAN,LOGOFF,RTN + .DW RTN,WTSPECL +; +; BDOS ERROR MESSAGE SECTION. +; +ERROR1: LD HL,BADSEC ; BAD SECTOR MESSAGE. + CALL PRTERR ; PRINT IT AND GET A 1 CHAR RESPONCE. + CP CNTRLC ; RE-BOOT R.EQUEST (CONTROL-C)? + JP Z,0 ; YES. + RET ; NO, RETURN TO RETRY I/O FUNCTION. +; +ERROR2: LD HL,BADSEL ; BAD DRIVE SELECTED. + JP ERROR5 +; +ERROR3: LD HL,DISKRO ; DISK IS READ ONLY. + JP ERROR5 +; +ERROR4: LD HL,FILERO ; FILE IS READ ONLY. +; +ERROR5: CALL PRTERR + JP 0 ; ALWAYS REBOOT ON THESE ERRORS. +; +BDOSERR:.DB "BDOS ERR ON " +BDOSDRV:.DB " : $" +BADSEC: .DB "BAD SECTOR$" +BADSEL: .DB "SELECT$" +FILERO: .DB "FILE " +DISKRO: .DB "R/O$" +; +; PRINT BDOS ERROR MESSAGE. +; +PRTERR: PUSH HL ; SAVE SECOND MESSAGE POINTER. + CALL OUTCRLF ; SEND (CR)(LF). + LD A,(ACTIVE) ; GET ACTIVE DRIVE. + ADD A,'A' ; MAKE ASCII. + LD (BDOSDRV),A ; AND PUT IN MESSAGE. + LD BC,BDOSERR ; AND PRINT IT. + CALL PRTMESG + POP BC ; PRINT SECOND MESSAGE LINE NOW. + CALL PRTMESG +; +; GET AN INPUT CHARACTER. WE WILL CHECK OUR 1 CHARACTER +; BUFFER FIRST. THIS MAY BE SET BY THE CONSOLE STATUS ROUTINE. +; +GETCHAR:LD HL,CHARBUF ; CHECK CHARACTER BUFFER. + LD A,(HL) ; ANYTHING PRESENT ALREADY? + LD (HL),0 ; ...EITHER CASE CLEAR IT. + OR A + RET NZ ; YES, USE IT. + JP CONIN ; NOPE, GO GET A CHARACTER RESPONCE. +; +; INPUT AND ECHO A CHARACTER. +; +GETECHO:CALL GETCHAR ; INPUT A CHARACTER. + CALL CHKCHAR ; CARRIAGE CONTROL? + RET C ; NO, A REGULAR CONTROL CHAR SO DON'T ECHO. + PUSH AF ; OK, SAVE CHARACTER NOW. + LD C,A + CALL OUTCON ; AND ECHO IT. + POP AF ; GET CHARACTER AND RETURN. + RET +; +; CHECK CHARACTER IN (A). SET THE ZERO FLAG ON A CARRIAGE +; CONTROL CHARACTER AND THE CARRY FLAG ON ANY OTHER CONTROL +; CHARACTER. +; +CHKCHAR:CP CR ; CHECK FOR CARRIAGE RETURN, LINE FEED, BACKSPACE, + RET Z ; OR A TAB. + CP LF + RET Z + CP TAB + RET Z + CP BS + RET Z + CP ' ' ; OTHER CONTROL CHAR? SET CARRY FLAG. + RET +; +; CHECK THE CONSOLE DURING OUTPUT. HALT ON A CONTROL-S, THEN +; REBOOT ON A CONTROL-C. IF ANYTHING ELSE IS READY, CLEAR THE +; ZERO FLAG AND RETURN (THE CALLING ROUTINE MAY WANT TO DO +; SOMETHING). +; +CKCONSOL: + LD A,(CHARBUF) ; CHECK BUFFER. + OR A ; IF ANYTHING, JUST RETURN WITHOUT CHECKING. + JP NZ,CKCON2 + CALL CONST ; NOTHING IN BUFFER. CHECK CONSOLE. + AND 01H ; LOOK AT BIT 0. + RET Z ; RETURN IF NOTHING. + CALL CONIN ; OK, GET IT. + CP CNTRLS ; IF NOT CONTROL-S, RETURN WITH ZERO CLEARED. + JP NZ,CKCON1 + CALL CONIN ; HALT PROCESSING UNTIL ANOTHER CHAR + CP CNTRLC ; IS TYPED. CONTROL-C? + JP Z,0 ; YES, REBOOT NOW. + XOR A ; NO, JUST PRETEND NOTHING WAS EVER READY. + RET +CKCON1: LD (CHARBUF),A ; SAVE CHARACTER IN BUFFER FOR LATER PROCESSING. +CKCON2: LD A,1 ; SET (A) TO NON ZERO TO MEAN SOMETHING IS READY. + RET +; +; OUTPUT (C) TO THE SCREEN. IF THE PRINTER FLIP-FLOP FLAG +; IS SET, WE WILL SEND CHARACTER TO PRINTER ALSO. THE CONSOLE +; WILL BE CHECKED IN THE PROCESS. +; +OUTCHAR:LD A,(OUTFLAG) ; CHECK OUTPUT FLAG. + OR A ; ANYTHING AND WE WON'T GENERATE OUTPUT. + JP NZ,OUTCHR1 + PUSH BC + CALL CKCONSOL ; CHECK CONSOLE (WE DON'T CARE WHATS THERE). + POP BC + PUSH BC + CALL CONOUT ; OUTPUT (C) TO THE SCREEN. + POP BC + PUSH BC + LD A,(PRTFLAG) ; CHECK PRINTER FLIP-FLOP FLAG. + OR A + CALL NZ,LIST ; PRINT IT ALSO IF NON-ZERO. + POP BC +OUTCHR1:LD A,C ; UPDATE CURSORS POSITION. + LD HL,CURPOS + CP DEL ; RUBOUTS DON'T DO ANYTHING HERE. + RET Z + INC (HL) ; BUMP LINE POINTER. + CP ' ' ; AND RETURN IF A NORMAL CHARACTER. + RET NC + DEC (HL) ; RESTORE AND CHECK FOR THE START OF THE LINE. + LD A,(HL) + OR A + RET Z ; INGNORE CONTROL CHARACTERS AT THE START OF THE LINE. + LD A,C + CP BS ; IS IT A BACKSPACE? + JP NZ,OUTCHR2 + DEC (HL) ; YES, BACKUP POINTER. + RET +OUTCHR2:CP LF ; IS IT A LINE FEED? + RET NZ ; IGNORE ANYTHING ELSE. + LD (HL),0 ; RESET POINTER TO START OF LINE. + RET +; +; OUTPUT (A) TO THE SCREEN. IF IT IS A CONTROL CHARACTER +; (OTHER THAN CARRIAGE CONTROL), USE ^X FORMAT. +; +SHOWIT: LD A,C + CALL CHKCHAR ; CHECK CHARACTER. + JP NC,OUTCON ; NOT A CONTROL, USE NORMAL OUTPUT. + PUSH AF + LD C,'^' ; FOR A CONTROL CHARACTER, PRECEED IT WITH '^'. + CALL OUTCHAR + POP AF + OR '@' ; AND THEN USE THE LETTER .EQUIVELANT. + LD C,A +; +; FUNCTION TO OUTPUT (C) TO THE CONSOLE DEVICE AND EXPAND TABS +; IF NECESSARY. +; +OUTCON: LD A,C + CP TAB ; IS IT A TAB? + JP NZ,OUTCHAR ; USE REGULAR OUTPUT. +OUTCON1:LD C,' ' ; YES IT IS, USE SPACES INSTEAD. + CALL OUTCHAR + LD A,(CURPOS) ; GO UNTIL THE CURSOR IS AT A MULTIPLE OF 8 + + AND 07H ; POSITION. + JP NZ,OUTCON1 + RET +; +; ECHO A BACKSPACE CHARACTER. ERASE THE PREVOIUS CHARACTER +; ON THE SCREEN. +; +BACKUP: CALL BACKUP1 ; BACKUP THE SCREEN 1 PLACE. + LD C,' ' ; THEN BLANK THAT CHARACTER. + CALL CONOUT +BACKUP1:LD C,BS ; THEN BACK SPACE ONCE MORE. + JP CONOUT +; +; SIGNAL A DELETED LINE. PRINT A '#' AT THE END AND START +; OVER. +; +NEWLINE:LD C,'#' + CALL OUTCHAR ; PRINT THIS. + CALL OUTCRLF ; START NEW LINE. +NEWLN1: LD A,(CURPOS) ; MOVE THE CURSOR TO THE STARTING POSITION. + LD HL,STARTING + CP (HL) + RET NC ; THERE YET? + LD C,' ' + CALL OUTCHAR ; NOPE, KEEP GOING. + JP NEWLN1 +; +; OUTPUT A (CR) (LF) TO THE CONSOLE DEVICE (SCREEN). +; +OUTCRLF:LD C,CR + CALL OUTCHAR + LD C,LF + JP OUTCHAR +; +; PRINT MESSAGE POINTED TO BY (BC). IT WILL END WITH A '$'. +; +PRTMESG:LD A,(BC) ; CHECK FOR TERMINATING CHARACTER. + CP '$' + RET Z + INC BC + PUSH BC ; OTHERWISE, BUMP POINTER AND PRINT IT. + LD C,A + CALL OUTCON + POP BC + JP PRTMESG +; +; FUNCTION TO EXECUTE A BUFFERED READ. +; +R.DBUFF: LD A,(CURPOS) ; USE PRESENT LOCATION AS STARTING ONE. + LD (STARTING),A + LD HL,(PARAMS) ; GET THE MAXIMUM BUFFER SPACE. + LD C,(HL) + INC HL ; POINT TO FIRST AVAILABLE SPACE. + PUSH HL ; AND SAVE. + LD B,0 ; KEEP A CHARACTER COUNT. +R.DBUF1: PUSH BC + PUSH HL +R.DBUF2: CALL GETCHAR ; GET THE NEXT INPUT CHARACTER. + AND 7FH ; STRIP BIT 7. + POP HL ; RESET REGISTERS. + POP BC + CP CR ; EN OF THE LINE? + JP Z,R.DBUF17 + CP LF + JP Z,R.DBUF17 + CP BS ; HOW ABOUT A BACKSPACE? + JP NZ,R.DBUF3 + LD A,B ; YES, BUT IGNORE AT THE BEGINNING OF THE LINE. + OR A + JP Z,R.DBUF1 + DEC B ; OK, UPDATE COUNTER. + LD A,(CURPOS) ; IF WE BACKSPACE TO THE START OF THE LINE, + LD (OUTFLAG),A ; TREAT AS A CANCEL (CONTROL-X). + JP R.DBUF10 +R.DBUF3: CP DEL ; USER TYPED A RUBOUT? + JP NZ,R.DBUF4 + LD A,B ; IGNORE AT THE START OF THE LINE. + OR A + JP Z,R.DBUF1 + LD A,(HL) ; OK, ECHO THE PREVOIUS CHARACTER. + DEC B ; AND RESET POINTERS (COUNTERS). + DEC HL + JP R.DBUF15 +R.DBUF4: CP CNTRLE ; PHYSICAL END OF LINE? + JP NZ,R.DBUF5 + PUSH BC ; YES, DO IT. + PUSH HL + CALL OUTCRLF + XOR A ; AND UPDATE STARTING POSITION. + LD (STARTING),A + JP R.DBUF2 +R.DBUF5: CP CNTRLP ; CONTROL-P? + JP NZ,R.DBUF6 + PUSH HL ; YES, FLIP THE PRINT FLAG FILP-FLOP BYTE. + LD HL,PRTFLAG + LD A,1 ; PRTFLAG=1-PRTFLAG + SUB (HL) + LD (HL),A + POP HL + JP R.DBUF1 +R.DBUF6: CP CNTRLX ; CONTROL-X (CANCEL)? + JP NZ,R.DBUF8 + POP HL +R.DBUF7: LD A,(STARTING) ; YES, BACKUP THE CURSOR TO HERE. + LD HL,CURPOS + CP (HL) + JP NC,R.DBUFF ; DONE YET? + DEC (HL) ; NO, DECREMENT POINTER AND OUTPUT BACK UP ONE SPACE. + CALL BACKUP + JP R.DBUF7 +R.DBUF8: CP CNTRLU ; CNTROL-U (CANCEL LINE)? + JP NZ,R.DBUF9 + CALL NEWLINE ; START A NEW LINE. + POP HL + JP R.DBUFF +R.DBUF9: CP CNTRLR ; CONTROL-R? + JP NZ,R.DBUF14 +R.DBUF10:PUSH BC ; YES, START A NEW LINE AND RETYPE THE OLD ONE. + CALL NEWLINE + POP BC + POP HL + PUSH HL + PUSH BC +R.DBUF11:LD A,B ; DONE WHOLE LINE YET? + OR A + JP Z,R.DBUF12 + INC HL ; NOPE, GET NEXT CHARACTER. + LD C,(HL) + DEC B ; COUNT IT. + PUSH BC + PUSH HL + CALL SHOWIT ; AND DISPLAY IT. + POP HL + POP BC + JP R.DBUF11 +R.DBUF12:PUSH HL ; DONE WITH LINE. IF WE WERE DISPLAYING + LD A,(OUTFLAG) ; THEN UPDATE CURSOR POSITION. + OR A + JP Z,R.DBUF2 + LD HL,CURPOS ; BECAUSE THIS LINE IS SHORTER, WE MUST + SUB (HL) ; BACK UP THE CURSOR (NOT THE SCREEN HOWEVER) + LD (OUTFLAG),A ; SOME NUMBER OF POSITIONS. +R.DBUF13:CALL BACKUP ; NOTE THAT AS LONG AS (OUTFLAG) IS NON + LD HL,OUTFLAG ; ZERO, THE SCREEN WILL NOT BE CHANGED. + DEC (HL) + JP NZ,R.DBUF13 + JP R.DBUF2 ; NOW JUST GET THE NEXT CHARACTER. +; +; JUST A NORMAL CHARACTER, PUT THIS IN OUR BUFFER AND ECHO. +; +R.DBUF14:INC HL + LD (HL),A ; STORE CHARACTER. + INC B ; AND COUNT IT. +R.DBUF15:PUSH BC + PUSH HL + LD C,A ; ECHO IT NOW. + CALL SHOWIT + POP HL + POP BC + LD A,(HL) ; WAS IT AN ABORT R.EQUEST? + CP CNTRLC ; CONTROL-C ABORT? + LD A,B + JP NZ,R.DBUF16 + CP 1 ; ONLY IF AT START OF LINE. + JP Z,0 +R.DBUF16:CP C ; NOPE, HAVE WE FILLED THE BUFFER? + JP C,R.DBUF1 +R.DBUF17:POP HL ; YES END THE LINE AND RETURN. + LD (HL),B + LD C,CR + JP OUTCHAR ; OUTPUT (CR) AND RETURN. +; +; FUNCTION TO GET A CHARACTER FROM THE CONSOLE DEVICE. +; +GETCON: CALL GETECHO ; GET AND ECHO. + JP SETSTAT ; SAVE STATUS AND RETURN. +; +; FUNCTION TO GET A CHARACTER FROM THE TAPE READER DEVICE. +; +GETRDR: CALL READER ; GET A CHARACTER FROM READER, SET STATUS AND RETURN. + JP SETSTAT +; +; FUNCTION TO PERFORM DIRECT CONSOLE I/O. IF (C) CONTAINS (FF) +; THEN THIS IS AN INPUT R.EQUEST. IF (C) CONTAINS (FE) THEN +; THIS IS A STATUS R.EQUEST. OTHERWISE WE ARE TO OUTPUT (C). +; +DIRCIO: LD A,C ; TEST FOR (FF). + INC A + JP Z,DIRC1 + INC A ; TEST FOR (FE). + JP Z,CONST + JP CONOUT ; JUST OUTPUT (C). +DIRC1: CALL CONST ; THIS IS AN INPUT R.EQUEST. + OR A + JP Z,GOBACK1 ; NOT READY? JUST RETURN (DIRECTLY). + CALL CONIN ; YES, GET CHARACTER. + JP SETSTAT ; SET STATUS AND RETURN. +; +; FUNCTION TO RETURN THE I/O BYTE. +; +GETIOB: LD A,(IOBYTE) + JP SETSTAT +; +; FUNCTION TO SET THE I/O BYTE. +; +SETIOB: LD HL,IOBYTE + LD (HL),C + RET +; +; FUNCTION TO PRINT THE CHARACTER STRING POINTED TO BY (DE) +; ON THE CONSOLE DEVICE. THE STRING ENDS WITH A '$'. +; +PRTSTR: EX DE,HL + LD C,L + LD B,H ; NOW (BC) POINTS TO IT. + JP PRTMESG +; +; FUNCTION TO INTERIGATE THE CONSOLE DEVICE. +; +GETCSTS:CALL CKCONSOL +; +; GET HERE TO SET THE STATUS AND RETURN TO THE CLEANUP +; SECTION. THEN BACK TO THE USER. +; +SETSTAT:LD (STATUS),A +RTN: RET +; +; SET THE STATUS TO 1 (READ OR WRITE ERROR CODE). +; +IOERR1: LD A,1 + JP SETSTAT +; +OUTFLAG:.DB 0 ; OUTPUT FLAG (NON ZERO MEANS NO OUTPUT). +STARTING: + .DB 2 ; STARTING POSITION FOR CURSOR. +CURPOS: .DB 0 ; CURSOR POSITION (0=START OF LINE). +PRTFLAG:.DB 0 ; PRINTER FLAG (CONTROL-P TOGGLE). LIST IF NON ZERO. +CHARBUF:.DB 0 ; SINGLE INPUT CHARACTER BUFFER. +; +; STACK AREA FOR BDOS CALLS. +; +USRSTACK: + .DW 0 ; SAVE USERS STACK POINTER HERE. +; + .DB 0,0,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,0,0 +STKAREA:.EQU $ ; END OF STACK AREA. +; +USERNO: .DB 0 ; CURRENT USER NUMBER. +ACTIVE: .DB 0 ; CURRENTLY ACTIVE DRIVE. +PARAMS: .DW 0 ; SAVE (DE) PARAMETERS HERE ON ENTRY. +STATUS: .DW 0 ; STATUS RETURNED FROM BDOS FUNCTION. +; +; SELECT ERROR OCCURED, JUMP TO ERROR ROUTINE. +; +SLCTERR:LD HL,BADSLCT +; +; JUMP TO (HL) INDIRECTLY. +; +JUMPHL: LD E,(HL) + INC HL + LD D,(HL) ; NOW (DE) CONTAIN THE DESIRED ADDRESS. + EX DE,HL + JP (HL) +; +; BLOCK MOVE. (DE) TO (HL), (C) BYTES TOTAL. +; +DE2HL: INC C ; IS COUNT DOWN TO ZERO? +DE2HL1: DEC C + RET Z ; YES, WE ARE DONE. + LD A,(DE) ; NO, MOVE ONE MORE BYTE. + LD (HL),A + INC DE + INC HL + JP DE2HL1 ; AND REPEAT. +; +; SELECT THE DESIRED DRIVE. +; +SELECT: LD A,(ACTIVE) ; GET ACTIVE DISK. + LD C,A + CALL SELDSK ; SELECT IT. + LD A,H ; VALID DRIVE? + OR L ; VALID DRIVE? + RET Z ; RETURN IF NOT. +; +; HERE, THE BIOS RETURNED THE ADDRESS OF THE PARAMETER BLOCK +; IN (HL). WE WILL EXTRACT THE NECESSARY POINTERS AND SAVE THEM. +; + LD E,(HL) ; YES, GET ADDRESS OF TRANSLATION TABLE INTO (DE). + INC HL + LD D,(HL) + INC HL + LD (SCRATCH1),HL ; SAVE POINTERS TO SCRATCH AREAS. + INC HL + INC HL + LD (SCRATCH2),HL ; DITTO. + INC HL + INC HL + LD (SCRATCH3),HL ; DITTO. + INC HL + INC HL + EX DE,HL ; NOW SAVE THE TRANSLATION TABLE ADDRESS. + LD (XLATE),HL + LD HL,DIRBUF ; PUT THE NEXT 8 BYTES HERE. + LD C,8 ; THEY CONSIST OF THE DIRECTORY BUFFER + CALL DE2HL ; POINTER, PARAMETER BLOCK POINTER, + LD HL,(DISKPB) ; CHECK AND ALLOCATION VECTORS. + EX DE,HL + LD HL,SECTORS ; MOVE PARAMETER BLOCK INTO OUR RAM. + LD C,15 ; IT IS 15 BYTES LONG. + CALL DE2HL + LD HL,(DSKSIZE) ; CHECK DISK SIZE. + LD A,H ; MORE THAN 256 BLOCKS ON THIS? + LD HL,BIGDISK + LD (HL),0FFH ; SET TO SAMLL. + OR A + JP Z,SELECT1 + LD (HL),0 ; WRONG, SET TO LARGE. +SELECT1:LD A,0FFH ; CLEAR THE ZERO FLAG. + OR A + RET +; +; ROUTINE TO HOME THE DISK TRACK HEAD AND CLEAR POINTERS. +; +HOMEDRV:CALL HOME ; HOME THE HEAD. + XOR A + LD HL,(SCRATCH2) ; SET OUR TRACK POINTER ALSO. + LD (HL),A + INC HL + LD (HL),A + LD HL,(SCRATCH3) ; AND OUR SECTOR POINTER. + LD (HL),A + INC HL + LD (HL),A + RET +; +; DO THE ACTUAL DISK READ AND CHECK THE ERROR RETURN STATUS. +; +DOREAD: CALL READ + JP IORET +; +; DO THE ACTUAL DISK WRITE AND HANDLE ANY BIOS ERROR. +; +DOWRITE:CALL WRITE +IORET: OR A + RET Z ; RETURN UNLESS AN ERROR OCCURED. + LD HL,BADSCTR ; BAD READ/WRITE ON THIS SECTOR. + JP JUMPHL +; +; ROUTINE TO SELECT THE TRACK AND SECTOR THAT THE DESIRED +; BLOCK NUMBER FALLS IN. +; +TRKSEC: LD HL,(FILEPOS) ; GET POSITION OF LAST ACCESSED FILE + LD C,2 ; IN DIRECTORY AND COMPUTE SECTOR #. + CALL SHIFTR ; SECTOR #=FILE-POSITION/4. + LD (BLKNMBR),HL ; SAVE THIS AS THE BLOCK NUMBER OF INTEREST. + LD (CKSUMTBL),HL ; WHAT'S IT DOING HERE TOO? +; +; IF THE SECTOR NUMBER HAS ALREADY BEEN SET (BLKNMBR), ENTER +; AT THIS POINT. +; +TRKSEC1:LD HL,BLKNMBR + LD C,(HL) ; MOVE SECTOR NUMBER INTO (BC). + INC HL + LD B,(HL) + LD HL,(SCRATCH3) ; GET CURRENT SECTOR NUMBER AND + LD E,(HL) ; MOVE THIS INTO (DE). + INC HL + LD D,(HL) + LD HL,(SCRATCH2) ; GET CURRENT TRACK NUMBER. + LD A,(HL) ; AND THIS INTO (HL). + INC HL + LD H,(HL) + LD L,A +TRKSEC2:LD A,C ; IS DESIRED SECTOR BEFORE CURRENT ONE? + SUB E + LD A,B + SBC A,D + JP NC,TRKSEC3 + PUSH HL ; YES, DECREMENT SECTORS BY ONE TRACK. + LD HL,(SECTORS) ; GET SECTORS PER TRACK. + LD A,E + SUB L + LD E,A + LD A,D + SBC A,H + LD D,A ; NOW WE HAVE BACKED UP ONE FULL TRACK. + POP HL + DEC HL ; ADJUST TRACK COUNTER. + JP TRKSEC2 +TRKSEC3:PUSH HL ; DESIRED SECTOR IS AFTER CURRENT ONE. + LD HL,(SECTORS) ; GET SECTORS PER TRACK. + ADD HL,DE ; BUMP SECTOR POINTER TO NEXT TRACK. + JP C,TRKSEC4 + LD A,C ; IS DESIRED SECTOR NOW BEFORE CURRENT ONE? + SUB L + LD A,B + SBC A,H + JP C,TRKSEC4 + EX DE,HL ; NOT YES, INCREMENT TRACK COUNTER + POP HL ; AND CONTINUE UNTIL IT IS. + INC HL + JP TRKSEC3 +; +; HERE WE HAVE DETERMINED THE TRACK NUMBER THAT CONTAINS THE +; DESIRED SECTOR. +; +TRKSEC4:POP HL ; GET TRACK NUMBER (HL). + PUSH BC + PUSH DE + PUSH HL + EX DE,HL + LD HL,(OFFSET) ; ADJUST FOR FIRST TRACK OFFSET. + ADD HL,DE + LD B,H + LD C,L + CALL SETTRK ; SELECT THIS TRACK. + POP DE ; RESET CURRENT TRACK POINTER. + LD HL,(SCRATCH2) + LD (HL),E + INC HL + LD (HL),D + POP DE + LD HL,(SCRATCH3) ; RESET THE FIRST SECTOR ON THIS TRACK. + LD (HL),E + INC HL + LD (HL),D + POP BC + LD A,C ; NOW SUBTRACT THE DESIRED ONE. + SUB E ; TO MAKE IT RELATIVE (1-# SECTORS/TRACK). + LD C,A + LD A,B + SBC A,D + LD B,A + LD HL,(XLATE) ; TRANSLATE THIS SECTOR ACCORDING TO THIS TABLE. + EX DE,HL + CALL SECTRN ; LET THE BIOS TRANSLATE IT. + LD C,L + LD B,H + JP SETSEC ; AND SELECT IT. +; +; COMPUTE BLOCK NUMBER FROM RECORD NUMBER (SAVNREC) AND +; EXTENT NUMBER (SAVEXT). +; +GETBLOCK: + LD HL,BLKSHFT ; GET LOGICAL TO PHYSICAL CONVERSION. + LD C,(HL) ; NOTE THAT THIS IS BASE 2 LOG OF RATIO. + LD A,(SAVNREC) ; GET RECORD NUMBER. +GETBLK1:OR A ; COMPUTE (A)=(A)/2^BLKSHFT. + RRA + DEC C + JP NZ,GETBLK1 + LD B,A ; SAVE RESULT IN (B). + LD A,8 + SUB (HL) + LD C,A ; COMPUTE (C)=8-BLKSHFT. + LD A,(SAVEXT) +GETBLK2:DEC C ; COMPUTE (A)=SAVEXT*2^(8-BLKSHFT). + JP Z,GETBLK3 + OR A + RLA + JP GETBLK2 +GETBLK3:ADD A,B + RET +; +; ROUTINE TO EXTRACT THE (BC) BLOCK BYTE FROM THE FCB POINTED +; TO BY (PARAMS). IF THIS IS A BIG-DISK, THEN THESE ARE 16 BIT +; BLOCK NUMBERS, ELSE THEY ARE 8 BIT NUMBERS. +; NUMBER IS RETURNED IN (HL). +; +EXTBLK: LD HL,(PARAMS) ; GET FCB ADDRESS. + LD DE,16 ; BLOCK NUMBERS START 16 BYTES INTO FCB. + ADD HL,DE + ADD HL,BC + LD A,(BIGDISK) ; ARE WE USING A BIG-DISK? + OR A + JP Z,EXTBLK1 + LD L,(HL) ; NO, EXTRACT AN 8 BIT NUMBER FROM THE FCB. + LD H,0 + RET +EXTBLK1:ADD HL,BC ; YES, EXTRACT A 16 BIT NUMBER. + LD E,(HL) + INC HL + LD D,(HL) + EX DE,HL ; RETURN IN (HL). + RET +; +; COMPUTE BLOCK NUMBER. +; +COMBLK: CALL GETBLOCK + LD C,A + LD B,0 + CALL EXTBLK + LD (BLKNMBR),HL + RET +; +; CHECK FOR A ZERO BLOCK NUMBER (UNUSED). +; +CHKBLK: LD HL,(BLKNMBR) + LD A,L ; IS IT ZERO? + OR H + RET +; +; ADJUST PHYSICAL BLOCK (BLKNMBR) AND CONVERT TO LOGICAL +; SECTOR (LOGSECT). THIS IS THE STARTING SECTOR OF THIS BLOCK. +; THE ACTUAL SECTOR OF INTEREST IS THEN ADDED TO THIS AND THE +; RESULTING SECTOR NUMBER IS STORED BACK IN (BLKNMBR). THIS +; WILL STILL HAVE TO BE ADJUSTED FOR THE TRACK NUMBER. +; +LOGICAL:LD A,(BLKSHFT) ; GET LOG2(PHYSICAL/LOGICAL SECTORS). + LD HL,(BLKNMBR) ; GET PHYSICAL SECTOR DESIRED. +LOGICL1:ADD HL,HL ; COMPUTE LOGICAL SECTOR NUMBER. + DEC A ; NOTE LOGICAL SECTORS ARE 128 BYTES LONG. + JP NZ,LOGICL1 + LD (LOGSECT),HL ; SAVE LOGICAL SECTOR. + LD A,(BLKMASK) ; GET BLOCK MASK. + LD C,A + LD A,(SAVNREC) ; GET NEXT SECTOR TO ACCESS. + AND C ; EXTRACT THE RELATIVE POSITION WITHIN PHYSICAL BLOCK. + OR L ; AND ADD IT TOO LOGICAL SECTOR. + LD L,A + LD (BLKNMBR),HL ; AND STORE. + RET +; +; SET (HL) TO POINT TO EXTENT BYTE IN FCB. +; +SETEXT: LD HL,(PARAMS) + LD DE,12 ; IT IS THE TWELTH BYTE. + ADD HL,DE + RET +; +; SET (HL) TO POINT TO RECORD COUNT BYTE IN FCB AND (DE) TO +; NEXT RECORD NUMBER BYTE. +; +SETHLDE:LD HL,(PARAMS) + LD DE,15 ; RECORD COUNT BYTE (#15). + ADD HL,DE + EX DE,HL + LD HL,17 ; NEXT RECORD NUMBER (#32). + ADD HL,DE + RET +; +; SAVE CURRENT FILE DATA FROM FCB. +; +STRDATA:CALL SETHLDE + LD A,(HL) ; GET AND STORE RECORD COUNT BYTE. + LD (SAVNREC),A + EX DE,HL + LD A,(HL) ; GET AND STORE NEXT RECORD NUMBER BYTE. + LD (SAVNXT),A + CALL SETEXT ; POINT TO EXTENT BYTE. + LD A,(EXTMASK) ; GET EXTENT MASK. + AND (HL) + LD (SAVEXT),A ; AND SAVE EXTENT HERE. + RET +; +; SET THE NEXT RECORD TO ACCESS. IF (MODE) IS SET TO 2, THEN +; THE LAST RECORD BYTE (SAVNREC) HAS THE CORRECT NUMBER TO ACCESS. +; FOR S.EQUENTIAL ACCESS, (MODE) WILL BE .EQUAL TO 1. +; +SETNREC:CALL SETHLDE + LD A,(MODE) ; GET S.EQUENTIAL FLAG (=1). + CP 2 ; A 2 INDICATES THAT NO ADDER IS NEEDED. + JP NZ,STNREC1 + XOR A ; CLEAR ADDER (RANDOM ACCESS?). +STNREC1:LD C,A + LD A,(SAVNREC) ; GET LAST RECORD NUMBER. + ADD A,C ; INCREMENT RECORD COUNT. + LD (HL),A ; AND SET FCB'S NEXT RECORD BYTE. + EX DE,HL + LD A,(SAVNXT) ; GET NEXT RECORD BYTE FROM STORAGE. + LD (HL),A ; AND PUT THIS INTO FCB AS NUMBER OF RECORDS USED. + RET +; +; SHIFT (HL) RIGHT (C) BITS. +; +SHIFTR: INC C +SHIFTR1:DEC C + RET Z + LD A,H + OR A + RRA + LD H,A + LD A,L + RRA + LD L,A + JP SHIFTR1 +; +; COMPUTE THE CHECK-SUM FOR THE DIRECTORY BUFFER. RETURN +; INTEGER SUM IN (A). +; +CHECKSUM: + LD C,128 ; LENGTH OF BUFFER. + LD HL,(DIRBUF) ; GET ITS LOCATION. + XOR A ; CLEAR SUMMATION BYTE. +CHKSUM1:ADD A,(HL) ; AND COMPUTE SUM IGNORING CARRIES. + INC HL + DEC C + JP NZ,CHKSUM1 + RET +; +; SHIFT (HL) LEFT (C) BITS. +; +SHIFTL: INC C +SHIFTL1:DEC C + RET Z + ADD HL,HL ; SHIFT LEFT 1 BIT. + JP SHIFTL1 +; +; ROUTINE TO SET A BIT IN A 16 BIT VALUE CONTAINED IN (BC). +; THE BIT SET DEPENDS ON THE CURRENT DRIVE SELECTION. +; +SETBIT: PUSH BC ; SAVE 16 BIT WORD. + LD A,(ACTIVE) ; GET ACTIVE DRIVE. + LD C,A + LD HL,1 + CALL SHIFTL ; SHIFT BIT 0 INTO PLACE. + POP BC ; NOW 'OR' THIS WITH THE ORIGINAL WORD. + LD A,C + OR L + LD L,A ; LOW BYTE DONE, DO HIGH BYTE. + LD A,B + OR H + LD H,A + RET +; +; EXTRACT THE WRITE PROTECT STATUS BIT FOR THE CURRENT DRIVE. +; THE RESULT IS RETURNED IN (A), BIT 0. +; +GETWPRT:LD HL,(WRTPRT) ; GET STATUS BYTES. + LD A,(ACTIVE) ; WHICH DRIVE IS CURRENT? + LD C,A + CALL SHIFTR ; SHIFT STATUS SUCH THAT BIT 0 IS THE + LD A,L ; ONE OF INTEREST FOR THIS DRIVE. + AND 01H ; AND ISOLATE IT. + RET +; +; FUNCTION TO WRITE PROTECT THE CURRENT DISK. +; +WRTPRTD:LD HL,WRTPRT ; POINT TO STATUS WORD. + LD C,(HL) ; SET (BC) .EQUAL TO THE STATUS. + INC HL + LD B,(HL) + CALL SETBIT ; AND SET THIS BIT ACCORDING TO CURRENT DRIVE. + LD (WRTPRT),HL ; THEN SAVE. + LD HL,(DIRSIZE) ; NOW SAVE DIRECTORY SIZE LIMIT. + INC HL ; REMEMBER THE LAST ONE. + EX DE,HL + LD HL,(SCRATCH1) ; AND STORE IT HERE. + LD (HL),E ; PUT LOW BYTE. + INC HL + LD (HL),D ; THEN HIGH BYTE. + RET +; +; CHECK FOR A READ ONLY FILE. +; +CHKROFL:CALL FCB2HL ; SET (HL) TO FILE ENTRY IN DIRECTORY BUFFER. +CKROF1: LD DE,9 ; LOOK AT BIT 7 OF THE NINTH BYTE. + ADD HL,DE + LD A,(HL) + RLA + RET NC ; RETURN IF OK. + LD HL,ROFILE ; ELSE, PRINT ERROR MESSAGE AND TERMINATE. + JP JUMPHL +; +; CHECK THE WRITE PROTECT STATUS OF THE ACTIVE DISK. +; +CHKWPRT:CALL GETWPRT + RET Z ; RETURN IF OK. + LD HL,RODISK ; ELSE PRINT MESSAGE AND TERMINATE. + JP JUMPHL +; +; ROUTINE TO SET (HL) POINTING TO THE PROPER ENTRY IN THE +; DIRECTORY BUFFER. +; +FCB2HL: LD HL,(DIRBUF) ; GET ADDRESS OF BUFFER. + LD A,(FCBPOS) ; RELATIVE POSITION OF FILE. +; +; ROUTINE TO ADD (A) TO (HL). +; +ADDA2HL:ADD A,L + LD L,A + RET NC + INC H ; TAKE CARE OF ANY CARRY. + RET +; +; ROUTINE TO GET THE 'S2' BYTE FROM THE FCB SUPPLIED IN +; THE INITIAL PARAMETER SPECIFICATION. +; +GETS2: LD HL,(PARAMS) ; GET ADDRESS OF FCB. + LD DE,14 ; RELATIVE POSITION OF 'S2'. + ADD HL,DE + LD A,(HL) ; EXTRACT THIS BYTE. + RET +; +; CLEAR THE 'S2' BYTE IN THE FCB. +; +CLEARS2:CALL GETS2 ; THIS SETS (HL) POINTING TO IT. + LD (HL),0 ; NOW CLEAR IT. + RET +; +; SET BIT 7 IN THE 'S2' BYTE OF THE FCB. +; +SETS2B7:CALL GETS2 ; GET THE BYTE. + OR 80H ; AND SET BIT 7. + LD (HL),A ; THEN STORE. + RET +; +; COMPARE (FILEPOS) WITH (SCRATCH1) AND SET FLAGS BASED ON +; THE DIFFERENCE. THIS CHECKS TO SEE IF THERE ARE MORE FILE +; NAMES IN THE DIRECTORY. WE ARE AT (FILEPOS) AND THERE ARE +; (SCRATCH1) OF THEM TO CHECK. +; +MOREFLS:LD HL,(FILEPOS) ; WE ARE HERE. + EX DE,HL + LD HL,(SCRATCH1) ; AND DON'T GO PAST HERE. + LD A,E ; COMPUTE DIFFERENCE BUT DON'T KEEP. + SUB (HL) + INC HL + LD A,D + SBC A,(HL) ; SET CARRY IF NO MORE NAMES. + RET +; +; CALL THIS ROUTINE TO PREVENT (SCRATCH1) FROM BEING GREATER +; THAN (FILEPOS). +; +CHKNMBR:CALL MOREFLS ; SCRATCH1 TOO BIG? + RET C + INC DE ; YES, RESET IT TO (FILEPOS). + LD (HL),D + DEC HL + LD (HL),E + RET +; +; COMPUTE (HL)=(DE)-(HL) +; +SUBHL: LD A,E ; COMPUTE DIFFERENCE. + SUB L + LD L,A ; STORE LOW BYTE. + LD A,D + SBC A,H + LD H,A ; AND THEN HIGH BYTE. + RET +; +; SET THE DIRECTORY CHECKSUM BYTE. +; +SETDIR: LD C,0FFH +; +; ROUTINE TO SET OR COMPARE THE DIRECTORY CHECKSUM BYTE. IF +; (C)=0FFH, THEN THIS WILL SET THE CHECKSUM BYTE. ELSE THE BYTE +; WILL BE CHECKED. IF THE CHECK FAILS (THE DISK HAS BEEN CHANGED), +; THEN THIS DISK WILL BE WRITE PROTECTED. +; +CHECKDIR: + LD HL,(CKSUMTBL) + EX DE,HL + LD HL,(ALLOC1) + CALL SUBHL + RET NC ; OK IF (CKSUMTBL) > (ALLOC1), SO RETURN. + PUSH BC + CALL CHECKSUM ; ELSE COMPUTE CHECKSUM. + LD HL,(CHKVECT) ; GET ADDRESS OF CHECKSUM TABLE. + EX DE,HL + LD HL,(CKSUMTBL) + ADD HL,DE ; SET (HL) TO POINT TO BYTE FOR THIS DRIVE. + POP BC + INC C ; SET OR CHECK ? + JP Z,CHKDIR1 + CP (HL) ; CHECK THEM. + RET Z ; RETURN IF THEY ARE THE SAME. + CALL MOREFLS ; NOT THE SAME, DO WE CARE? + RET NC + CALL WRTPRTD ; YES, MARK THIS AS WRITE PROTECTED. + RET +CHKDIR1:LD (HL),A ; JUST SET THE BYTE. + RET +; +; DO A WRITE TO THE DIRECTORY OF THE CURRENT DISK. +; +DIRWRITE: + CALL SETDIR ; SET CHECKSUM BYTE. + CALL DIRDMA ; SET DIRECTORY DMA ADDRESS. + LD C,1 ; TELL THE BIOS TO ACTUALLY WRITE. + CALL DOWRITE ; THEN DO THE WRITE. + JP DEFDMA +; +; READ FROM THE DIRECTORY. +; +DIRREAD:CALL DIRDMA ; SET THE DIRECTORY DMA ADDRESS. + CALL DOREAD ; AND READ IT. +; +; ROUTINE TO SET THE DMA ADDRESS TO THE USERS CHOICE. +; +DEFDMA: LD HL,USERDMA ; RESET THE DEFAULT DMA ADDRESS AND RETURN. + JP DIRDMA1 +; +; ROUTINE TO SET THE DMA ADDRESS FOR DIRECTORY WORK. +; +DIRDMA: LD HL,DIRBUF +; +; SET THE DMA ADDRESS. ON ENTRY, (HL) POINTS TO +; WORD CONTAINING THE DESIRED DMA ADDRESS. +; +DIRDMA1:LD C,(HL) + INC HL + LD B,(HL) ; SETUP (BC) AND GO TO THE BIOS TO SET IT. + JP SETDMA +; +; MOVE THE DIRECTORY BUFFER INTO USER'S DMA SPACE. +; +MOVEDIR:LD HL,(DIRBUF) ; BUFFER IS LOCATED HERE, AND + EX DE,HL + LD HL,(USERDMA) ; PUT IT HERE. + LD C,128 ; THIS IS ITS LENGTH. + JP DE2HL ; MOVE IT NOW AND RETURN. +; +; CHECK (FILEPOS) AND SET THE ZERO FLAG IF IT .EQUALS 0FFFFH. +; +CKFILPOS: + LD HL,FILEPOS + LD A,(HL) + INC HL + CP (HL) ; ARE BOTH BYTES THE SAME? + RET NZ + INC A ; YES, BUT ARE THEY EACH 0FFH? + RET +; +; SET LOCATION (FILEPOS) TO 0FFFFH. +; +STFILPOS: + LD HL,0FFFFH + LD (FILEPOS),HL + RET +; +; MOVE ON TO THE NEXT FILE POSITION WITHIN THE CURRENT +; DIRECTORY BUFFER. IF NO MORE EXIST, SET POINTER TO 0FFFFH +; AND THE CALLING ROUTINE WILL CHECK FOR THIS. ENTER WITH (C) +; .EQUAL TO 0FFH TO CAUSE THE CHECKSUM BYTE TO BE SET, ELSE WE +; WILL CHECK THIS DISK AND SET WRITE PROTECT IF CHECKSUMS ARE +; NOT THE SAME (APPLIES ONLY IF ANOTHER DIRECTORY SECTOR MUST +; BE READ). +; +NXENTRY:LD HL,(DIRSIZE) ; GET DIRECTORY ENTRY SIZE LIMIT. + EX DE,HL + LD HL,(FILEPOS) ; GET CURRENT COUNT. + INC HL ; GO ON TO THE NEXT ONE. + LD (FILEPOS),HL + CALL SUBHL ; (HL)=(DIRSIZE)-(FILEPOS) + JP NC,NXENT1 ; IS THERE MORE ROOM LEFT? + JP STFILPOS ; NO. SET THIS FLAG AND RETURN. +NXENT1: LD A,(FILEPOS) ; GET FILE POSITION WITHIN DIRECTORY. + AND 03H ; ONLY LOOK WITHIN THIS SECTOR (ONLY 4 ENTRIES FIT). + LD B,5 ; CONVERT TO RELATIVE POSITION (32 BYTES EACH). +NXENT2: ADD A,A ; NOTE THAT THIS IS NOT EFFICIENT CODE. + DEC B ; 5 'ADD A'S WOULD BE BETTER. + JP NZ,NXENT2 + LD (FCBPOS),A ; SAVE IT AS POSITION OF FCB. + OR A + RET NZ ; RETURN IF WE ARE WITHIN BUFFER. + PUSH BC + CALL TRKSEC ; WE NEED THE NEXT DIRECTORY SECTOR. + CALL DIRREAD + POP BC + JP CHECKDIR +; +; ROUTINE TO TO GET A BIT FROM THE DISK SPACE ALLOCATION +; MAP. IT IS RETURNED IN (A), BIT POSITION 0. ON ENTRY TO HERE, +; SET (BC) TO THE BLOCK NUMBER ON THE DISK TO CHECK. +; ON RETURN, (D) WILL CONTAIN THE ORIGINAL BIT POSITION FOR +; THIS BLOCK NUMBER AND (HL) WILL POINT TO THE ADDRESS FOR IT. +; +CKBITMAP: + LD A,C ; DETERMINE BIT NUMBER OF INTEREST. + AND 07H ; COMPUTE (D)=(E)=(C AND 7)+1. + INC A + LD E,A ; SAVE PARTICULAR BIT NUMBER. + LD D,A +; +; COMPUTE (BC)=(BC)/8. +; + LD A,C + RRCA ; NOW SHIFT RIGHT 3 BITS. + RRCA + RRCA + AND 1FH ; AND CLEAR BITS 7,6,5. + LD C,A + LD A,B + ADD A,A ; NOW SHIFT (B) INTO BITS 7,6,5. + ADD A,A + ADD A,A + ADD A,A + ADD A,A + OR C ; AND ADD IN (C). + LD C,A ; OK, (C) HA BEEN COMPLETED. + LD A,B ; IS THERE A BETTER WAY OF DOING THIS? + RRCA + RRCA + RRCA + AND 1FH + LD B,A ; AND NOW (B) IS COMPLETED. +; +; USE THIS AS AN OFFSET INTO THE DISK SPACE ALLOCATION +; TABLE. +; + LD HL,(ALOCVECT) + ADD HL,BC + LD A,(HL) ; NOW GET CORRECT BYTE. +CKBMAP1:RLCA ; GET CORRECT BIT INTO POSITION 0. + DEC E + JP NZ,CKBMAP1 + RET +; +; SET OR CLEAR THE BIT MAP SUCH THAT BLOCK NUMBER (BC) WILL BE MARKED +; AS USED. ON ENTRY, IF (E)=0 THEN THIS BIT WILL BE CLEARED, IF IT .EQUALS +; 1 THEN IT WILL BE SET (DON'T USE ANYOTHER VALUES). +; +STBITMAP: + PUSH DE + CALL CKBITMAP ; GET THE BYTE OF INTEREST. + AND 0FEH ; CLEAR THE AFFECTED BIT. + POP BC + OR C ; AND NOW SET IT ACORDING TO (C). +; +; ENTRY TO RESTORE THE ORIGINAL BIT POSITION AND THEN STORE +; IN TABLE. (A) CONTAINS THE VALUE, (D) CONTAINS THE BIT +; POSITION (1-8), AND (HL) POINTS TO THE ADDRESS WITHIN THE +; SPACE ALLOCATION TABLE FOR THIS BYTE. +; +STBMAP1:RRCA ; RESTORE ORIGINAL BIT POSITION. + DEC D + JP NZ,STBMAP1 + LD (HL),A ; AND STOR BYTE IN TABLE. + RET +; +; SET/CLEAR SPACE USED BITS IN ALLOCATION MAP FOR THIS FILE. +; ON ENTRY, (C)=1 TO SET THE MAP AND (C)=0 TO CLEAR IT. +; +SETFILE:CALL FCB2HL ; GET ADDRESS OF FCB + LD DE,16 + ADD HL,DE ; GET TO BLOCK NUMBER BYTES. + PUSH BC + LD C,17 ; CHECK ALL 17 BYTES (MAX) OF TABLE. +SETFL1: POP DE + DEC C ; DONE ALL BYTES YET? + RET Z + PUSH DE + LD A,(BIGDISK) ; CHECK DISK SIZE FOR 16 BIT BLOCK NUMBERS. + OR A + JP Z,SETFL2 + PUSH BC ; ONLY 8 BIT NUMBERS. SET (BC) TO THIS ONE. + PUSH HL + LD C,(HL) ; GET LOW BYTE FROM TABLE, ALWAYS + LD B,0 ; SET HIGH BYTE TO ZERO. + JP SETFL3 +SETFL2: DEC C ; FOR 16 BIT BLOCK NUMBERS, ADJUST COUNTER. + PUSH BC + LD C,(HL) ; NOW GET BOTH THE LOW AND HIGH BYTES. + INC HL + LD B,(HL) + PUSH HL +SETFL3: LD A,C ; BLOCK USED? + OR B + JP Z,SETFL4 + LD HL,(DSKSIZE) ; IS THIS BLOCK NUMBER WITHIN THE + LD A,L ; SPACE ON THE DISK? + SUB C + LD A,H + SBC A,B + CALL NC,STBITMAP ; YES, SET THE PROPER BIT. +SETFL4: POP HL ; POINT TO NEXT BLOCK NUMBER IN FCB. + INC HL + POP BC + JP SETFL1 +; +; CONSTRUCT THE SPACE USED ALLOCATION BIT MAP FOR THE ACTIVE +; DRIVE. IF A FILE NAME STARTS WITH '$' AND IT IS UNDER THE +; CURRENT USER NUMBER, THEN (STATUS) IS SET TO MINUS 1. OTHERWISE +; IT IS NOT SET AT ALL. +; +BITMAP: LD HL,(DSKSIZE) ; COMPUTE SIZE OF ALLOCATION TABLE. + LD C,3 + CALL SHIFTR ; (HL)=(HL)/8. + INC HL ; AT LEASE 1 BYTE. + LD B,H + LD C,L ; SET (BC) TO THE ALLOCATION TABLE LENGTH. +; +; INITIALIZE THE BITMAP FOR THIS DRIVE. RIGHT NOW, THE FIRST +; TWO BYTES ARE SPECIFIED BY THE DISK PARAMETER BLOCK. HOWEVER +; A PATCH COULD BE ENTERED HERE IF IT WERE NECESSARY TO SETUP +; THIS TABLE IN A SPECIAL MANNOR. FOR EXAMPLE, THE BIOS COULD +; DETERMINE LOCATIONS OF 'BAD BLOCKS' AND SET THEM AS ALREADY +; 'USED' IN THE MAP. +; + LD HL,(ALOCVECT) ; NOW ZERO OUT THE TABLE NOW. +BITMAP1:LD (HL),0 + INC HL + DEC BC + LD A,B + OR C + JP NZ,BITMAP1 + LD HL,(ALLOC0) ; GET INITIAL SPACE USED BY DIRECTORY. + EX DE,HL + LD HL,(ALOCVECT) ; AND PUT THIS INTO MAP. + LD (HL),E + INC HL + LD (HL),D +; +; END OF INITIALIZATION PORTION. +; + CALL HOMEDRV ; NOW HOME THE DRIVE. + LD HL,(SCRATCH1) + LD (HL),3 ; FORCE NEXT DIRECTORY R.EQUEST TO READ + INC HL ; IN A SECTOR. + LD (HL),0 + CALL STFILPOS ; CLEAR INITIAL FILE POSITION ALSO. +BITMAP2:LD C,0FFH ; READ NEXT FILE NAME IN DIRECTORY + CALL NXENTRY ; AND SET CHECKSUM BYTE. + CALL CKFILPOS ; IS THERE ANOTHER FILE? + RET Z + CALL FCB2HL ; YES, GET ITS ADDRESS. + LD A,0E5H + CP (HL) ; EMPTY FILE ENTRY? + JP Z,BITMAP2 + LD A,(USERNO) ; NO, CORRECT USER NUMBER? + CP (HL) + JP NZ,BITMAP3 + INC HL + LD A,(HL) ; YES, DOES NAME START WITH A '$'? + SUB '$' + JP NZ,BITMAP3 + DEC A ; YES, SET ATATUS TO MINUS ONE. + LD (STATUS),A +BITMAP3:LD C,1 ; NOW SET THIS FILE'S SPACE AS USED IN BIT MAP. + CALL SETFILE + CALL CHKNMBR ; KEEP (SCRATCH1) IN BOUNDS. + JP BITMAP2 +; +; SET THE STATUS (STATUS) AND RETURN. +; +STSTATUS: + LD A,(FNDSTAT) + JP SETSTAT +; +; CHECK EXTENTS IN (A) AND (C). SET THE ZERO FLAG IF THEY +; ARE THE SAME. THE NUMBER OF 16K CHUNKS OF DISK SPACE THAT +; THE DIRECTORY EXTENT COVERS IS EXPRESSAD IS (EXTMASK+1). +; NO REGISTERS ARE MODIFIED. +; +SAMEXT: PUSH BC + PUSH AF + LD A,(EXTMASK) ; GET EXTENT MASK AND USE IT TO + CPL ; TO COMPARE BOTH EXTENT NUMBERS. + LD B,A ; SAVE RESULTING MASK HERE. + LD A,C ; MASK FIRST EXTENT AND SAVE IN (C). + AND B + LD C,A + POP AF ; NOW MASK SECOND EXTENT AND COMPARE + AND B ; WITH THE FIRST ONE. + SUB C + AND 1FH ; (* ONLY CHECK BUTS 0-4 *) + POP BC ; THE ZERO FLAG IS SET IF THEY ARE THE SAME. + RET ; RESTORE (BC) AND RETURN. +; +; SEARCH FOR THE FIRST OCCURENCE OF A FILE NAME. ON ENTRY, +; REGISTER (C) SHOULD CONTAIN THE NUMBER OF BYTES OF THE FCB +; THAT MUST MATCH. +; +FINDFST:LD A,0FFH + LD (FNDSTAT),A + LD HL,COUNTER ; SAVE CHARACTER COUNT. + LD (HL),C + LD HL,(PARAMS) ; GET FILENAME TO MATCH. + LD (SAVEFCB),HL ; AND SAVE. + CALL STFILPOS ; CLEAR INITIAL FILE POSITION (SET TO 0FFFFH). + CALL HOMEDRV ; HOME THE DRIVE. +; +; ENTRY TO LOCATE THE NEXT OCCURENCE OF A FILENAME WITHIN THE +; DIRECTORY. THE DISK IS NOT EXPECTED TO HAVE BEEN CHANGED. IF +; IT WAS, THEN IT WILL BE WRITE PROTECTED. +; +FINDNXT:LD C,0 ; WRITE PROTECT THE DISK IF CHANGED. + CALL NXENTRY ; GET NEXT FILENAME ENTRY IN DIRECTORY. + CALL CKFILPOS ; IS FILE POSITION = 0FFFFH? + JP Z,FNDNXT6 ; YES, EXIT NOW THEN. + LD HL,(SAVEFCB) ; SET (DE) POINTING TO FILENAME TO MATCH. + EX DE,HL + LD A,(DE) + CP 0E5H ; EMPTY DIRECTORY ENTRY? + JP Z,FNDNXT1 ; (* ARE WE TRYING TO RESERECT ERASED ENTRIES? *) + PUSH DE + CALL MOREFLS ; MORE FILES IN DIRECTORY? + POP DE + JP NC,FNDNXT6 ; NO MORE. EXIT NOW. +FNDNXT1:CALL FCB2HL ; GET ADDRESS OF THIS FCB IN DIRECTORY. + LD A,(COUNTER) ; GET NUMBER OF BYTES (CHARACTERS) TO CHECK. + LD C,A + LD B,0 ; INITIALIZE BYTE POSITION COUNTER. +FNDNXT2:LD A,C ; ARE WE DONE WITH THE COMPARE? + OR A + JP Z,FNDNXT5 + LD A,(DE) ; NO, CHECK NEXT BYTE. + CP '?' ; DON'T CARE ABOUT THIS CHARACTER? + JP Z,FNDNXT4 + LD A,B ; GET BYTES POSITION IN FCB. + CP 13 ; DON'T CARE ABOUT THE THIRTEENTH BYTE EITHER. + JP Z,FNDNXT4 + CP 12 ; EXTENT BYTE? + LD A,(DE) + JP Z,FNDNXT3 + SUB (HL) ; OTHERWISE COMPARE CHARACTERS. + AND 7FH + JP NZ,FINDNXT ; NOT THE SAME, CHECK NEXT ENTRY. + JP FNDNXT4 ; SO FAR SO GOOD, KEEP CHECKING. +FNDNXT3:PUSH BC ; CHECK THE EXTENT BYTE HERE. + LD C,(HL) + CALL SAMEXT + POP BC + JP NZ,FINDNXT ; NOT THE SAME, LOOK SOME MORE. +; +; SO FAR THE NAMES COMPARE. BUMP POINTERS TO THE NEXT BYTE +; AND CONTINUE UNTIL ALL (C) CHARACTERS HAVE BEEN CHECKED. +; +FNDNXT4:INC DE ; BUMP POINTERS. + INC HL + INC B + DEC C ; ADJUST CHARACTER COUNTER. + JP FNDNXT2 +FNDNXT5:LD A,(FILEPOS) ; RETURN THE POSITION OF THIS ENTRY. + AND 03H + LD (STATUS),A + LD HL,FNDSTAT + LD A,(HL) + RLA + RET NC + XOR A + LD (HL),A + RET +; +; FILENAME WAS NOT FOUND. SET APPROPRIATE STATUS. +; +FNDNXT6:CALL STFILPOS ; SET (FILEPOS) TO 0FFFFH. + LD A,0FFH ; SAY NOT LOCATED. + JP SETSTAT +; +; ERASE FILES FROM THE DIRECTORY. ONLY THE FIRST BYTE OF THE +; FCB WILL BE AFFECTED. IT IS SET TO (E5). +; +ERAFILE:CALL CHKWPRT ; IS DISK WRITE PROTECTED? + LD C,12 ; ONLY COMPARE FILE NAMES. + CALL FINDFST ; GET FIRST FILE NAME. +ERAFIL1:CALL CKFILPOS ; ANY FOUND? + RET Z ; NOPE, WE MUST BE DONE. + CALL CHKROFL ; IS FILE READ ONLY? + CALL FCB2HL ; NOPE, GET ADDRESS OF FCB AND + LD (HL),0E5H ; SET FIRST BYTE TO 'EMPTY'. + LD C,0 ; CLEAR THE SPACE FROM THE BIT MAP. + CALL SETFILE + CALL DIRWRITE ; NOW WRITE THE DIRECTORY SECTOR BACK OUT. + CALL FINDNXT ; FIND THE NEXT FILE NAME. + JP ERAFIL1 ; AND REPEAT PROCESS. +; +; LOOK THROUGH THE SPACE ALLOCATION MAP (BIT MAP) FOR THE +; NEXT AVAILABLE BLOCK. START SEARCHING AT BLOCK NUMBER (BC-1). +; THE SEARCH PROCEDURE IS TO LOOK FOR AN EMPTY BLOCK THAT IS +; BEFORE THE STARTING BLOCK. IF NOT EMPTY, LOOK AT A LATER +; BLOCK NUMBER. IN THIS WAY, WE RETURN THE CLOSEST EMPTY BLOCK +; ON EITHER SIDE OF THE 'TARGET' BLOCK NUMBER. THIS WILL SPEED +; ACCESS ON RANDOM DEVICES. FOR SERIAL DEVICES, THIS SHOULD BE +; CHANGED TO LOOK IN THE FORWARD DIRECTION FIRST AND THEN START +; AT THE FRONT AND SEARCH SOME MORE. +; +; ON RETURN, (DE)= BLOCK NUMBER THAT IS EMPTY AND (HL) =0 +; IF NO EMPRY BLOCK WAS FOUND. +; +FNDSPACE: + LD D,B ; SET (DE) AS THE BLOCK THAT IS CHECKED. + LD E,C +; +; LOOK BEFORE TARGET BLOCK. REGISTERS (BC) ARE USED AS THE LOWER +; POINTER AND (DE) AS THE UPPER POINTER. +; +FNDSPA1:LD A,C ; IS BLOCK 0 SPECIFIED? + OR B + JP Z,FNDSPA2 + DEC BC ; NOPE, CHECK PREVIOUS BLOCK. + PUSH DE + PUSH BC + CALL CKBITMAP + RRA ; IS THIS BLOCK EMPTY? + JP NC,FNDSPA3 ; YES. USE THIS. +; +; NOTE THAT THE ABOVE LOGIC GETS THE FIRST BLOCK THAT IT FINDS +; THAT IS EMPTY. THUS A FILE COULD BE WRITTEN 'BACKWARD' MAKING +; IT VERY SLOW TO ACCESS. THIS COULD BE CHANGED TO LOOK FOR THE +; FIRST EMPTY BLOCK AND THEN CONTINUE UNTIL THE START OF THIS +; EMPTY SPACE IS LOCATED AND THEN USED THAT STARTING BLOCK. +; THIS SHOULD HELP SPEED UP ACCESS TO SOME FILES ESPECIALLY ON +; A WELL USED DISK WITH LOTS OF FAIRLY SMALL 'HOLES'. +; + POP BC ; NOPE, CHECK SOME MORE. + POP DE +; +; NOW LOOK AFTER TARGET BLOCK. +; +FNDSPA2:LD HL,(DSKSIZE) ; IS BLOCK (DE) WITHIN DISK LIMITS? + LD A,E + SUB L + LD A,D + SBC A,H + JP NC,FNDSPA4 + INC DE ; YES, MOVE ON TO NEXT ONE. + PUSH BC + PUSH DE + LD B,D + LD C,E + CALL CKBITMAP ; CHECK IT. + RRA ; EMPTY? + JP NC,FNDSPA3 + POP DE ; NOPE, CONTINUE SEARCHING. + POP BC + JP FNDSPA1 +; +; EMPTY BLOCK FOUND. SET IT AS USED AND RETURN WITH (HL) +; POINTING TO IT (TRUE?). +; +FNDSPA3:RLA ; RESET BYTE. + INC A ; AND SET BIT 0. + CALL STBMAP1 ; UPDATE BIT MAP. + POP HL ; SET RETURN REGISTERS. + POP DE + RET +; +; FREE BLOCK WAS NOT FOUND. IF (BC) IS NOT ZERO, THEN WE HAVE +; NOT CHECKED ALL OF THE DISK SPACE. +; +FNDSPA4:LD A,C + OR B + JP NZ,FNDSPA1 + LD HL,0 ; SET 'NOT FOUND' STATUS. + RET +; +; MOVE A COMPLETE FCB ENTRY INTO THE DIRECTORY AND WRITE IT. +; +FCBSET: LD C,0 + LD E,32 ; LENGTH OF EACH ENTRY. +; +; MOVE (E) BYTES FROM THE FCB POINTED TO BY (PARAMS) INTO +; FCB IN DIRECTORY STARTING AT RELATIVE BYTE (C). THIS UPDATED +; DIRECTORY BUFFER IS THEN WRITTEN TO THE DISK. +; +UPDATE: PUSH DE + LD B,0 ; SET (BC) TO RELATIVE BYTE POSITION. + LD HL,(PARAMS) ; GET ADDRESS OF FCB. + ADD HL,BC ; COMPUTE STARTING BYTE. + EX DE,HL + CALL FCB2HL ; GET ADDRESS OF FCB TO UPDATE IN DIRECTORY. + POP BC ; SET (C) TO NUMBER OF BYTES TO CHANGE. + CALL DE2HL +UPDATE1:CALL TRKSEC ; DETERMINE THE TRACK AND SECTOR AFFECTED. + JP DIRWRITE ; THEN WRITE THIS SECTOR OUT. +; +; ROUTINE TO CHANGE THE NAME OF ALL FILES ON THE DISK WITH A +; SPECIFIED NAME. THE FCB CONTAINS THE CURRENT NAME AS THE +; FIRST 12 CHARACTERS AND THE NEW NAME 16 BYTES INTO THE FCB. +; +CHGNAMES: + CALL CHKWPRT ; CHECK FOR A WRITE PROTECTED DISK. + LD C,12 ; MATCH FIRST 12 BYTES OF FCB ONLY. + CALL FINDFST ; GET FIRST NAME. + LD HL,(PARAMS) ; GET ADDRESS OF FCB. + LD A,(HL) ; GET USER NUMBER. + LD DE,16 ; MOVE OVER TO DESIRED NAME. + ADD HL,DE + LD (HL),A ; KEEP SAME USER NUMBER. +CHGNAM1:CALL CKFILPOS ; ANY MATCHING FILE FOUND? + RET Z ; NO, WE MUST BE DONE. + CALL CHKROFL ; CHECK FOR READ ONLY FILE. + LD C,16 ; START 16 BYTES INTO FCB. + LD E,12 ; AND UPDATE THE FIRST 12 BYTES OF DIRECTORY. + CALL UPDATE + CALL FINDNXT ; GET TE NEXT FILE NAME. + JP CHGNAM1 ; AND CONTINUE. +; +; UPDATE A FILES ATTRIBUTES. THE PROCEDURE IS TO SEARCH FOR +; EVERY FILE WITH THE SAME NAME AS SHOWN IN FCB (IGNORING BIT 7) +; AND THEN TO UPDATE IT (WHICH INCLUDES BIT 7). NO OTHER CHANGES +; ARE MADE. +; +SAVEATTR: + LD C,12 ; MATCH FIRST 12 BYTES. + CALL FINDFST ; LOOK FOR FIRST FILENAME. +SAVATR1:CALL CKFILPOS ; WAS ONE FOUND? + RET Z ; NOPE, WE MUST BE DONE. + LD C,0 ; YES, UPDATE THE FIRST 12 BYTES NOW. + LD E,12 + CALL UPDATE ; UPDATE FILENAME AND WRITE DIRECTORY. + CALL FINDNXT ; AND GET THE NEXT FILE. + JP SAVATR1 ; THEN CONTINUE UNTIL DONE. +; +; OPEN A FILE (NAME SPECIFIED IN FCB). +; +OPENIT: LD C,15 ; COMPARE THE FIRST 15 BYTES. + CALL FINDFST ; GET THE FIRST ONE IN DIRECTORY. + CALL CKFILPOS ; ANY AT ALL? + RET Z +OPENIT1:CALL SETEXT ; POINT TO EXTENT BYTE WITHIN USERS FCB. + LD A,(HL) ; AND GET IT. + PUSH AF ; SAVE IT AND ADDRESS. + PUSH HL + CALL FCB2HL ; POINT TO FCB IN DIRECTORY. + EX DE,HL + LD HL,(PARAMS) ; THIS IS THE USERS COPY. + LD C,32 ; MOVE IT INTO USERS SPACE. + PUSH DE + CALL DE2HL + CALL SETS2B7 ; SET BIT 7 IN 'S2' BYTE (UNMODIFIED). + POP DE ; NOW GET THE EXTENT BYTE FROM THIS FCB. + LD HL,12 + ADD HL,DE + LD C,(HL) ; INTO (C). + LD HL,15 ; NOW GET THE RECORD COUNT BYTE INTO (B). + ADD HL,DE + LD B,(HL) + POP HL ; KEEP THE SAME EXTENT AS THE USER HAD ORIGINALLY. + POP AF + LD (HL),A + LD A,C ; IS IT THE SAME AS IN THE DIRECTORY FCB? + CP (HL) + LD A,B ; IF YES, THEN USE THE SAME RECORD COUNT. + JP Z,OPENIT2 + LD A,0 ; IF THE USER SPECIFIED AN EXTENT GREATER THAN + JP C,OPENIT2 ; THE ONE IN THE DIRECTORY, THEN SET RECORD COUNT TO 0. + LD A,128 ; OTHERWISE SET TO MAXIMUM. +OPENIT2:LD HL,(PARAMS) ; SET RECORD COUNT IN USERS FCB TO (A). + LD DE,15 + ADD HL,DE ; COMPUTE RELATIVE POSITION. + LD (HL),A ; AND SET THE RECORD COUNT. + RET +; +; MOVE TWO BYTES FROM (DE) TO (HL) IF (AND ONLY IF) (HL) +; POINT TO A ZERO VALUE (16 BIT). +; RETURN WITH ZERO FLAG SET IT (DE) WAS MOVED. REGISTERS (DE) +; AND (HL) ARE NOT CHANGED. HOWEVER (A) IS. +; +MOVEWORD: + LD A,(HL) ; CHECK FOR A ZERO WORD. + INC HL + OR (HL) ; BOTH BYTES ZERO? + DEC HL + RET NZ ; NOPE, JUST RETURN. + LD A,(DE) ; YES, MOVE TWO BYTES FROM (DE) INTO + LD (HL),A ; THIS ZERO SPACE. + INC DE + INC HL + LD A,(DE) + LD (HL),A + DEC DE ; DON'T DISTURB THESE REGISTERS. + DEC HL + RET +; +; GET HERE TO CLOSE A FILE SPECIFIED BY (FCB). +; +CLOSEIT:XOR A ; CLEAR STATUS AND FILE POSITION BYTES. + LD (STATUS),A + LD (FILEPOS),A + LD (FILEPOS+1),A + CALL GETWPRT ; GET WRITE PROTECT BIT FOR THIS DRIVE. + RET NZ ; JUST RETURN IF IT IS SET. + CALL GETS2 ; ELSE GET THE 'S2' BYTE. + AND 80H ; AND LOOK AT BIT 7 (FILE UNMODIFIED?). + RET NZ ; JUST RETURN IF SET. + LD C,15 ; ELSE LOOK UP THIS FILE IN DIRECTORY. + CALL FINDFST + CALL CKFILPOS ; WAS IT FOUND? + RET Z ; JUST RETURN IF NOT. + LD BC,16 ; SET (HL) POINTING TO RECORDS USED SECTION. + CALL FCB2HL + ADD HL,BC + EX DE,HL + LD HL,(PARAMS) ; DO THE SAME FOR USERS SPECIFIED FCB. + ADD HL,BC + LD C,16 ; THIS MANY BYTES ARE PRESENT IN THIS EXTENT. +CLOSEIT1: + LD A,(BIGDISK) ; 8 OR 16 BIT RECORD NUMBERS? + OR A + JP Z,CLOSEIT4 + LD A,(HL) ; JUST 8 BIT. GET ONE FROM USERS FCB. + OR A + LD A,(DE) ; NOW GET ONE FROM DIRECTORY FCB. + JP NZ,CLOSEIT2 + LD (HL),A ; USERS BYTE WAS ZERO. UPDATE FROM DIRECTORY. +CLOSEIT2: + OR A + JP NZ,CLOSEIT3 + LD A,(HL) ; DIRECTORIES BYTE WAS ZERO, UPDATE FROM USERS FCB. + LD (DE),A +CLOSEIT3: + CP (HL) ; IF NEITHER ONE OF THESE BYTES WERE ZERO, + JP NZ,CLOSEIT7 ; THEN CLOSE ERROR IF THEY ARE NOT THE SAME. + JP CLOSEIT5 ; OK SO FAR, GET TO NEXT BYTE IN FCBS. +CLOSEIT4: + CALL MOVEWORD ; UPDATE USERS FCB IF IT IS ZERO. + EX DE,HL + CALL MOVEWORD ; UPDATE DIRECTORIES FCB IF IT IS ZERO. + EX DE,HL + LD A,(DE) ; IF THESE TWO VALUES ARE NO DIFFERENT, + CP (HL) ; THEN A CLOSE ERROR OCCURED. + JP NZ,CLOSEIT7 + INC DE ; CHECK SECOND BYTE. + INC HL + LD A,(DE) + CP (HL) + JP NZ,CLOSEIT7 + DEC C ; REMEMBER 16 BIT VALUES. +CLOSEIT5: + INC DE ; BUMP TO NEXT ITEM IN TABLE. + INC HL + DEC C ; THERE ARE 16 ENTRIES ONLY. + JP NZ,CLOSEIT1 ; CONTINUE IF MORE TO DO. + LD BC,0FFECH ; BACKUP 20 PLACES (EXTENT BYTE). + ADD HL,BC + EX DE,HL + ADD HL,BC + LD A,(DE) + CP (HL) ; DIRECTORY'S EXTENT ALREADY GREATER THAN THE + JP C,CLOSEIT6 ; USERS EXTENT? + LD (HL),A ; NO, UPDATE DIRECTORY EXTENT. + LD BC,3 ; AND UPDATE THE RECORD COUNT BYTE IN + ADD HL,BC ; DIRECTORIES FCB. + EX DE,HL + ADD HL,BC + LD A,(HL) ; GET FROM USER. + LD (DE),A ; AND PUT IN DIRECTORY. +CLOSEIT6: + LD A,0FFH ; SET 'WAS OPEN AND IS NOW CLOSED' BYTE. + LD (CLOSEFLG),A + JP UPDATE1 ; UPDATE THE DIRECTORY NOW. +CLOSEIT7: + LD HL,STATUS ; SET RETURN STATUS AND THEN RETURN. + DEC (HL) + RET +; +; ROUTINE TO GET THE NEXT EMPTY SPACE IN THE DIRECTORY. IT +; WILL THEN BE CLEARED FOR USE. +; +GETEMPTY: + CALL CHKWPRT ; MAKE SURE DISK IS NOT WRITE PROTECTED. + LD HL,(PARAMS) ; SAVE CURRENT PARAMETERS (FCB). + PUSH HL + LD HL,EMPTYFCB ; USE SPECIAL ONE FOR EMPTY SPACE. + LD (PARAMS),HL + LD C,1 ; SEARCH FOR FIRST EMPTY SPOT IN DIRECTORY. + CALL FINDFST ; (* ONLY CHECK FIRST BYTE *) + CALL CKFILPOS ; NONE? + POP HL + LD (PARAMS),HL ; RESTORE ORIGINAL FCB ADDRESS. + RET Z ; RETURN IF NO MORE SPACE. + EX DE,HL + LD HL,15 ; POINT TO NUMBER OF RECORDS FOR THIS FILE. + ADD HL,DE + LD C,17 ; AND CLEAR ALL OF THIS SPACE. + XOR A +GETMT1: LD (HL),A + INC HL + DEC C + JP NZ,GETMT1 + LD HL,13 ; CLEAR THE 'S1' BYTE ALSO. + ADD HL,DE + LD (HL),A + CALL CHKNMBR ; KEEP (SCRATCH1) WITHIN BOUNDS. + CALL FCBSET ; WRITE OUT THIS FCB ENTRY TO DIRECTORY. + JP SETS2B7 ; SET 'S2' BYTE BIT 7 (UNMODIFIED AT PRESENT). +; +; ROUTINE TO CLOSE THE CURRENT EXTENT AND OPEN THE NEXT ONE +; FOR READING. +; +GETNEXT:XOR A + LD (CLOSEFLG),A ; CLEAR CLOSE FLAG. + CALL CLOSEIT ; CLOSE THIS EXTENT. + CALL CKFILPOS + RET Z ; NOT THERE??? + LD HL,(PARAMS) ; GET EXTENT BYTE. + LD BC,12 + ADD HL,BC + LD A,(HL) ; AND INCREMENT IT. + INC A + AND 1FH ; KEEP WITHIN RANGE 0-31. + LD (HL),A + JP Z,GTNEXT1 ; OVERFLOW? + LD B,A ; MASK EXTENT BYTE. + LD A,(EXTMASK) + AND B + LD HL,CLOSEFLG ; CHECK CLOSE FLAG (0FFH IS OK). + AND (HL) + JP Z,GTNEXT2 ; IF ZERO, WE MUST READ IN NEXT EXTENT. + JP GTNEXT3 ; ELSE, IT IS ALREADY IN MEMORY. +GTNEXT1:LD BC,2 ; POINT TO THE 'S2' BYTE. + ADD HL,BC + INC (HL) ; AND BUMP IT. + LD A,(HL) ; TOO MANY EXTENTS? + AND 0FH + JP Z,GTNEXT5 ; YES, SET ERROR CODE. +; +; GET HERE TO OPEN THE NEXT EXTENT. +; +GTNEXT2:LD C,15 ; SET TO CHECK FIRST 15 BYTES OF FCB. + CALL FINDFST ; FIND THE FIRST ONE. + CALL CKFILPOS ; NONE AVAILABLE? + JP NZ,GTNEXT3 + LD A,(R.DWRTFLG) ; NO EXTENT PRESENT. CAN WE OPEN AN EMPTY ONE? + INC A ; 0FFH MEANS READING (SO NOT POSSIBLE). + JP Z,GTNEXT5 ; OR AN ERROR. + CALL GETEMPTY ; WE ARE WRITING, GET AN EMPTY ENTRY. + CALL CKFILPOS ; NONE? + JP Z,GTNEXT5 ; ERROR IF TRUE. + JP GTNEXT4 ; ELSE WE ARE ALMOST DONE. +GTNEXT3:CALL OPENIT1 ; OPEN THIS EXTENT. +GTNEXT4:CALL STRDATA ; MOVE IN UPDATED DATA (REC #, EXTENT #, ETC.) + XOR A ; CLEAR STATUS AND RETURN. + JP SETSTAT +; +; ERROR IN EXTENDING THE FILE. TOO MANY EXTENTS WERE NEEDED +; OR NOT ENOUGH SPACE ON THE DISK. +; +GTNEXT5:CALL IOERR1 ; SET ERROR CODE, CLEAR BIT 7 OF 'S2' + JP SETS2B7 ; SO THIS IS NOT WRITTEN ON A CLOSE. +; +; READ A S.EQUENTIAL FILE. +; +RDSEQ: LD A,1 ; SET S.EQUENTIAL ACCESS MODE. + LD (MODE),A +RDSEQ1: LD A,0FFH ; DON'T ALLOW READING UNWRITTEN SPACE. + LD (R.DWRTFLG),A + CALL STRDATA ; PUT REC# AND EXT# INTO FCB. + LD A,(SAVNREC) ; GET NEXT RECORD TO READ. + LD HL,SAVNXT ; GET NUMBER OF RECORDS IN EXTENT. + CP (HL) ; WITHIN THIS EXTENT? + JP C,RDSEQ2 + CP 128 ; NO. IS THIS EXTENT FULLY USED? + JP NZ,RDSEQ3 ; NO. END-OF-FILE. + CALL GETNEXT ; YES, OPEN THE NEXT ONE. + XOR A ; RESET NEXT RECORD TO READ. + LD (SAVNREC),A + LD A,(STATUS) ; CHECK ON OPEN, SUCCESSFUL? + OR A + JP NZ,RDSEQ3 ; NO, ERROR. +RDSEQ2: CALL COMBLK ; OK. COMPUTE BLOCK NUMBER TO READ. + CALL CHKBLK ; CHECK IT. WITHIN BOUNDS? + JP Z,RDSEQ3 ; NO, ERROR. + CALL LOGICAL ; CONVERT (BLKNMBR) TO LOGICAL SECTOR (128 BYTE). + CALL TRKSEC1 ; SET THE TRACK AND SECTOR FOR THIS BLOCK #. + CALL DOREAD ; AND READ IT. + JP SETNREC ; AND SET THE NEXT RECORD TO BE ACCESSED. +; +; READ ERROR OCCURED. SET STATUS AND RETURN. +; +RDSEQ3: JP IOERR1 +; +; WRITE THE NEXT S.EQUENTIAL RECORD. +; +WTSEQ: LD A,1 ; SET S.EQUENTIAL ACCESS MODE. + LD (MODE),A +WTSEQ1: LD A,0 ; ALLOW AN ADDITION EMPTY EXTENT TO BE OPENED. + LD (R.DWRTFLG),A + CALL CHKWPRT ; CHECK WRITE PROTECT STATUS. + LD HL,(PARAMS) + CALL CKROF1 ; CHECK FOR READ ONLY FILE, (HL) ALREADY SET TO FCB. + CALL STRDATA ; PUT UPDATED DATA INTO FCB. + LD A,(SAVNREC) ; GET RECORD NUMBER TO WRITE. + CP 128 ; WITHIN RANGE? + JP NC,IOERR1 ; NO, ERROR(?). + CALL COMBLK ; COMPUTE BLOCK NUMBER. + CALL CHKBLK ; CHECK NUMBER. + LD C,0 ; IS THERE ONE TO WRITE TO? + JP NZ,WTSEQ6 ; YES, GO DO IT. + CALL GETBLOCK ; GET NEXT BLOCK NUMBER WITHIN FCB TO USE. + LD (RELBLOCK),A ; AND SAVE. + LD BC,0 ; START LOOKING FOR SPACE FROM THE START + OR A ; IF NONE ALLOCATED AS YET. + JP Z,WTSEQ2 + LD C,A ; EXTRACT PREVIOUS BLOCK NUMBER FROM FCB + DEC BC ; SO WE CAN BE CLOSEST TO IT. + CALL EXTBLK + LD B,H + LD C,L +WTSEQ2: CALL FNDSPACE ; FIND THE NEXT EMPTY BLOCK NEAREST NUMBER (BC). + LD A,L ; CHECK FOR A ZERO NUMBER. + OR H + JP NZ,WTSEQ3 + LD A,2 ; NO MORE SPACE? + JP SETSTAT +WTSEQ3: LD (BLKNMBR),HL ; SAVE BLOCK NUMBER TO ACCESS. + EX DE,HL ; PUT BLOCK NUMBER INTO (DE). + LD HL,(PARAMS) ; NOW WE MUST UPDATE THE FCB FOR THIS + LD BC,16 ; NEWLY ALLOCATED BLOCK. + ADD HL,BC + LD A,(BIGDISK) ; 8 OR 16 BIT BLOCK NUMBERS? + OR A + LD A,(RELBLOCK) ; (* UPDATE THIS ENTRY *) + JP Z,WTSEQ4 ; ZERO MEANS 16 BIT ONES. + CALL ADDA2HL ; (HL)=(HL)+(A) + LD (HL),E ; STORE NEW BLOCK NUMBER. + JP WTSEQ5 +WTSEQ4: LD C,A ; COMPUTE SPOT IN THIS 16 BIT TABLE. + LD B,0 + ADD HL,BC + ADD HL,BC + LD (HL),E ; STUFF BLOCK NUMBER (DE) THERE. + INC HL + LD (HL),D +WTSEQ5: LD C,2 ; SET (C) TO INDICATE WRITING TO UN-USED DISK SPACE. +WTSEQ6: LD A,(STATUS) ; ARE WE OK SO FAR? + OR A + RET NZ + PUSH BC ; YES, SAVE WRITE FLAG FOR BIOS (REGISTER C). + CALL LOGICAL ; CONVERT (BLKNMBR) OVER TO LOICAL SECTORS. + LD A,(MODE) ; GET ACCESS MODE FLAG (1=S.EQUENTIAL, + DEC A ; 0=RANDOM, 2=SPECIAL?). + DEC A + JP NZ,WTSEQ9 +; +; SPECIAL RANDOM I/O FROM FUNCTION #40. MAYBE FOR M/PM, BUT THE +; CURRENT BLOCK, IF IT HAS NOT BEEN WRITTEN TO, WILL BE ZEROED +; OUT AND THEN WRITTEN (REASON?). +; + POP BC + PUSH BC + LD A,C ; GET WRITE STATUS FLAG (2=WRITING UNUSED SPACE). + DEC A + DEC A + JP NZ,WTSEQ9 + PUSH HL + LD HL,(DIRBUF) ; ZERO OUT THE DIRECTORY BUFFER. + LD D,A ; NOTE THAT (A) IS ZERO HERE. +WTSEQ7: LD (HL),A + INC HL + INC D ; DO 128 BYTES. + JP P,WTSEQ7 + CALL DIRDMA ; TELL THE BIOS THE DMA ADDRESS FOR DIRECTORY ACCESS. + LD HL,(LOGSECT) ; GET SECTOR THAT STARTS CURRENT BLOCK. + LD C,2 ; SET 'WRITING TO UNUSED SPACE' FLAG. +WTSEQ8: LD (BLKNMBR),HL ; SAVE SECTOR TO WRITE. + PUSH BC + CALL TRKSEC1 ; DETERMINE ITS TRACK AND SECTOR NUMBERS. + POP BC + CALL DOWRITE ; NOW WRITE OUT 128 BYTES OF ZEROS. + LD HL,(BLKNMBR) ; GET SECTOR NUMBER. + LD C,0 ; SET NORMAL WRITE FLAG. + LD A,(BLKMASK) ; DETERMINE IF WE HAVE WRITTEN THE ENTIRE + LD B,A ; PHYSICAL BLOCK. + AND L + CP B + INC HL ; PREPARE FOR THE NEXT ONE. + JP NZ,WTSEQ8 ; CONTINUE UNTIL (BLKMASK+1) SECTORS WRITTEN. + POP HL ; RESET NEXT SECTOR NUMBER. + LD (BLKNMBR),HL + CALL DEFDMA ; AND RESET DMA ADDRESS. +; +; NORMAL DISK WRITE. SET THE DESIRED TRACK AND SECTOR THEN +; DO THE ACTUAL WRITE. +; +WTSEQ9: CALL TRKSEC1 ; DETERMINE TRACK AND SECTOR FOR THIS WRITE. + POP BC ; GET WRITE STATUS FLAG. + PUSH BC + CALL DOWRITE ; AND WRITE THIS OUT. + POP BC + LD A,(SAVNREC) ; GET NUMBER OF RECORDS IN FILE. + LD HL,SAVNXT ; GET LAST RECORD WRITTEN. + CP (HL) + JP C,WTSEQ10 + LD (HL),A ; WE HAVE TO UPDATE RECORD COUNT. + INC (HL) + LD C,2 +; +;* THIS AREA HAS BEEN PATCHED TO CORRECT DISK UPDATE PROBLEM +;* WHEN USING BLOCKING AND DE-BLOCKING IN THE BIOS. +; +WTSEQ10:NOP ; WAS 'DCR C' + NOP ; WAS 'DCR C' + LD HL,0 ; WAS 'JNZ WTSEQ99' +; +; * END OF PATCH. +; + PUSH AF + CALL GETS2 ; SET 'EXTENT WRITTEN TO' FLAG. + AND 7FH ; (* CLEAR BIT 7 *) + LD (HL),A + POP AF ; GET RECORD COUNT FOR THIS EXTENT. +WTSEQ99:CP 127 ; IS IT FULL? + JP NZ,WTSEQ12 + LD A,(MODE) ; YES, ARE WE IN S.EQUENTIAL MODE? + CP 1 + JP NZ,WTSEQ12 + CALL SETNREC ; YES, SET NEXT RECORD NUMBER. + CALL GETNEXT ; AND GET NEXT EMPTY SPACE IN DIRECTORY. + LD HL,STATUS ; OK? + LD A,(HL) + OR A + JP NZ,WTSEQ11 + DEC A ; YES, SET RECORD COUNT TO -1. + LD (SAVNREC),A +WTSEQ11:LD (HL),0 ; CLEAR STATUS. +WTSEQ12:JP SETNREC ; SET NEXT RECORD TO ACCESS. +; +; FOR RANDOM I/O, SET THE FCB FOR THE DESIRED RECORD NUMBER +; BASED ON THE 'R0,R1,R2' BYTES. THESE BYTES IN THE FCB ARE +; USED AS FOLLOWS: +; +; FCB+35 FCB+34 FCB+33 +; | 'R-2' | 'R-1' | 'R-0' | +; |7 0 | 7 0 | 7 0| +; |0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0| +; | OVERFLOW | | EXTRA | EXTENT | RECORD # | +; | ______________| |_EXTENT|__NUMBER___|_____________| +; ALSO 'S2' +; +; ON ENTRY, REGISTER (C) CONTAINS 0FFH IF THIS IS A READ +; AND THUS WE CAN NOT ACCESS UNWRITTEN DISK SPACE. OTHERWISE, +; ANOTHER EXTENT WILL BE OPENED (FOR WRITING) IF R.EQUIRED. +; +POSITION: + XOR A ; SET RANDOM I/O FLAG. + LD (MODE),A +; +; SPECIAL ENTRY (FUNCTION #40). M/PM ? +; +POSITN1:PUSH BC ; SAVE READ/WRITE FLAG. + LD HL,(PARAMS) ; GET ADDRESS OF FCB. + EX DE,HL + LD HL,33 ; NOW GET BYTE 'R0'. + ADD HL,DE + LD A,(HL) + AND 7FH ; KEEP BITS 0-6 FOR THE RECORD NUMBER TO ACCESS. + PUSH AF + LD A,(HL) ; NOW GET BIT 7 OF 'R0' AND BITS 0-3 OF 'R1'. + RLA + INC HL + LD A,(HL) + RLA + AND 1FH ; AND SAVE THIS IN BITS 0-4 OF (C). + LD C,A ; THIS IS THE EXTENT BYTE. + LD A,(HL) ; NOW GET THE EXTRA EXTENT BYTE. + RRA + RRA + RRA + RRA + AND 0FH + LD B,A ; AND SAVE IT IN (B). + POP AF ; GET RECORD NUMBER BACK TO (A). + INC HL ; CHECK OVERFLOW BYTE 'R2'. + LD L,(HL) + INC L + DEC L + LD L,6 ; PREPARE FOR ERROR. + JP NZ,POSITN5 ; OUT OF DISK SPACE ERROR. + LD HL,32 ; STORE RECORD NUMBER INTO FCB. + ADD HL,DE + LD (HL),A + LD HL,12 ; AND NOW CHECK THE EXTENT BYTE. + ADD HL,DE + LD A,C + SUB (HL) ; SAME EXTENT AS BEFORE? + JP NZ,POSITN2 + LD HL,14 ; YES, CHECK EXTRA EXTENT BYTE 'S2' ALSO. + ADD HL,DE + LD A,B + SUB (HL) + AND 7FH + JP Z,POSITN3 ; SAME, WE ARE ALMOST DONE THEN. +; +; GET HERE WHEN ANOTHER EXTENT IS R.EQUIRED. +; +POSITN2:PUSH BC + PUSH DE + CALL CLOSEIT ; CLOSE CURRENT EXTENT. + POP DE + POP BC + LD L,3 ; PREPARE FOR ERROR. + LD A,(STATUS) + INC A + JP Z,POSITN4 ; CLOSE ERROR. + LD HL,12 ; PUT DESIRED EXTENT INTO FCB NOW. + ADD HL,DE + LD (HL),C + LD HL,14 ; AND STORE EXTRA EXTENT BYTE 'S2'. + ADD HL,DE + LD (HL),B + CALL OPENIT ; TRY AND GET THIS EXTENT. + LD A,(STATUS) ; WAS IT THERE? + INC A + JP NZ,POSITN3 + POP BC ; NO. CAN WE CREATE A NEW ONE (WRITING?). + PUSH BC + LD L,4 ; PREPARE FOR ERROR. + INC C + JP Z,POSITN4 ; NOPE, READING UNWRITTEN SPACE ERROR. + CALL GETEMPTY ; YES WE CAN, TRY TO FIND SPACE. + LD L,5 ; PREPARE FOR ERROR. + LD A,(STATUS) + INC A + JP Z,POSITN4 ; OUT OF SPACE? +; +; NORMAL RETURN LOCATION. CLEAR ERROR CODE AND RETURN. +; +POSITN3:POP BC ; RESTORE STACK. + XOR A ; AND CLEAR ERROR CODE BYTE. + JP SETSTAT +; +; ERROR. SET THE 'S2' BYTE TO INDICATE THIS (WHY?). +; +POSITN4:PUSH HL + CALL GETS2 + LD (HL),0C0H + POP HL +; +; RETURN WITH ERROR CODE (PRESENTLY IN L). +; +POSITN5:POP BC + LD A,L ; GET ERROR CODE. + LD (STATUS),A + JP SETS2B7 +; +; READ A RANDOM RECORD. +; +READRAN:LD C,0FFH ; SET 'READ' STATUS. + CALL POSITION ; POSITION THE FILE TO PROPER RECORD. + CALL Z,RDSEQ1 ; AND READ IT AS USUAL (IF NO ERRORS). + RET +; +; WRITE TO A RANDOM RECORD. +; +WRITERAN: + LD C,0 ; SET 'WRITING' FLAG. + CALL POSITION ; POSITION THE FILE TO PROPER RECORD. + CALL Z,WTSEQ1 ; AND WRITE AS USUAL (IF NO ERRORS). + RET +; +; COMPUTE THE RANDOM RECORD NUMBER. ENTER WITH (HL) POINTING +; TO A FCB AN (DE) CONTAINS A RELATIVE LOCATION OF A RECORD +; NUMBER. ON EXIT, (C) CONTAINS THE 'R0' BYTE, (B) THE 'R1' +; BYTE, AND (A) THE 'R2' BYTE. +; +; ON RETURN, THE ZERO FLAG IS SET IF THE RECORD IS WITHIN +; BOUNDS. OTHERWISE, AN OVERFLOW OCCURED. +; +COMPRAND: + EX DE,HL ; SAVE FCB POINTER IN (DE). + ADD HL,DE ; COMPUTE RELATIVE POSITION OF RECORD #. + LD C,(HL) ; GET RECORD NUMBER INTO (BC). + LD B,0 + LD HL,12 ; NOW GET EXTENT. + ADD HL,DE + LD A,(HL) ; COMPUTE (BC)=(RECORD #)+(EXTENT)*128. + RRCA ; MOVE LOWER BIT INTO BIT 7. + AND 80H ; AND IGNORE ALL OTHER BITS. + ADD A,C ; ADD TO OUR RECORD NUMBER. + LD C,A + LD A,0 ; TAKE CARE OF ANY CARRY. + ADC A,B + LD B,A + LD A,(HL) ; NOW GET THE UPPER BITS OF EXTENT INTO + RRCA ; BIT POSITIONS 0-3. + AND 0FH ; AND IGNORE ALL OTHERS. + ADD A,B ; ADD THIS IN TO 'R1' BYTE. + LD B,A + LD HL,14 ; GET THE 'S2' BYTE (EXTRA EXTENT). + ADD HL,DE + LD A,(HL) + ADD A,A ; AND SHIFT IT LEFT 4 BITS (BITS 4-7). + ADD A,A + ADD A,A + ADD A,A + PUSH AF ; SAVE CARRY FLAG (BIT 0 OF FLAG BYTE). + ADD A,B ; NOW ADD EXTRA EXTENT INTO 'R1'. + LD B,A + PUSH AF ; AND SAVE CARRY (OVERFLOW BYTE 'R2'). + POP HL ; BIT 0 OF (L) IS THE OVERFLOW INDICATOR. + LD A,L + POP HL ; AND SAME FOR FIRST CARRY FLAG. + OR L ; EITHER ONE OF THESE SET? + AND 01H ; ONLY CHECK THE CARRY FLAGS. + RET +; +; ROUTINE TO SETUP THE FCB (BYTES 'R0', 'R1', 'R2') TO +; REFLECT THE LAST RECORD USED FOR A RANDOM (OR OTHER) FILE. +; THIS READS THE DIRECTORY AND LOOKS AT ALL EXTENTS COMPUTING +; THE LARGERST RECORD NUMBER FOR EACH AND KEEPING THE MAXIMUM +; VALUE ONLY. THEN 'R0', 'R1', AND 'R2' WILL REFLECT THIS +; MAXIMUM RECORD NUMBER. THIS IS USED TO COMPUTE THE SPACE USED +; BY A RANDOM FILE. +; +RANSIZE:LD C,12 ; LOOK THRU DIRECTORY FOR FIRST ENTRY WITH + CALL FINDFST ; THIS NAME. + LD HL,(PARAMS) ; ZERO OUT THE 'R0, R1, R2' BYTES. + LD DE,33 + ADD HL,DE + PUSH HL + LD (HL),D ; NOTE THAT (D)=0. + INC HL + LD (HL),D + INC HL + LD (HL),D +RANSIZ1:CALL CKFILPOS ; IS THERE AN EXTENT TO PROCESS? + JP Z,RANSIZ3 ; NO, WE ARE DONE. + CALL FCB2HL ; SET (HL) POINTING TO PROPER FCB IN DIR. + LD DE,15 ; POINT TO LAST RECORD IN EXTENT. + CALL COMPRAND ; AND COMPUTE RANDOM PARAMETERS. + POP HL + PUSH HL ; NOW CHECK THESE VALUES AGAINST THOSE + LD E,A ; ALREADY IN FCB. + LD A,C ; THE CARRY FLAG WILL BE SET IF THOSE + SUB (HL) ; IN THE FCB REPRESENT A LARGER SIZE THAN + INC HL ; THIS EXTENT DOES. + LD A,B + SBC A,(HL) + INC HL + LD A,E + SBC A,(HL) + JP C,RANSIZ2 + LD (HL),E ; WE FOUND A LARGER (IN SIZE) EXTENT. + DEC HL ; STUFF THESE VALUES INTO FCB. + LD (HL),B + DEC HL + LD (HL),C +RANSIZ2:CALL FINDNXT ; NOW GET THE NEXT EXTENT. + JP RANSIZ1 ; CONTINUE TIL ALL DONE. +RANSIZ3:POP HL ; WE ARE DONE, RESTORE THE STACK AND + RET ; RETURN. +; +; FUNCTION TO RETURN THE RANDOM RECORD POSITION OF A GIVEN +; FILE WHICH HAS BEEN READ IN S.EQUENTIAL MODE UP TO NOW. +; +SETRAN: LD HL,(PARAMS) ; POINT TO FCB. + LD DE,32 ; AND TO LAST USED RECORD. + CALL COMPRAND ; COMPUTE RANDOM POSITION. + LD HL,33 ; NOW STUFF THESE VALUES INTO FCB. + ADD HL,DE + LD (HL),C ; MOVE 'R0'. + INC HL + LD (HL),B ; AND 'R1'. + INC HL + LD (HL),A ; AND LASTLY 'R2'. + RET +; +; THIS ROUTINE SELECT THE DRIVE SPECIFIED IN (ACTIVE) AND +; UPDATE THE LOGIN VECTOR AND BITMAP TABLE IF THIS DRIVE WAS +; NOT ALREADY ACTIVE. +; +LOGINDRV: + LD HL,(LOGIN) ; GET THE LOGIN VECTOR. + LD A,(ACTIVE) ; GET THE DEFAULT DRIVE. + LD C,A + CALL SHIFTR ; POSITION ACTIVE BIT FOR THIS DRIVE + PUSH HL ; INTO BIT 0. + EX DE,HL + CALL SELECT ; SELECT THIS DRIVE. + POP HL + CALL Z,SLCTERR ; VALID DRIVE? + LD A,L ; IS THIS A NEWLY ACTIVATED DRIVE? + RRA + RET C + LD HL,(LOGIN) ; YES, UPDATE THE LOGIN VECTOR. + LD C,L + LD B,H + CALL SETBIT + LD (LOGIN),HL ; AND SAVE. + JP BITMAP ; NOW UPDATE THE BITMAP. +; +; FUNCTION TO SET THE ACTIVE DISK NUMBER. +; +SETDSK: LD A,(EPARAM) ; GET PARAMETER PASSED AND SEE IF THIS + LD HL,ACTIVE ; REPRESENTS A CHANGE IN DRIVES. + CP (HL) + RET Z + LD (HL),A ; YES IT DOES, LOG IT IN. + JP LOGINDRV +; +; THIS IS THE 'AUTO DISK SELECT' ROUTINE. THE FIRSST BYTE +; OF THE FCB IS EXAMINED FOR A DRIVE SPECIFICATION. IF NON +; ZERO THEN THE DRIVE WILL BE SELECTED AND LOGED IN. +; +AUTOSEL:LD A,0FFH ; SAY 'AUTO-SELECT ACTIVATED'. + LD (AUTO),A + LD HL,(PARAMS) ; GET DRIVE SPECIFIED. + LD A,(HL) + AND 1FH ; LOOK AT LOWER 5 BITS. + DEC A ; ADJUST FOR (1=A, 2=B) ETC. + LD (EPARAM),A ; AND SAVE FOR THE SELECT ROUTINE. + CP 1EH ; CHECK FOR 'NO CHANGE' CONDITION. + JP NC,AUTOSL1 ; YES, DON'T CHANGE. + LD A,(ACTIVE) ; WE MUST CHANGE, SAVE CURRENTLY ACTIVE + LD (OLDDRV),A ; DRIVE. + LD A,(HL) ; AND SAVE FIRST BYTE OF FCB ALSO. + LD (AUTOFLAG),A ; THIS MUST BE NON-ZERO. + AND 0E0H ; WHATS THIS FOR (BITS 6,7 ARE USED FOR + LD (HL),A ; SOMETHING)? + CALL SETDSK ; SELECT AND LOG IN THIS DRIVE. +AUTOSL1:LD A,(USERNO) ; MOVE USER NUMBER INTO FCB. + LD HL,(PARAMS) ; (* UPPER HALF OF FIRST BYTE *) + OR (HL) + LD (HL),A + RET ; AND RETURN (ALL DONE). +; +; FUNCTION TO RETURN THE CURRENT CP/M VERSION NUMBER. +; +GETVER: LD A,022H ; VERSION 2.2 + JP SETSTAT +; +; FUNCTION TO RESET THE DISK SYSTEM. +; +RSTDSK: LD HL,0 ; CLEAR WRITE PROTECT STATUS AND LOG + LD (WRTPRT),HL ; IN VECTOR. + LD (LOGIN),HL + XOR A ; SELECT DRIVE 'A'. + LD (ACTIVE),A + LD HL,TBUFF ; SETUP DEFAULT DMA ADDRESS. + LD (USERDMA),HL + CALL DEFDMA + JP LOGINDRV ; NOW LOG IN DRIVE 'A'. +; +; FUNCTION TO OPEN A SPECIFIED FILE. +; +OPENFIL:CALL CLEARS2 ; CLEAR 'S2' BYTE. + CALL AUTOSEL ; SELECT PROPER DISK. + JP OPENIT ; AND OPEN THE FILE. +; +; FUNCTION TO CLOSE A SPECIFIED FILE. +; +CLOSEFIL: + CALL AUTOSEL ; SELECT PROPER DISK. + JP CLOSEIT ; AND CLOSE THE FILE. +; +; FUNCTION TO RETURN THE FIRST OCCURENCE OF A SPECIFIED FILE +; NAME. IF THE FIRST BYTE OF THE FCB IS '?' THEN THE NAME WILL +; NOT BE CHECKED (GET THE FIRST ENTRY NO MATTER WHAT). +; +GETFST: LD C,0 ; PREPARE FOR SPECIAL SEARCH. + EX DE,HL + LD A,(HL) ; IS FIRST BYTE A '?'? + CP '?' + JP Z,GETFST1 ; YES, JUST GET VERY FIRST ENTRY (ZERO LENGTH MATCH). + CALL SETEXT ; GET THE EXTENSION BYTE FROM FCB. + LD A,(HL) ; IS IT '?'? IF YES, THEN WE WANT + CP '?' ; AN ENTRY WITH A SPECIFIC 'S2' BYTE. + CALL NZ,CLEARS2 ; OTHERWISE, LOOK FOR A ZERO 'S2' BYTE. + CALL AUTOSEL ; SELECT PROPER DRIVE. + LD C,15 ; COMPARE BYTES 0-14 IN FCB (12&13 EXCLUDED). +GETFST1:CALL FINDFST ; FIND AN ENTRY AND THEN MOVE IT INTO + JP MOVEDIR ; THE USERS DMA SPACE. +; +; FUNCTION TO RETURN THE NEXT OCCURENCE OF A FILE NAME. +; +GETNXT: LD HL,(SAVEFCB) ; RESTORE POINTERS. NOTE THAT NO + LD (PARAMS),HL ; OTHER .DBOS CALLS ARE ALLOWED. + CALL AUTOSEL ; NO ERROR WILL BE RETURNED, BUT THE + CALL FINDNXT ; RESULTS WILL BE WRONG. + JP MOVEDIR +; +; FUNCTION TO DELETE A FILE BY NAME. +; +DELFILE:CALL AUTOSEL ; SELECT PROPER DRIVE. + CALL ERAFILE ; ERASE THE FILE. + JP STSTATUS ; SET STATUS AND RETURN. +; +; FUNCTION TO EXECUTE A S.EQUENTIAL READ OF THE SPECIFIED +; RECORD NUMBER. +; +READSEQ:CALL AUTOSEL ; SELECT PROPER DRIVE THEN READ. + JP RDSEQ +; +; FUNCTION TO WRITE THE NET S.EQUENTIAL RECORD. +; +WRTSEQ: CALL AUTOSEL ; SELECT PROPER DRIVE THEN WRITE. + JP WTSEQ +; +; CREATE A FILE FUNCTION. +; +FCREATE:CALL CLEARS2 ; CLEAR THE 'S2' BYTE ON ALL CREATES. + CALL AUTOSEL ; SELECT PROPER DRIVE AND GET THE NEXT + JP GETEMPTY ; EMPTY DIRECTORY SPACE. +; +; FUNCTION TO RENAME A FILE. +; +RENFILE:CALL AUTOSEL ; SELECT PROPER DRIVE AND THEN SWITCH + CALL CHGNAMES ; FILE NAMES. + JP STSTATUS +; +; FUNCTION TO RETURN THE LOGIN VECTOR. +; +GETLOG: LD HL,(LOGIN) + JP GETPRM1 +; +; FUNCTION TO RETURN THE CURRENT DISK ASSIGNMENT. +; +GETCRNT:LD A,(ACTIVE) + JP SETSTAT +; +; FUNCTION TO SET THE DMA ADDRESS. +; +PUTDMA: EX DE,HL + LD (USERDMA),HL ; SAVE IN OUR SPACE AND THEN GET TO + JP DEFDMA ; THE BIOS WITH THIS ALSO. +; +; FUNCTION TO RETURN THE ALLOCATION VECTOR. +; +GETALOC:LD HL,(ALOCVECT) + JP GETPRM1 +; +; FUNCTION TO RETURN THE READ-ONLY STATUS VECTOR. +; +GETROV: LD HL,(WRTPRT) + JP GETPRM1 +; +; FUNCTION TO SET THE FILE ATTRIBUTES (READ-ONLY, SYSTEM). +; +SETATTR:CALL AUTOSEL ; SELECT PROPER DRIVE THEN SAVE ATTRIBUTES. + CALL SAVEATTR + JP STSTATUS +; +; FUNCTION TO RETURN THE ADDRESS OF THE DISK PARAMETER BLOCK +; FOR THE CURRENT DRIVE. +; +GETPARM:LD HL,(DISKPB) +GETPRM1:LD (STATUS),HL + RET +; +; FUNCTION TO GET OR SET THE USER NUMBER. IF (E) WAS (FF) +; THEN THIS IS A R.EQUEST TO RETURN THE CURRENT USER NUMBER. +; ELSE SET THE USER NUMBER FROM (E). +; +GETUSER:LD A,(EPARAM) ; GET PARAMETER. + CP 0FFH ; GET USER NUMBER? + JP NZ,SETUSER + LD A,(USERNO) ; YES, JUST DO IT. + JP SETSTAT +SETUSER:AND 1FH ; NO, WE SHOULD SET IT INSTEAD. KEEP LOW + LD (USERNO),A ; BITS (0-4) ONLY. + RET +; +; FUNCTION TO READ A RANDOM RECORD FROM A FILE. +; +RDRANDOM: + CALL AUTOSEL ; SELECT PROPER DRIVE AND READ. + JP READRAN +; +; FUNCTION TO COMPUTE THE FILE SIZE FOR RANDOM FILES. +; +WTRANDOM: + CALL AUTOSEL ; SELECT PROPER DRIVE AND WRITE. + JP WRITERAN +; +; FUNCTION TO COMPUTE THE SIZE OF A RANDOM FILE. +; +FILESIZE: + CALL AUTOSEL ; SELECT PROPER DRIVE AND CHECK FILE LENGTH + JP RANSIZE +; +; FUNCTION #37. THIS ALLOWS A PROGRAM TO LOG OFF ANY DRIVES. +; ON ENTRY, SET (DE) TO CONTAIN A WORD WITH BITS SET FOR THOSE +; DRIVES THAT ARE TO BE LOGGED OFF. THE LOG-IN VECTOR AND THE +; WRITE PROTECT VECTOR WILL BE UPDATED. THIS MUST BE A M/PM +; SPECIAL FUNCTION. +; +LOGOFF: LD HL,(PARAMS) ; GET DRIVES TO LOG OFF. + LD A,L ; FOR EACH BIT THAT IS SET, WE WANT + CPL ; TO CLEAR THAT BIT IN (LOGIN) + LD E,A ; AND (WRTPRT). + LD A,H + CPL + LD HL,(LOGIN) ; RESET THE LOGIN VECTOR. + AND H + LD D,A + LD A,L + AND E + LD E,A + LD HL,(WRTPRT) + EX DE,HL + LD (LOGIN),HL ; AND SAVE. + LD A,L ; NOW DO THE WRITE PROTECT VECTOR. + AND E + LD L,A + LD A,H + AND D + LD H,A + LD (WRTPRT),HL ; AND SAVE. ALL DONE. + RET +; +; GET HERE TO RETURN TO THE USER. +; +GOBACK: LD A,(AUTO) ; WAS AUTO SELECT ACTIVATED? + OR A + JP Z,GOBACK1 + LD HL,(PARAMS) ; YES, BUT WAS A CHANGE MADE? + LD (HL),0 ; (* RESET FIRST BYTE OF FCB *) + LD A,(AUTOFLAG) + OR A + JP Z,GOBACK1 + LD (HL),A ; YES, RESET FIRST BYTE PROPERLY. + LD A,(OLDDRV) ; AND GET THE OLD DRIVE AND SELECT IT. + LD (EPARAM),A + CALL SETDSK +GOBACK1:LD HL,(USRSTACK) ; RESET THE USERS STACK POINTER. + LD SP,HL + LD HL,(STATUS) ; GET RETURN STATUS. + LD A,L ; FORCE VERSION 1.4 COMPATABILITY. + LD B,H + RET ; AND GO BACK TO USER. +; +; FUNCTION #40. THIS IS A SPECIAL ENTRY TO DO RANDOM I/O. +; FOR THE CASE WHERE WE ARE WRITING TO UNUSED DISK SPACE, THIS +; SPACE WILL BE ZEROED OUT FIRST. THIS MUST BE A M/PM SPECIAL +; PURPOSE FUNCTION, BECAUSE WHY WOULD ANY NORMAL PROGRAM EVEN +; CARE ABOUT THE PREVIOUS CONTENTS OF A SECTOR ABOUT TO BE +; WRITTEN OVER. +; +WTSPECL:CALL AUTOSEL ; SELECT PROPER DRIVE. + LD A,2 ; USE SPECIAL WRITE MODE. + LD (MODE),A + LD C,0 ; SET WRITE INDICATOR. + CALL POSITN1 ; POSITION THE FILE. + CALL Z,WTSEQ1 ; AND WRITE (IF NO ERRORS). + RET +; +;************************************************************** +;* +;* BDOS DATA STORAGE POOL. +;* +;************************************************************** +; +EMPTYFCB: + .DB 0E5H ; EMPTY DIRECTORY SEGMENT INDICATOR. +WRTPRT: .DW 0 ; WRITE PROTECT STATUS FOR ALL 16 DRIVES. +LOGIN: .DW 0 ; DRIVE ACTIVE WORD (1 BIT PER DRIVE). +USERDMA:.DW 080H ; USER'S DMA ADDRESS (DEFAULTS TO 80H). +; +; SCRATCH AREAS FROM PARAMETER BLOCK. +; +SCRATCH1: + .DW 0 ; RELATIVE POSITION WITHIN DIR SEGMENT FOR FILE (0-3). +SCRATCH2: + .DW 0 ; LAST SELECTED TRACK NUMBER. +SCRATCH3: + .DW 0 ; LAST SELECTED SECTOR NUMBER. +; +; DISK STORAGE AREAS FROM PARAMETER BLOCK. +; +DIRBUF: .DW 0 ; ADDRESS OF DIRECTORY BUFFER TO USE. +DISKPB: .DW 0 ; CONTAINS ADDRESS OF DISK PARAMETER BLOCK. +CHKVECT:.DW 0 ; ADDRESS OF CHECK VECTOR. +ALOCVECT: + .DW 0 ; ADDRESS OF ALLOCATION VECTOR (BIT MAP). +; +; PARAMETER BLOCK RETURNED FROM THE BIOS. +; +SECTORS:.DW 0 ; SECTORS PER TRACK FROM BIOS. +BLKSHFT:.DB 0 ; BLOCK SHIFT. +BLKMASK:.DB 0 ; BLOCK MASK. +EXTMASK:.DB 0 ; EXTENT MASK. +DSKSIZE:.DW 0 ; DISK SIZE FROM BIOS (NUMBER OF BLOCKS-1). +DIRSIZE:.DW 0 ; DIRECTORY SIZE. +ALLOC0: .DW 0 ; STORAGE FOR FIRST BYTES OF BIT MAP (DIR SPACE USED). +ALLOC1: .DW 0 +OFFSET: .DW 0 ; FIRST USABLE TRACK NUMBER. +XLATE: .DW 0 ; SECTOR TRANSLATION TABLE ADDRESS. +; +; +CLOSEFLG: + .DB 0 ; CLOSE FLAG (=0FFH IS EXTENT WRITTEN OK). +R.DWRTFLG: + .DB 0 ; READ/WRITE FLAG (0FFH=READ, 0=WRITE). +FNDSTAT:.DB 0 ; FILENAME FOUND STATUS (0=FOUND FIRST ENTRY). +MODE: .DB 0 ; I/O MODE SELECT (0=RANDOM, 1=S.EQUENTIAL, 2=SPECIAL RANDOM). +EPARAM: .DB 0 ; STORAGE FOR REGISTER (E) ON ENTRY TO BDOS. +RELBLOCK: + .DB 0 ; RELATIVE POSITION WITHIN FCB OF BLOCK NUMBER WRITTEN. +COUNTER:.DB 0 ; BYTE COUNTER FOR DIRECTORY NAME SEARCHES. +SAVEFCB:.DW 0,0 ; SAVE SPACE FOR ADDRESS OF FCB (FOR DIRECTORY SEARCHES). +BIGDISK:.DB 0 ; IF =0 THEN DISK IS > 256 BLOCKS LONG. +AUTO: .DB 0 ; IF NON-ZERO, THEN AUTO SELECT ACTIVATED. +OLDDRV: .DB 0 ; ON AUTO SELECT, STORAGE FOR PREVIOUS DRIVE. +AUTOFLAG: + .DB 0 ; IF NON-ZERO, THEN AUTO SELECT CHANGED DRIVES. +SAVNXT: .DB 0 ; STORAGE FOR NEXT RECORD NUMBER TO ACCESS. +SAVEXT: .DB 0 ; STORAGE FOR EXTENT NUMBER OF FILE. +SAVNREC:.DW 0 ; STORAGE FOR NUMBER OF RECORDS IN FILE. +BLKNMBR:.DW 0 ; BLOCK NUMBER (PHYSICAL SECTOR) USED WITHIN A FILE OR LOGICAL SEC +LOGSECT:.DW 0 ; STARTING LOGICAL (128 BYTE) SECTOR OF BLOCK (PHYSICAL SECTOR). +FCBPOS: .DB 0 ; RELATIVE POSITION WITHIN BUFFER FOR FCB OF FILE OF INTEREST. +FILEPOS:.DW 0 ; FILES POSITION WITHIN DIRECTORY (0 TO MAX ENTRIES -1). +; +; DISK DIRECTORY BUFFER CHECKSUM BYTES. ONE FOR EACH OF THE +; 16 POSSIBLE DRIVES. +; +CKSUMTBL: + .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +; +;************************************************************** +;* +;* B I O S J U M P T A B L E +;* +;************************************************************** +; + +BIOS: .EQU BIOSO ;BIOS ORIGIN +; +BOOT: .EQU BIOS ;(BOOT) Cold boot entry +WBOOT: .EQU BIOS+3 ;Warm boot entry +CONST: .EQU BIOS+6 ;Console status +CONIN: .EQU BIOS+9 ;Console char in +CONOUT: .EQU BIOS+12 ;Console char out +LIST: .EQU BIOS+15 ;List char out +PUNCH: .EQU BIOS+18 ;Punch char out +READER: .EQU BIOS+21 ;Reader char in +HOME: .EQU BIOS+24 ;Home disk +SELDSK: .EQU BIOS+27 ;Select disk +SETTRK: .EQU BIOS+30 ;Set disk track addr +SETSEC: .EQU BIOS+33 ;Set disk sector addr +SETDMA: .EQU BIOS+36 ;Set DMA buffer addr +READ: .EQU BIOS+39 ;Read sector +WRITE: .EQU BIOS+42 ;Write sector +SECTRN: .EQU BIOS+48 ;Sector translation routine +; + .IF ENDFIL + .ORG BDOSO+0DFFH + .DB 55H + .ENDIF + .END diff --git a/doug/ref/n8-romim.ref b/doug/ref/n8-romim.ref new file mode 100755 index 00000000..33dfdad8 Binary files /dev/null and b/doug/ref/n8-romim.ref differ diff --git a/doug/src/4th.s b/doug/src/4th.s new file mode 100755 index 00000000..728d7eca --- /dev/null +++ b/doug/src/4th.s @@ -0,0 +1,4310 @@ +;------------------------------------------------------------------------------- +; Save to Space-Time Productions Z-80 directory on +; February 22, 2007 and converted terms for TASM +;------------------------------------------------------------------------------- +; +;------------------------------------------------------------------------------- +; This is an implementation of FORTH for the Z80 that should be easily portable +; to other Z80 systems. It assumes RAM from $9000 to $FFFF and a UART for +; communication with the host or VDU. +;------------------------------------------------------------------------------- +DATA_STACK: .EQU $FD80 ; Data stack grows down +VOCAB_BASE: .EQU $F000 ; Dictionary grows up from here +MASS_STORE: .EQU $FEA0 ; Mass storage buffer (default) +DISK_START: .EQU $A000 ; Pseudo disk buffer start +DISK_END: .EQU $F000 ; Pseudo disk buffer end +BLOCK_SIZE: .EQU $0200 ; Pseudo disk block size +BUFFERS: .EQU $0001 ; Pseudo disk buffers per block +MONSTART: .EQU $0000 ; Monitor entry address + +SYSTEM: .EQU $FE00 ; SYSTEM VARIABLES +S0: .EQU $FE06 ; Initial value of Data SP +R0: .EQU $FE08 ; Initial value of Return SP +TIB: .EQU $FE0A ; Terminal Input Buffer +WIDTH: .EQU $FE0C ; Number of letters saved in names +WARNING: .EQU $FE0E ; Error message control number +FENCE: .EQU $FE10 ; Dictionary FORGET +DP: .EQU $FE12 ; Dictionary Pointer +VOC_LINK: .EQU $FE14 ; Most recently created vocabulary +BLK: .EQU $FE16 ; Current block number interpretation +TOIN: .EQU $FE18 ; Offset in the current input text buffer +OUT: .EQU $FE1A ; Offset in the current output text buff +SCR: .EQU $FE1C ; Screen number last ref'd by LIST +OFFSET: .EQU $FE1E ; Block offset for disk drives +CONTEXT: .EQU $FE20 ; Pointer to vocabulary within which + ; dictionary search will first begin +CURRENT: .EQU $FE22 ; Pointer to the vocabulary within which + ; new definitions are to be created +STATE: .EQU $FE24 ; Contains state of compilation +BASE: .EQU $FE26 ; Current I/O Base Address +DPL: .EQU $FE28 ; Number of digits to the right of the + ; decimal point on double integer input +FLD: .EQU $FE2A ; Field width for formatted number output +CSP: .EQU $FE2C ; Check SP +RHASH: .EQU $FE2E ; Location of editor cursor in a txt blk +HLD: .EQU $FE30 ; Address of current output +FLAST: .EQU $FE32 ; FORTH vocabulary data initialized +ELAST: .EQU $FE38 ; Editor vocabulary data +CRFLAG: .EQU $FE3E ; Carriage Return flag +PAT: .EQU $FE40 ; I/O port fetch routine INPUT +PST: .EQU $FE43 ; I/O port store routine OUTPUT +RPP: .EQU $FE46 ; Return SP +USE: .EQU $FE48 ; Mass storage buffer address to use +PREV: .EQU $FE4A ; Mass storage buffer address just used +INTFLAG: .EQU $FE4C ; Interrupt flag and user byte following +INTVECT: .EQU $FE4E ; Interrupt vector +UTERMNL: .EQU $FE50 ; Code field address of word ?TERMINAL +UKEY: .EQU $FE52 ; Code field address of word KEY +UEMIT: .EQU $FE54 ; Code field address of word EMIT +UCR: .EQU $FE56 ; Code field address of word CR +URW: .EQU $FE58 ; Code field address of word R/W +UABORT: .EQU $FE5A ; Code field address of word ABORT +UCL: .EQU $FE5C ; Number of chars per input line +UFIRST: .EQU $FE5E ; Start of pseudo disk buffer +ULIMIT: .EQU $FE60 ; End of pseudo disk buffer +UBBUF: .EQU $FE62 ; Number of bytes per block +UBSCR: .EQU $FE64 ; Number of buffers per block +KEYBUF: .EQU $FE66 ; Double key buffer +RAF: .EQU $FE68 ; Register AF +RBC: .EQU $FE6A ; Register BC +RDE: .EQU $FE6C ; Register DE +RHL: .EQU $FE6E ; Register HL +RIX: .EQU $FE70 ; Register IX +RIY: .EQU $FE72 ; Register IY +RAF2: .EQU $FE74 ; Register AF' +RBC2: .EQU $FE76 ; Register BC' +RDE2: .EQU $FE78 ; Register DE' +RHL2: .EQU $FE7A ; Regisetr HL' +JPCODE: .EQU $FE7D ; JP code ($C3) for word +JPVECT: .EQU $FE7E ; JP vector +;------------------------------------------------------------------------------ +FORTH: .ORG $8000 ; Start of RAM + + XOR A ; Clear A + LD (KEYBUF),A ; Clear buffered key + JP X_COLD + +BACKSPACE: + .WORD $0008 ; Backspace chr + +WORD1: .WORD DATA_STACK +DEF_SYSADDR: + .WORD SYSTEM + .WORD DATA_STACK + .WORD $001F ; Word name length (default 31) + .WORD $0000 ; Error message control number + .WORD VOCAB_BASE ; FORGET protection + .WORD VOCAB_BASE+$0B ; Dictionary pointer + .WORD E_FORTH ; Most recently created vocab. + +START_TABLE: + .BYTE $81,$A0 + .WORD VOCAB_BASE + .BYTE $00,$00 ; FLAST + .BYTE $81,$A0 + .WORD W_EDITI + .WORD E_FORTH ; ELAST + .BYTE $00 ; CRFLAG + .BYTE $00 ; Free + IN A,($00) ; I/O Port input + RET ; routine + OUT ($00),A ; I/O Port output + RET ; routine + .WORD SYSTEM ; Return stack pointer + .WORD MASS_STORE ; Mass storage buffer to use + .WORD MASS_STORE ; Storage buffer just used + .BYTE $00 ; Interrupt flag + .BYTE $00 ; Free + .WORD C_ABORT ; Interrupt vector + .WORD CF_UQTERMINAL ; C field address ?TERMINAL + .WORD CF_UKEY ; C field address KEY + .WORD CF_UEMIT ; C field address EMIT + .WORD CF_UCR ; C field address CR + .WORD CF_URW ; C field address R/W + .WORD CF_UABORT ; C field address ABORT + .WORD $0020 ; CHRs per input line + .WORD DISK_START ; Pseudo disk buf start + .WORD DISK_END ; Pseudo disk buf end + .WORD BLOCK_SIZE ; Bytes per block + .WORD BUFFERS ; Buffers per block + +NEXTS2: PUSH DE +NEXTS1: PUSH HL +NEXT: LD A,(INTFLAG) ; Interrupt flag + BIT 7,A ; Check for interrupt + JR Z,NOINT ; No interrupt + BIT 6,A ; Interrupt enabled ? + JR NZ,NOINT ; No interrupt + LD HL,(INTVECT) ; Get nterrupt vector + LD A,$40 ; Clear flag byte + LD (INTFLAG),A ; Interrupt flag into HL + JR NEXTADDR ; JP (HL) + +NOINT: LD A,(BC) ; effectively LD HL,(BC) + INC BC ; + LD L,A ; + LD A,(BC) ; + INC BC ; BC now points to next vector + LD H,A ; HL has addr vector + +NEXTADDR: LD E,(HL) ; effectively LD HL,(HL) + INC HL ; + LD D,(HL) ; + EX DE,HL ; + JP (HL) ; Jump to it + +W_LIT: ; Puts next 2 bytes on the stack + .BYTE $83,"LI",'T'+$80 + .WORD $0000 ; First word in vocabulary +C_LIT: .WORD 2+$ ; Vector to code + LD A,(BC) ; Gets next word from (BC) + INC BC ; then increments BC to point + LD L,A ; to the next addr. Pushes the + LD A,(BC) ; result onto the stack. + INC BC ; + LD H,A ; + JP NEXTS1 ; Save & NEXT + + +W_EXECUTE: ; Jump to address on stack + .BYTE $87,"EXECUT",'E'+$80 + .WORD W_LIT +C_EXECUTE: + .WORD 2+$ ; Vector to code + POP HL ; Get addr off data stack + JP NEXTADDR ; Basically JP (HL) + + +W_BRANCH: ; Add following offset to BC + .BYTE $86,"BRANC",'H'+$80 + .WORD W_EXECUTE +C_BRANCH: .WORD 2+$ ; Vector to code +X_BRANCH: LD H,B ; Next pointer into HL + LD L,C ; + LD E,(HL) ; Get word offset LD DE,(HL) + INC HL ; Incr to point at next byte + LD D,(HL) ; + DEC HL ; Restore HL + ADD HL,DE ; Calculate new address + LD C,L ; Put it in BC + LD B,H ; + JP NEXT ; Go do it + + +W_0BRANCH: ; Add offset to BC if stack top = 0 + .BYTE $87,"0BRANC",'H'+$80 ; Conditional branch + .WORD W_BRANCH +C_0BRANCH: + .WORD 2+$ ; Vector to code + POP HL ; Get value off stack + LD A,L ; Set flags + OR H ; + JR Z,X_BRANCH ; If zero then do the branch + INC BC ; Else dump branch address + INC BC ; + JP NEXT ; Continue execution + +W_LLOOP: ; Increment loop & branch if not done + .BYTE $86,"'+$80 + .WORD W_0BRANCH +C_LLOOP: + .WORD 2+$ ; Vector to code + LD DE,0001 +C_ILOOP: + LD HL,(RPP) ; Get return stack pointer + LD A,(HL) ; Add DE to value on return stack + ADD A,E ; + LD (HL),A ; + LD E,A ; + INC HL ; + LD A,(HL) ; + ADC A,D ; + LD (HL),A ; + INC HL ; HL now points to limit value + INC D ; Get Ds sign bit + DEC D ; + LD D,A ; Result now in DE + JP M,DECR_LOOP ; Decrement loop so check > limit + ; otherwies check < limit + LD A,E ; Low byte back + SUB (HL) ; Subtract limit low + LD A,D ; High byte back + INC HL ; Point to limit high + SBC A,(HL) ; Subtract it + JR TEST_LIMIT ; +DECR_LOOP: + LD A,(HL) ; Get limit low + SUB E ; Subtract index low + INC HL ; Point to limit high + LD A,(HL) ; Get it + SBC A,D ; Subtract index high +TEST_LIMIT: + JP M,X_BRANCH ; Not reached limit so jump + INC HL ; Drop index & limit from return stack + LD (RPP),HL ; Save stack pointer + INC BC ; Skip branch offset + INC BC ; + JP NEXT + +W_PLOOP: ; Loop + stack & branch if not done + .BYTE $87,"<+LOOP",'>'+$80 + .WORD W_LLOOP +C_PLOOP: + .WORD 2+$ ; Vector to code + POP DE ; Get value from stack + JR C_ILOOP ; Go do loop increment + +W_LDO: ; Put start & end loop values on RPP + .BYTE $84,"'+$80 + .WORD W_PLOOP +C_LDO: + .WORD 2+$ + LD HL,(RPP) ; Get return stack pointer + DEC HL ; Add space for two values + DEC HL ; + DEC HL ; + DEC HL ; + LD (RPP),HL ; Save new stack pointer + POP DE ; Get start value & + LD (HL),E ; put on return stack top + INC HL ; + LD (HL),D ; + INC HL ; + POP DE ; Get end value & + LD (HL),E ; put on return stack - 1 + INC HL ; + LD (HL),D ; + JP NEXT + +W_I: ; Copy LOOP index to data stack + .BYTE $81,'I'+$80 + .WORD W_LDO +C_I: + .WORD 2+$ +X_I: + LD HL,(RPP) ; Get return stack pointer +X_I2: + LD E,(HL) ; Get LOOP index off return stack + INC HL ; + LD D,(HL) ; + PUSH DE ; Push onto data stack + JP NEXT + +W_DIGIT: ; Convert digit n2 using base n1 + .BYTE $85,"DIGI",'T'+$80 + .WORD W_I +C_DIGIT: + .WORD 2+$ + POP HL ; Get base to use + POP DE ; Get char + LD A,E ; A = char + SUB $30 ; Subtract 30h + JP M,NDIGIT + CP $0A ; Greater than 9 ? + JP M,LESS10 ; If not then skip + SUB $07 ; Convert 'A' to 10 + CP $0A ; Is it 10? + JP M,NDIGIT ; If not an error occured +LESS10: + CP L ; L is 1 digit limit + JP P,NDIGIT ; Out of range for digit + LD E,A ; Result into DE + LD HL,0001 ; Leave TRUE flag + JP NEXTS2 ; Save both & NEXT +NDIGIT: + LD L,H ; Leave FALSE flag + JP NEXTS1 ; Save & NEXT + +W_FIND: ; Find word & return vector,byte & flag + .BYTE $86,"'+$80 + .WORD W_DIGIT +C_FIND: + .WORD 2+$ ; Vector to code + POP DE ; Get pointer to next vocabulary word +COMPARE: + POP HL ; Copy pointer to word we're looking 4 + PUSH HL ; + LD A,(DE) ; Get 1st vocabulary word letter + XOR (HL) ; Compare with what we've got + AND $3F ; Ignore start flag + JR NZ,NOT_END_CHR ; No match so skip to next word +MATCH_NO_END: + INC HL ; Compare next chr + INC DE ; + LD A,(DE) ; + XOR (HL) ; + ADD A,A ; Move bit 7 to C flag + JR NZ,NO_MATCH ; No match jump + JR NC,MATCH_NO_END ; Match & not last, so next chr + LD HL,0005 ; Offset to start of code + ADD HL,DE ; HL now points to code start for word + EX (SP),HL ; Swap with value on stack +NOT_WORD_BYTE: + DEC DE ; Search back for word type byte + LD A,(DE) ; + OR A ; + JP P,NOT_WORD_BYTE ; Not yet so loop + LD E,A ; Byte into DE + LD D,$00 ; + LD HL,0001 ; Leave TRUE flag + JP NEXTS2 ; Save both & NEXT +NO_MATCH: + JR C,END_CHR ; If last chr then jump +NOT_END_CHR: + INC DE ; Next chr of this vocab word + LD A,(DE) ; Get it + OR A ; Set flags + JP P,NOT_END_CHR ; Loop if not end chr +END_CHR: + INC DE ; Now points to next word vector + EX DE,HL ; Swap + LD E,(HL) ; Vector into DE + INC HL ; + LD D,(HL) ; + LD A,D ; Check it's not last (first) word + OR E ; + JR NZ,COMPARE ; No error so loop + POP HL ; Dump pointer + LD HL,0000 ; Flag error + JP NEXTS1 ; Save & NEXT + +W_ENCLOSE: + .BYTE $87,"ENCLOS",'E'+$80 + .WORD W_FIND +C_ENCLOSE: + .WORD 2+$ ; Vector to code + POP DE ; get delimiter character + POP HL ; get address 1 + PUSH HL ; duplicate it + LD A,E ; delimiter char into A + LD D,A ; copy to D + LD E,$ff ;-1 for offset + DEC HL ; to allow for first INCR +J21E6: + INC HL ; point to next chr + INC E ; next offset + CP (HL) ; compare chr with (address) + JR Z,J21E6 ; loop if = delimiter chr + LD A,$0D ; else set CR + CP (HL) ; compare with (address) + LD A,D ; restore delimiter chr + JR Z,J21E6 ; loop if it was = CR + LD D,$00 ; zero high byte + PUSH DE ; save offset + LD D,A ; restore delimiter chr + LD A,(HL) ; get byte from address + AND A ; set the flags + JR NZ,J2202 ; branch if not null + LD D,$00 ; clear high byte + INC E ; point to next addr + PUSH DE ; save address + DEC E ; point to end + PUSH DE ; push address + JP NEXT ; done +J2202: + LD A,D ; restore delimiter chr + INC HL ; increment address + INC E ; increment offset + CP (HL) ; compare delimiter with (address) + JR Z,J2218 ; jump if = + LD A,$0D ; else get CR + CP (HL) ; compare with (address) + JR Z,J2218 ; jump if = + LD A,(HL) ; else get byte + AND A ; set the flags + JR NZ,J2202 ; loop if not null + LD D,$00 ; clear gigh byte + PUSH DE ; save address + PUSH DE ; save address + JP NEXT ; done +J2218: + LD D,$00 ; clear high byte + PUSH DE ; save address + INC E ; increment offset + PUSH DE ; save address + JP NEXT ; done + +W_EMIT: ; Output CHR from stack + .BYTE $84,"EMI",'T'+$80 + .WORD W_ENCLOSE +C_EMIT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UEMIT ; Put UEMIT addr on stack + .WORD C_FETCH ; Get UEMIT code field address + .WORD C_EXECUTE ; Jump to address on stack + .WORD C_1 + .WORD C_OUT + .WORD C_PLUSSTORE + .WORD C_STOP ; Pop BC from return stack (=next) + +W_KEY: ; Wait for key, value on stack + .BYTE $83,"KE",'Y'+$80 + .WORD W_EMIT +C_KEY: + .WORD 2+$ ; Vector to code + LD HL,(UKEY) ; Get the vector + JP (HL) ; Jump to it + +; .WORD E_COLON ; Interpret following word sequence +; .WORD C_UKEY ; Put UKEY addr on stack +; .WORD C_FETCH ; Get CF_KEY +; .WORD C_EXECUTE ; Jump to CF_KEY +; .WORD C_STOP ; Pop BC from return stack (=next) + + +W_TERMINAL: + .BYTE $89,"?TERMINA",'L'+$80 + .WORD W_KEY +C_TERMINAL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UTERMINAL + .WORD C_FETCH ; Get word from addr on stack + .WORD C_EXECUTE ; Jump to address on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CR: ; Output [CR][LF] + .BYTE $82,"C",'R'+$80 + .WORD W_TERMINAL +C_CR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UCR ; Push UCR addr + .WORD C_FETCH ; Get UCR code field addr + .WORD C_EXECUTE ; Jump to address on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CLS: ; Clear screen + .BYTE $83,"CL",'S'+$80 + .WORD W_CR +C_CLS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Put clear screen code on stack + .WORD 000Ch ; + .WORD C_EMIT ; Output it + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CMOVE: ; Move block + .BYTE $85,"CMOV",'E'+$80 + .WORD W_CLS +C_CMOVE: + .WORD 2+$ ; Vector to code + LD L,C ; Save BC for now + LD H,B ; + POP BC ; Get no. of bytes to move + POP DE ; Get destination address + EX (SP),HL ; Get source address + LD A,B ; Check it's not a 0 length block + OR C ; + JR Z,NO_BYTES ; If 0 length then do nothing + LDIR ; Move block +NO_BYTES: + POP BC ; Get BC back + JP NEXT + +W_USTAR: ; Unsigned multiply + .BYTE $82,"U",'*'+$80 + .WORD W_CMOVE +C_USTAR: + .WORD 2+$ ; Vector to code + POP DE ; get n2 + POP HL ; get n1 + PUSH BC ; save BC for now + LD C,H ; save H + LD A,L ; low byte to multiply by + CALL HALF_TIMES ; HL = A * DE + PUSH HL ; save partial result + LD H,A ; clear H + LD A,C ; high byte to multiply by + LD C,H ; clear B + CALL HALF_TIMES ; HL = A * DE + POP DE ; get last partial result + LD B,C ; add partial results + LD C,D ; add partial results + ADD HL,BC ; + ADC A,$00 ; + LD D,L ; + LD L,H ; + LD H,A ; + POP BC ; get BC back + JP NEXTS2 ; save 32 bit result & NEXT + +HALF_TIMES: ; + LD HL,$0000 ; clear partial result + LD B,08h ; eight bits to do +NEXT_BIT: + ADD HL,HL ; result * 2 + RLA ; multiply bit into C + JR NC,NO_MUL ; branch if no multiply + ADD HL,DE ; add multiplicand + ADC A,$00 ; add in any carry +NO_MUL: + DJNZ NEXT_BIT ; decr and loop if not done + RET ; + +W_UMOD: ; Unsigned divide & MOD + .BYTE $85,"U/MO",'D'+$80 + .WORD W_USTAR +C_UMOD: + .WORD 2+$ ; Vector to code + LD HL,0004 + ADD HL,SP + LD E,(HL) + LD (HL),C + INC HL + LD D,(HL) + LD (HL),B + POP BC + POP HL + LD A,L + SUB C + LD A,H + SBC A,B + JR C,J22DB + LD HL,$FFFF + LD DE,$FFFF + JR J2301 +J22DB: + LD A,10h +J22DD: + ADD HL,HL + RLA + EX DE,HL + ADD HL,HL + JR NC,J22E5 + INC DE + AND A +J22E5: + EX DE,HL + RRA + PUSH AF + JR NC,J22F2 + LD A,L + SUB C + LD L,A + LD A,H + SBC A,B + LD H,A + JR J22FC +J22F2: + LD A,L + SUB C + LD L,A + LD A,H + SBC A,B + LD H,A + JR NC,J22FC + ADD HL,BC + DEC DE +J22FC: + INC DE + POP AF + DEC A + JR NZ,J22DD +J2301: + POP BC + PUSH HL + PUSH DE + JP NEXT + +W_AND: ; AND + .BYTE $83,"AN",'D'+$80 + .WORD W_UMOD +C_AND: + .WORD 2+$ ; Vector to code + POP DE ; Get n1 off stack + POP HL ; Get n2 off stack + LD A,E ; AND lo bytes + AND L ; + LD L,A ; Result in L + LD A,D ; AND hi bytes + AND H ; + LD H,A ; Result in H + JP NEXTS1 ; Save & next + +W_OR: ; OR + .BYTE $82,"O",'R'+$80 + .WORD W_AND +C_OR: + .WORD 2+$ ; Vector to code + POP DE ; Get n1 off stack + POP HL ; Get n2 off stack + LD A,E ; OR lo bytes + OR L ; + LD L,A ; Result in L + LD A,D ; OR hi bytes + OR H ; + LD H,A ; Result in H + JP NEXTS1 ; Save & next + +W_XOR: ; XOR + .BYTE $83,"XO",'R'+$80 + .WORD W_OR +C_XOR: + .WORD 2+$ ; Vector to code + POP DE ; Get n1 off stack + POP HL ; Get n2 off stack + LD A,E ; XOR lo bytes + XOR L ; + LD L,A ; Result in L + LD A,D ; XOR hi bytes + XOR H ; + LD H,A ; Result in H + JP NEXTS1 ; Save & NEXT + +W_SPFETCH: ; Stack pointer onto stack + .BYTE $83,"SP",'@'+$80 + .WORD W_XOR +C_SPFETCH: + .WORD 2+$ ; Vector to code + LD HL,0000 ; No offset + ADD HL,SP ; Add SP to HL + JP NEXTS1 ; Save & NEXT + +W_SPSTORE: ; Set initial stack pointer value + .BYTE $83,"SP",'!'+$80 + .WORD W_SPFETCH +C_SPSTORE: + .WORD 2+$ ; Vector to code + LD HL,(DEF_SYSADDR) ; Get system base addr + LD DE,S0-SYSTEM ; Offset to stack pointer value (0006) + ADD HL,DE ; Add to base addr + LD E,(HL) ; Get SP from ram + INC HL ; + LD D,(HL) ; + EX DE,HL ; Put into HL + LD SP,HL ; Set SP + JP NEXT + +W_RPFETCH: ; Get return stack pointer + .BYTE $83,"RP",'@'+$80 + .WORD W_SPSTORE +C_RPFETCH: + .WORD 2+$ ; Vector to code + LD HL,(RPP) ; Return stack pointer into HL + JP NEXTS1 ; Save & NEXT + +W_RPSTORE: ; Set initial return stack pointer + .BYTE $83,"RP",'!'+$80 + .WORD W_RPFETCH +C_RPSTORE: + .WORD 2+$ ; Vector to code + LD HL,(DEF_SYSADDR) ; Get system base addr + LD DE,0008 ; Offset to return stack pointer value + ADD HL,DE ; Add to base addr + LD E,(HL) ; Get SP from ram + INC HL ; + LD D,(HL) ; + EX DE,HL ; Put into HL + LD (RPP),HL ; Set return SP + JP NEXT + +W_STOP: ; Pop BC from return stack (=next) + .BYTE $82,"; ",'S'+$80 + .WORD W_RPSTORE +C_STOP: + .WORD 2+$ ; Vector to code +X_STOP: + LD HL,(RPP) ; Return stack pointer to HL + LD C,(HL) ; Get low byte + INC HL ; + LD B,(HL) ; Get high byte + INC HL ; + LD (RPP),HL ; Save stack pointer + JP NEXT + +W_LEAVE: ; Quit loop by making index = limit + .BYTE $85,"LEAV",'E'+$80 + .WORD W_STOP +C_LEAVE: + .WORD 2+$ ; Vector to code + LD HL,(RPP) ; Get return stack pointer + LD E,(HL) ; Get loop limit low + INC HL ; + LD D,(HL) ; Get loop limit high + INC HL ; + LD (HL),E ; Set index low to loop limit + INC HL ; + LD (HL),D ; Set index high to loop limit + JP NEXT + +W_MOVER: ; Move from data to return stack + .BYTE $82,">",'R'+$80 + .WORD W_LEAVE +C_MOVER: + .WORD 2+$ ; Vector to code + POP DE ; Get value + LD HL,(RPP) ; Get return stack pointer + DEC HL ; Set new value + DEC HL ; + LD (RPP),HL ; Save it + LD (HL),E ; Push low byte onto return stack + INC HL ; + LD (HL),D ; Push high byte onto return stack + JP NEXT + +W_RMOVE: ; Move word from return to data stack + .BYTE $82,"R",'>'+$80 + .WORD W_MOVER +C_RMOVE: + .WORD 2+$ ; Vector to code + LD HL,(RPP) ; Get return stack pointer + LD E,(HL) ; Pop word off return stack + INC HL ; + LD D,(HL) ; + INC HL ; + LD (RPP),HL ; Save new return stack pointer + PUSH DE ; Push on data stack + JP NEXT + +W_RFETCH: ; Return stack top to data stack + .BYTE $82,"R",'@'+$80 + .WORD W_RMOVE +C_RFETCH: + .WORD X_I ; Return stack top to data stack + + +W_0EQUALS: ; =0 + .BYTE $82,"0",'='+$80 + .WORD W_RFETCH +C_0EQUALS: + .WORD 2+$ ; Vector to code +X_0EQUALS: + POP HL ; Get value from stack + LD A,L ; set flags + OR H ; + LD HL,0000 ; Not = 0 flag + JR NZ,NO_ZERO ; + INC HL ; = 0 flag +NO_ZERO: + JP NEXTS1 ; Save & NEXT + +W_NOT: ; Convert flag, same as 0= + .BYTE $83,"NO",'T'+$80 + .WORD W_0EQUALS +C_NOT: + .WORD X_0EQUALS + +W_0LESS: ; Less than 0 + .BYTE $82,"0",'<'+$80 + .WORD W_NOT +C_0LESS: + .WORD 2+$ ; Vector to code + POP HL ; Get value + ADD HL,HL ; S bit into C + LD HL,0000 ; Wasn't < 0 flag + JR NC,NOT_LT0 ; + INC HL ; Was < 0 flag +NOT_LT0: JP NEXTS1 ; Save & NEXT + +W_PLUS: ; n1 + n2 + .BYTE $81,'+'+$80 + .WORD W_0LESS +C_PLUS: + .WORD 2+$ ; Vector to code + POP DE ; Get n2 + POP HL ; Get n1 + ADD HL,DE ; Add them + JP NEXTS1 ; Save & NEXT + +W_DPLUS: ; 32 bit add + .BYTE $82,"D",'+'+$80 + .WORD W_PLUS +C_DPLUS: + .WORD 2+$ ; Vector to code + LD HL,0006 ; offset to low word + ADD HL,SP ; add stack pointer + LD E,(HL) ; get d1 low word low byte + LD (HL),C ; save BC low byte + INC HL ; point to high byte + LD D,(HL) ; get d1 low word high byte + LD (HL),B ; save BC high byte + POP BC ; get high word d2 + POP HL ; get low word d2 + ADD HL,DE ; add low words + EX DE,HL ; save result low word in DE + POP HL ; get d1 high word + LD A,L ; copy d1 high word low byte + ADC A,C ; add d2 high word low byte + ; + carry from low word add + LD L,A ; result from high word low byte into L + LD A,H ; copy d1 high word low byte + ADC A,B ; add d2 high word low byte + ; + carry from high word low byte add + LD H,A ; result from high word high byte into H + POP BC ; restore BC + JP NEXTS2 ; Save 32 bit result & NEXT + +W_NEGATE: ; Form 2s complement of n + .BYTE $86,"NEGAT",'E'+$80 + .WORD W_DPLUS +C_NEGATE: + .WORD 2+$ ; Vector to code + POP HL ; Get number + LD A,L ; Low byte into A + CPL ; Complement it + LD L,A ; Back into L + LD A,H ; High byte into A + CPL ; Complement it + LD H,A ; Back into H + INC HL ; +1 + JP NEXTS1 ; Save & NEXT + +W_DNEGATE: ; Form 2s complement of 32 bit n + .BYTE $87,"DNEGAT",'E'+$80 + .WORD W_NEGATE +C_DNEGATE: + .WORD 2+$ ; Vector to code + POP HL ; get high word + POP DE ; get low word + SUB A ; clear A + SUB E ; negate low word low byte + LD E,A ; copy back to E + LD A,$00 ; clear A + SBC A,D ; negate low word high byte + LD D,A ; copy back to D + LD A,$00 ; clear A + SBC A,L ; negate high word low byte + LD L,A ; copy back to L + LD A,$00 ; clear A + SBC A,H ; negate high word high byte + LD H,A ; copy back to H + JP NEXTS2 ; Save 32 bit result & NEXT + +W_OVER: ; Copy 2nd down to top of stack + .BYTE $84,"OVE",'R'+$80 + .WORD W_DNEGATE +C_OVER: + .WORD 2+$ ; Vector to code + POP DE ; Get top + POP HL ; Get next + PUSH HL ; Save it back + JP NEXTS2 ; Save both & NEXT + +W_DROP: ; Drop top value from stack + .BYTE $84,"DRO",'P'+$80 + .WORD W_OVER +C_DROP: + .WORD 2+$ ; Vector to code + POP HL ; Get top value + JP NEXT + +W_2DROP: ; Drop top two values from stack + .BYTE $85,"2DRO",'P'+$80 + .WORD W_DROP +C_2DROP: + .WORD 2+$ ; Vector to code + POP HL ; Get top value + POP HL ; Get top value + JP NEXT + +W_SWAP: ; Swap top 2 values on stack + .BYTE $84,"SWA",'P'+$80 + .WORD W_2DROP +C_SWAP: + .WORD 2+$ ; Vector to code + POP HL ; Get top value + EX (SP),HL ; Exchanhe with next down + JP NEXTS1 ; Save & NEXT + +W_DUP: ; Duplicate top value on stack + .BYTE $83,"DU",'P'+$80 + .WORD W_SWAP +C_DUP: + .WORD 2+$ ; Vector to code + POP HL ; Get value off stack + PUSH HL ; Copy it back + JP NEXTS1 ; Save & NEXT + +W_2DUP: ; Dup top 2 values on stack + .BYTE $84,"2DU",'P'+$80 + .WORD W_DUP +C_2DUP: + .WORD 2+$ ; Vector to code + POP HL ; Get top two values from stack + POP DE ; + PUSH DE ; Copy them back + PUSH HL ; + JP NEXTS2 ; Save both & NEXT + +W_BOUNDS: ; Convert address & n to start & end + .BYTE $86,"BOUND",'S'+$80 + .WORD W_2DUP +C_BOUNDS: + .WORD 2+$ ; Vector to code + POP HL ; get n + POP DE ; get addr + ADD HL,DE ; add addr to n + EX DE,HL ; swap them + JP NEXTS2 ; save both & NEXT + +W_PLUSSTORE: ; Add n1 to addr + .BYTE $82,"+",'!'+$80 + .WORD W_BOUNDS +C_PLUSSTORE: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + POP DE ; Get DE + LD A,(HL) ; Add low bytes + ADD A,E ; + LD (HL),A ; Store result + INC HL ; Point to high byte + LD A,(HL) ; Add high bytes + ADC A,D ; + LD (HL),A ; Store result + JP NEXT + +W_TOGGLE: ; XOR (addr) with byte + .BYTE $86,"TOGGL",'E'+$80 + .WORD W_PLUSSTORE +C_TOGGLE: + .WORD 2+$ ; Vector to code + POP DE ; Get byte + POP HL ; Get addr + LD A,(HL) ; Get byte from addr + XOR E ; Toggle it + LD (HL),A ; Save result + JP NEXT + +W_FETCH: ; Get word from addr on stack + .BYTE $81,'@'+$80 + .WORD W_TOGGLE +C_FETCH: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + LD E,(HL) ; Get low byte + INC HL ; + LD D,(HL) ; Get high byte + PUSH DE ; Save it + JP NEXT + +W_CFETCH: ; Get byte from addr on stack + .BYTE $82,"C",'@'+$80 + .WORD W_FETCH +C_CFETCH: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + LD L,(HL) ; Get byte + LD H,$00 ; Top byte = 0 + JP NEXTS1 ; Save & NEXT + +W_2FETCH: ; Get word from addr+2 and addr + .BYTE $82,"2",'@'+$80 + .WORD W_CFETCH +C_2FETCH: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + LD DE,0002 ; Plus 2 bytes + ADD HL,DE ; Get 2nd word first + LD E,(HL) ; Low byte + INC HL ; + LD D,(HL) ; High byte + PUSH DE ; Save it + LD DE,$FFFD ; Minus 2 bytes + ADD HL,DE ; Get 1st word + LD E,(HL) ; Low byte + INC HL ; + LD D,(HL) ; High byte + PUSH DE ; Save it + JP NEXT + +W_STORE: ; Store word at addr + .BYTE $81,'!'+$80 + .WORD W_2FETCH +C_STORE: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + POP DE ; Get word + LD (HL),E ; Store low byte + INC HL ; + LD (HL),D ; Store high byte + JP NEXT + +W_CSTORE: ; Store byte at addr + .BYTE $82,"C",'!'+$80 + .WORD W_STORE +C_CSTORE: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + POP DE ; Get byte + LD (HL),E ; Save it + JP NEXT + +W_2STORE: ; Store 2 words at addr (+2) + .BYTE $82,"2",'!'+$80 + .WORD W_CSTORE +C_2STORE: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + POP DE ; Get word + LD (HL),E ; Save low byte + INC HL ; + LD (HL),D ; Save high byte + INC HL ; + POP DE ; Get next word + LD (HL),E ; Save low byte + INC HL ; + LD (HL),D ; Save high byte + JP NEXT + +W_COLON: + .BYTE $81,':'+$80 + .WORD W_2STORE +C_COLON: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QEXEC ; Error not if not in execute mode + .WORD C_CSPSTORE ; Set current stack pointer value + .WORD C_CURRENT ; Get CURRENT addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CONTEXT ; Make CONTEXT current vocab + .WORD C_STORE ; Store word at addr + .WORD C_XXX1 ; Puts name into dictionary + .WORD C_RIGHTBRKT ; Set STATE to compile + .WORD C_CCODE ; Execute following machine code + +E_COLON: + LD HL,(RPP) ; Get return stack pointer + DEC HL ; Put BC on return stack + LD (HL),B ; + DEC HL ; + LD (HL),C ; + LD (RPP),HL ; Save new pointer + INC DE + LD C,E + LD B,D + JP NEXT + +W_SEMICOLON: ; Terminate compilation + .BYTE $C1,'; '+$80 + .WORD W_COLON +C_SEMICOLON: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QCOMP ; Check we're allready compiling + .WORD C_WHATSTACK ; Check stack pointer, error if not ok + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_STOP ; + .WORD C_SMUDGE ; Smudge bit to O.K. + .WORD C_LEFTBRKT ; Set STATE to execute + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CONSTANT: + .BYTE $88,"CONSTAN",'T'+$80 + .WORD W_SEMICOLON +C_CONSTANT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_XXX1 + .WORD C_SMUDGE + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_CCODE ; Execute following machine code + +X_CONSTANT: ; Put next word on stack + INC DE ; Adjust pointer + EX DE,HL ; Get next word + LD E,(HL) ; + INC HL ; + LD D,(HL) ; + PUSH DE ; Put on stack + JP NEXT + +W_VARIABLE: + .BYTE $88,"VARIABL",'E'+$80 + .WORD W_CONSTANT +C_VARIABLE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_CONSTANT + .WORD C_CCODE ; Execute following machine code + +X_VARIABLE: + INC DE + PUSH DE + JP NEXT + +W_USER: + .BYTE $84,"USE",'R'+$80 + .WORD W_VARIABLE +C_USER: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CONSTANT + .WORD C_CCODE ; Execute following machine code + +X_USER: + INC DE ; Adjust to next word + EX DE,HL + LD E,(HL) + INC HL + LD D,(HL) + LD HL,(DEF_SYSADDR) + ADD HL,DE + JP NEXTS1 ; Save & NEXT + +W_ZERO: ; Put zero on stack + .BYTE $81,'0'+$80 + .WORD W_USER +C_ZERO: + .WORD X_CONSTANT ; Put next word on stack + .WORD $0000 + +W_1: ; Put 1 on stack + .BYTE $81,'1'+$80 + .WORD W_ZERO +C_1: + .WORD X_CONSTANT ; Put next word on stack + .WORD 0001h + +W_2: + .BYTE $81,'2'+$80 + .WORD W_1 +C_2: + .WORD X_CONSTANT ; Put next word on stack + .WORD 0002h + +W_3: + .BYTE $81,'3'+$80 + .WORD W_2 +C_3: + .WORD X_CONSTANT ; Put next word on stack + .WORD 0003h + +W_BL: ; Leaves ASCII for blank on stack + .BYTE $82,"B",'L'+$80 + .WORD W_3 +C_BL: + .WORD X_CONSTANT ; Put next word on stack + .WORD 0020h + +W_CL: + .BYTE $83,"C/",'L'+$80 + .WORD W_BL +C_CL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UCL + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_FIRST: + .BYTE $85,"FIRS",'T'+$80 + .WORD W_CL +C_FIRST: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UFIRST ; Put UFIRST addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LIMIT: + .BYTE $85,"LIMI",'T'+$80 + .WORD W_FIRST +C_LIMIT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ULIMIT ; Put ULIMIT on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BBUF: + .BYTE $85,"B/BU",'F'+$80 + .WORD W_LIMIT +C_BBUF: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UBBUF + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BSCR: + .BYTE $85,"B/SC",'R'+$80 + .WORD W_BBUF +C_BSCR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UBSCR ; Number of buffers per block + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_S0: ; Push S0 (initial data stack pointer) + .BYTE $82,"S",'0'+$80 + .WORD W_BSCR +C_S0: + .WORD X_USER ; Put next word on stack then do next + .WORD S0-SYSTEM + +W_R0: + .BYTE $82,"R",'0'+$80 + .WORD W_S0 +C_R0: + .WORD X_USER ; Put next word on stack then do next + .WORD R0-SYSTEM + +W_TIB: + .BYTE $83,"TI",'B'+$80 + .WORD W_R0 +C_TIB: + .WORD X_USER ; Put next word on stack then do next + .WORD TIB-SYSTEM + +W_WIDTH: + .BYTE $85,"WIDT",'H'+$80 + .WORD W_TIB +C_WIDTH: + .WORD X_USER ; Put next word on stack then do next + .WORD WIDTH-SYSTEM + +W_WARNING: ; Put WARNING addr on stack + .BYTE $87,"WARNIN",'G'+$80 + .WORD W_WIDTH +C_WARNING: + .WORD X_USER ; Put next word on stack then do next + .WORD WARNING-SYSTEM + +W_FENCE: + .BYTE $85,"FENC",'E'+$80 + .WORD W_WARNING +C_FENCE: + .WORD X_USER ; Put next word on stack then do next + .WORD FENCE-SYSTEM + +W_DP: ; Dictionary pointer addr on stack + .BYTE $82,"D",'P'+$80 + .WORD W_FENCE +C_DP: + .WORD X_USER ; Put next word on stack then do next + .WORD DP-SYSTEM + +W_VOC_LINK: + .BYTE $88,"VOC-LIN",'K'+$80 + .WORD W_DP +C_VOC_LINK: + .WORD X_USER ; Put next word on stack then do next + .WORD VOC_LINK-SYSTEM + +W_BLK: + .BYTE $83,"BL",'K'+$80 + .WORD W_VOC_LINK +C_BLK: + .WORD X_USER ; Put next word on stack then do next + .WORD BLK-SYSTEM + +W_TOIN: + .BYTE $83,">I",'N'+$80 + .WORD W_BLK +C_TOIN: + .WORD X_USER ; Put next word on stack then do next + .WORD TOIN-SYSTEM + +W_OUT: ; Put OUT buffer count addr on stack + .BYTE $83,"OU",'T'+$80 + .WORD W_TOIN +C_OUT: + .WORD X_USER ; Put next word on stack then do next + .WORD OUT-SYSTEM + +W_SCR: + .BYTE $83,"SC",'R'+$80 + .WORD W_OUT +C_SCR: + .WORD X_USER ; Put next word on stack then do next + .WORD SCR-SYSTEM + +W_OFFSET: ; Put disk block offset on stack + .BYTE $86,"OFFSE",'T'+$80 + .WORD W_SCR +C_OFFSET: + .WORD X_USER ; Put next word on stack then do next + .WORD OFFSET-SYSTEM + +W_CONTEXT: + .BYTE $87,"CONTEX",'T'+$80 + .WORD W_OFFSET +C_CONTEXT: + .WORD X_USER ; Put next word on stack then do next + .WORD CONTEXT-SYSTEM + +W_CURRENT: + .BYTE $87,"CURREN",'T'+$80 + .WORD W_CONTEXT +C_CURRENT: + .WORD X_USER ; Put next word on stack then do next + .WORD CURRENT-SYSTEM + +W_STATE: ; Push STATE addr + .BYTE $85,"STAT",'E'+$80 + .WORD W_CURRENT +C_STATE: + .WORD X_USER ; Put next word on stack then do next + .WORD STATE-SYSTEM + +W_BASE: ; Put BASE addr on stack + .BYTE $84,"BAS",'E'+$80 + .WORD W_STATE +C_BASE: + .WORD X_USER ; Put next word on stack then do next + .WORD BASE-SYSTEM + +W_DPL: + .BYTE $83,"DP",'L'+$80 + .WORD W_BASE +C_DPL: + .WORD X_USER ; Put next word on stack then do next + .WORD DPL-SYSTEM + +W_FLD: + .BYTE $83,"FL",'D'+$80 + .WORD W_DPL +C_FLD: + .WORD X_USER ; Put next word on stack then do next + .WORD FLD-SYSTEM + +W_CSP: ; Push check stack pointer addr + .BYTE $83,"CS",'P'+$80 + .WORD W_FLD +C_CSP: + .WORD X_USER ; Put next word on stack then do next + .WORD CSP-SYSTEM + +W_RHASH: + .BYTE $82,"R",'#'+$80 + .WORD W_CSP +C_RHASH: + .WORD X_USER ; Put next word on stack then do next + .WORD RHASH-SYSTEM + +W_HLD: + .BYTE $83,"HL",'D'+$80 + .WORD W_RHASH +C_HLD: + .WORD X_USER ; Put next word on stack then do next + .WORD HLD-SYSTEM + +W_UCL: + .BYTE $84,"UC/",'L'+$80 + .WORD W_HLD +C_UCL: + .WORD X_USER ; Put next word on stack then do next + .WORD UCL-SYSTEM + +W_UFIRST: + .BYTE $86,"UFIRS",'T'+$80 + .WORD W_UCL +C_UFIRST: + .WORD X_USER ; Put next word on stack then do next + .WORD UFIRST-SYSTEM + +W_ULIMIT: + .BYTE $86,"ULIMI",'T'+$80 + .WORD W_UFIRST +C_ULIMIT: + .WORD X_USER ; Put next word on stack then do next + .WORD ULIMIT-SYSTEM + +W_UBBUF: + .BYTE $86,"UB/BU",'F'+$80 + .WORD W_ULIMIT +C_UBBUF: + .WORD X_USER ; Put next word on stack then do next + .WORD UBBUF-SYSTEM + +W_UBSCR: + .BYTE $86,"UB/SC",'R'+$80 + .WORD W_UBBUF +C_UBSCR: + .WORD X_USER ; Put next word on stack then do next + .WORD UBSCR-SYSTEM + +W_UTERMINAL: + .BYTE 8Ah,"U?TERMINA",'L'+$80 + .WORD W_UBSCR +C_UTERMINAL: + .WORD X_USER ; Put next word on stack then do next + .WORD UTERMNL-SYSTEM + +W_UKEY: ; Put UKEY addr on stack + .BYTE $84,"UKE",'Y'+$80 + .WORD W_UTERMINAL +C_UKEY: + .WORD X_USER ; Put next word on stack then do next + .WORD UKEY-SYSTEM + +W_UEMIT: ; Put UEMIT addr on stack + .BYTE $85,"UEMI",'T'+$80 + .WORD W_UKEY +C_UEMIT: + .WORD X_USER ; Put next word on stack then do next + .WORD UEMIT-SYSTEM + +W_UCR: ; Push UCR addr + .BYTE $83,"UC",'R'+$80 + .WORD W_UEMIT +C_UCR: + .WORD X_USER ; Put next word on stack then do next + .WORD UCR-SYSTEM + +W_URW: + .BYTE $84,"UR/",'W'+$80 + .WORD W_UCR +C_URW: + .WORD X_USER ; Put next word on stack then do next + .WORD URW-SYSTEM + +W_UABORT: ; Put UABORT on stack + .BYTE $86,"UABOR",'T'+$80 + .WORD W_URW +C_UABORT: + .WORD X_USER ; Put next word on stack then do next + .WORD UABORT-SYSTEM + +W_RAF: + .BYTE $83,"RA",'F'+$80 + .WORD W_UABORT +C_RAF: + .WORD X_USER ; Put next word on stack then do next + .WORD RAF-SYSTEM + +W_RBC: + .BYTE $83,"RB",'C'+$80 + .WORD W_RAF +C_RBC: + .WORD X_USER ; Put next word on stack then do next + .WORD RBC-SYSTEM + +W_RDE: + .BYTE $83,"RD",'E'+$80 + .WORD W_RBC +C_RDE + .WORD X_USER ; Put next word on stack then do next + .WORD RDE-SYSTEM + +W_RHL: + .BYTE $83,"RH",'L'+$80 + .WORD W_RDE +C_RHL: + .WORD X_USER ; Put next word on stack then do next + .WORD RHL-SYSTEM + +W_RIX: + .BYTE $83,"RI",'X'+$80 + .WORD W_RHL +C_RIX: + .WORD X_USER ; Put next word on stack then do next + .WORD RIX-SYSTEM + +W_RIY: + .BYTE $83,"RI",'Y'+$80 + .WORD W_RIX +C_RIY: + .WORD X_USER ; Put next word on stack then do next + .WORD RIY-SYSTEM + +W_RAF2: + .BYTE $84,"RAF",2Ch+$80 + .WORD W_RIY +C_RAF2: + .WORD X_USER ; Put next word on stack then do next + .WORD RAF2-SYSTEM + +W_RBC2: + .BYTE $84,"RBC",2Ch+$80 + .WORD W_RAF2 +C_RBC2: + .WORD X_USER ; Put next word on stack then do next + .WORD RBC2-SYSTEM + +W_RDE2: + .BYTE $84,"RDE",2Ch+$80 + .WORD W_RBC2 +C_RDE2: + .WORD X_USER ; Put next word on stack then do next + .WORD RDE2-SYSTEM + +W_RHL2: + .BYTE $84,"RHL",2Ch+$80 + .WORD W_RDE2 +C_RHL2: + .WORD X_USER ; Put next word on stack then do next + .WORD RHL2-SYSTEM + +W_RA: + .BYTE $82,"R",'A'+$80 + .WORD W_RHL2 +C_RA: + .WORD X_USER ; Put next word on stack then do next + .WORD RAF+1-SYSTEM + +W_RF: + .BYTE $82,"R",'F'+$80 + .WORD W_RA +C_RF: + .WORD X_USER ; Put next word on stack then do next + .WORD RAF-SYSTEM + +W_RB: + .BYTE $82,"R",'B'+$80 + .WORD W_RF +C_RB: + .WORD X_USER ; Put next word on stack then do next + .WORD RBC+1-SYSTEM + +W_RC: + .BYTE $82,"R",'C'+$80 + .WORD W_RB +C_RC: + .WORD X_USER ; Put next word on stack then do next + .WORD RBC-SYSTEM + +W_RD: + .BYTE $82,"R",'D'+$80 + .WORD W_RC +C_RD: + .WORD X_USER ; Put next word on stack then do next + .WORD RDE+1-SYSTEM + +W_RE: + .BYTE $82,"R",'E'+$80 + .WORD W_RD +C_RE: + .WORD X_USER ; Put next word on stack then do next + .WORD RDE-SYSTEM + +W_RH: + .BYTE $82,"R",'H'+$80 + .WORD W_RE +C_RH: + .WORD X_USER ; Put next word on stack then do next + .WORD RHL+1-SYSTEM + +W_RL: + .BYTE $82,"R",'L'+$80 + .WORD W_RH +C_RL: + .WORD X_USER ; Put next word on stack then do next + .WORD RHL-SYSTEM + +W_CALL: + .BYTE $84,"CAL",'L'+$80 + .WORD W_RL +C_CALL: + .WORD 2+$ ; Vector to code + POP HL ; Address of routine CALLed + PUSH DE ; Save register + PUSH BC ; Save register + LD A,$C3 ; Hex code for JMP + LD (JPCODE),A ; Save it + LD (JPVECT),HL ; Save jump vector + LD HL,(RAF) ; Get register AF + PUSH HL ; Onto stack + POP AF ; POP into AF + LD BC,(RBC) ; Get register BC + LD DE,(RDE) ; Get register DE + LD HL,(RHL) ; Get register HL + LD IX,(RIX) ; Get register IX + LD IY,(RIY) ; Get register IY + CALL JPCODE ; Call jump to code + LD (RIY),IY ; Save register IY + LD (RIX),IX ; Save register IX + LD (RBC),BC ; Save register BC + LD (RDE),DE ; Save register DE + LD (RHL),HL ; Save register HL + PUSH AF ; Save register AF + POP HL ; Into HL + LD (RAF),HL ; Into memory + POP BC ; Restore BC + POP DE ; Restore DE + JP NEXT ; + +W_1PLUS: ; 1 plus + .BYTE $82,"1",'+'+$80 + .WORD W_CALL +C_1PLUS: + .WORD 2+$ ; Vector to code + POP HL ; get n + INC HL ; add 1 + JP NEXTS1 ; save result & NEXT + +W_2PLUS: ; 2 plus + .BYTE $82,"2",'+'+$80 + .WORD W_1PLUS +C_2PLUS: + .WORD 2+$ ; Vector to code + POP HL ; get n + INC HL ; add 1 + INC HL ; add 2 + JP NEXTS1 ; save result & NEXT + +W_1MINUS: ; 1 minus + .BYTE $82,"1",'-'+$80 + .WORD W_2PLUS +C_1MINUS: + .WORD 2+$ ; Vector to code + POP HL ; get n + DEC HL ; add 1 + JP NEXTS1 ; save result & NEXT + +W_2MINUS: ; 2 minus + .BYTE $82,"2",'-'+$80 + .WORD W_1MINUS +C_2MINUS: + .WORD 2+$ ; Vector to code + POP HL ; get n + DEC HL ; subtract 1 + DEC HL ; subtract 2 + JP NEXTS1 ; save result & NEXT + +W_HERE: ; Dictionary pointer onto stack + .BYTE $84,"HER",'E'+$80 + .WORD W_2MINUS +C_HERE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DP ; Dictionary pointer addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ALLOT: + .BYTE $85,"ALLO",'T'+$80 + .WORD W_HERE +C_ALLOT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DP ; Dictionary pointer addr on stack + .WORD C_PLUSSTORE ; Add n1 to addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_COMMA: ; Reserve 2 bytes and save n + .BYTE $81,','+$80 + .WORD W_ALLOT +C_COMMA: + .WORD E_COLON ; Interpret following word sequence + .WORD C_HERE ; Next free dictionary pointer onto stack + .WORD C_STORE ; Store word at addr + .WORD C_2 ; + .WORD C_ALLOT ; Move pointer + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CCOMMA: + .BYTE $82,"C",','+$80 + .WORD W_COMMA +C_CCOMMA: + .WORD E_COLON ; Interpret following word sequence + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_CSTORE ; Store byte at addr + .WORD C_1 ; Put 1 on stack + .WORD C_ALLOT + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MINUS: + .BYTE $81,'-'+$80 + .WORD W_CCOMMA +C_MINUS: + .WORD 2+$ ; Vector to code + POP DE ; get n1 + POP HL ; get n2 + CALL MINUS16 ; call subtract routine + JP NEXTS1 ; save & NEXT + +MINUS16: + LD A,L ; gel low byte + SUB E ; subtract low bytes + LD L,A ; save low byte result + LD A,H ; get high byte + SBC A,D ; subtract high bytes + LD H,A ; save high byte result + RET ; + +W_EQUALS: + .BYTE $81,'='+$80 + .WORD W_MINUS +C_EQUALS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MINUS + .WORD C_0EQUALS ; =0 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LESSTHAN: + .BYTE $81,'<'+$80 + .WORD W_EQUALS +C_LESSTHAN: + .WORD 2+$ ; Vector to code + POP DE + POP HL + LD A,D + XOR H + JP M,J298C + CALL MINUS16 +J298C: + INC H + DEC H + JP M,J2997 + LD HL,0000 + JP NEXTS1 ; Save & NEXT +J2997: + LD HL,0001 + JP NEXTS1 ; Save & NEXT + +W_ULESS: ; IF stack-1 < stack_top leave true flag + .BYTE $82,"U",'<'+$80 + .WORD W_LESSTHAN +C_ULESS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_2DUP ; Dup top 2 values on stack + .WORD C_XOR ; Exclusive OR them + .WORD C_0LESS ; Less than 0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0000-$ ; 000Ch + .WORD C_DROP ; Drop top value from stack + .WORD C_0LESS ; Less than 0 + .WORD C_0EQUALS ; =0 + .WORD C_BRANCH ; Add following offset to BC + .WORD B0001-$ ; 0006h +B0000: + .WORD C_MINUS + .WORD C_0LESS ; Less than 0 +B0001: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_GREATER: + .BYTE $81,'>'+$80 + .WORD W_ULESS +C_GREATER: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_LESSTHAN + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ROT: ; 3rd valu down to top of stack + .BYTE $83,"RO",'T'+$80 + .WORD W_GREATER +C_ROT: + .WORD 2+$ ; Vector to code + POP DE ; Top value + POP HL ; Next one down + EX (SP),HL ; Exchange with third + JP NEXTS2 ; Save both & NEXT + +W_PICK: + .BYTE $84,"PIC",'K'+$80 + .WORD W_ROT +C_PICK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate top value on stack + .WORD C_PLUS ; n1 + n2 + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_PLUS ; n1 + n2 + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SPACE: + .BYTE $85,"SPAC",'E'+$80 + .WORD W_PICK +C_SPACE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BL ; Leaves ASCII for space on stack + .WORD C_EMIT ; Output CHR from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QUERYDUP: + .BYTE $84,"?DU",'P'+$80 + .WORD W_SPACE +C_QUERYDUP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate top value on stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0002-$ ; 0004h + .WORD C_DUP ; Duplicate top value on stack +B0002: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TRAVERSE: + .BYTE $88,"TRAVERS",'E'+$80 + .WORD W_QUERYDUP +C_TRAVERSE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SWAP ; Swap top 2 values on stack +B0054: + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_PLUS ; n1 + n2 + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 007Fh + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_LESSTHAN + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0054-$ ; FFF0h + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LATEST: + .BYTE $86,"LATES",'T'+$80 + .WORD W_TRAVERSE +C_LATEST: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CURRENT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LFA: + .BYTE $83,"LF",'A'+$80 + .WORD W_LATEST +C_LFA: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0004h + .WORD C_MINUS + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CFA: + .BYTE $83,"CF",'A'+$80 + .WORD W_LFA +C_CFA: + .WORD 2+$ ; Vector to code + POP HL ; get n + DEC HL ; subtract 1 + DEC HL ; subtract 2 + JP NEXTS1 ; save result & NEXT +W_NFA: + .BYTE $83,"NF",'A'+$80 + .WORD W_CFA +C_NFA: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0005h + .WORD C_MINUS + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $FFFF + .WORD C_TRAVERSE + .WORD C_STOP ; Pop BC from return stack (=next) + +W_PFA: ; Convert NFA to PFA + .BYTE $83,"PF",'A'+$80 + .WORD W_NFA +C_PFA: + .WORD E_COLON ; Interpret following word sequence + .WORD C_1 ; Traverse up memory + .WORD C_TRAVERSE ; End of name on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0005h ; Offset to start of word code + .WORD C_PLUS ; n1 + n2 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CSPSTORE: + .BYTE $84,"!CS",'P'+$80 + .WORD W_PFA +C_CSPSTORE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_CSP ; Push check stack pointer addr + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QERROR: + .BYTE $86,"?ERRO",'R'+$80 + .WORD W_CSPSTORE +C_QERROR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_0BRANCH ; Branch if no error + .WORD B0003-$ ; 0008h + .WORD C_ERROR + .WORD C_BRANCH ; Add following offset to BC + .WORD B0004-$ ; 0004h +B0003: + .WORD C_DROP ; Drop error no. +B0004: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QCOMP: ; Error if not in compile mode + .BYTE $85,"?COM",'P'+$80 + .WORD W_QERROR +C_QCOMP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_STATE ; Push STATE addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0EQUALS ; =0 + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0011h ; Error message number + .WORD C_QERROR ; Error if state <> 0 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QEXEC: ; Error not if not in execute mode + .BYTE $85,"?EXE",'C'+$80 + .WORD W_QCOMP +C_QEXEC: + .WORD E_COLON ; Interpret following word sequence + .WORD C_STATE ; Push STATE addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0012h ; Error not if not in execute mode + .WORD C_QERROR + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QPAIRS: + .BYTE $86,"?PAIR",'S'+$80 + .WORD W_QEXEC +C_QPAIRS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MINUS + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0013h + .WORD C_QERROR + .WORD C_STOP ; Pop BC from return stack (=next) + +W_WHATSTACK: ; Check stack pointer, error if not ok + .BYTE $84,"?CS",'P'+$80 + .WORD W_QPAIRS +C_WHATSTACK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_CSP ; Push check stack pointer addr + .WORD C_FETCH ; Get check stack pointer + .WORD C_MINUS ; If ok then result is 0 + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0014h ; Error no if not ok + .WORD C_QERROR ; Error if stack top -1 <> 0 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QLOADING: + .BYTE $88,"?LOADIN",'G'+$80 + .WORD W_WHATSTACK +C_QLOADING: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0EQUALS ; =0 + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0016h + .WORD C_QERROR + .WORD C_STOP ; Pop BC from return stack (=next) + +W_COMPILE: + .BYTE $87,"COMPIL",'E'+$80 + .WORD W_QLOADING +C_COMPILE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QCOMP ; Error if not in compile mode + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_DUP ; Bump return address and put back + .WORD C_2PLUS ; + .WORD C_MOVER ; + .WORD C_FETCH ; Get word from addr on stack + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LEFTBRKT: ; Set STATE to execute + .BYTE $81,'['+$80 + .WORD W_COMPILE +C_LEFTBRKT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_STATE ; Push STATE addr + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_RIGHTBRKT: ; Set STATE to compile + .BYTE $81,']'+$80 + .WORD W_LEFTBRKT +C_RIGHTBRKT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 00$C0 + .WORD C_STATE ; Push STATE addr + .WORD C_STORE ; Set STATE to execute + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SMUDGE: + .BYTE $86,"SMUDG",'E'+$80 + .WORD W_RIGHTBRKT +C_SMUDGE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LATEST ; Push top words NFA + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0020h + .WORD C_TOGGLE ; XOR (addr) with byte + .WORD C_STOP ; Pop BC from return stack (=next) + +W_HEX: + .BYTE $83,"HE",'X'+$80 + .WORD W_SMUDGE +C_HEX: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0010h + .WORD C_BASE ; Put BASE addr on stack + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DECIMAL: ; Sets decimal mode + .BYTE $87,"DECIMA",'L'+$80 + .WORD W_HEX +C_DECIMAL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 00$0A ; Sets decimal value + .WORD C_BASE ; Put BASE addr on stack + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CCODE: ; Stop compillation & terminate word + .BYTE $87,"<; CODE",'>'+$80 + .WORD W_DECIMAL +C_CCODE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_LATEST ; Push top words NFA + .WORD C_PFA ; Convert NFA to PFA + .WORD C_CFA ; Convert PFA to CFA + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SCCODE: + .BYTE $C5,"; COD",'E'+$80 + .WORD W_CCODE +C_SCCODE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_WHATSTACK ; Check stack pointer, error if not ok + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_CCODE + .WORD C_LEFTBRKT ; Set STATE to execute + .WORD C_TASK + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CREATE: + .BYTE $86,"CREAT",'E'+$80 + .WORD W_SCCODE +C_CREATE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_CONSTANT + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DOES: + .BYTE $85,"DOES",'>'+$80 + .WORD W_CREATE +C_DOES: + .WORD E_COLON ; Interpret following word sequence + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_LATEST ; Push top words NFA + .WORD C_PFA ; Convert NFA to PFA + .WORD C_STORE ; Store word at addr + .WORD C_CCODE ; Execute following machine code + +X_DOES: + LD HL,(RPP) ; Get return stack pointer + DEC HL ; Push next pointer + LD (HL),B ; + DEC HL ; + LD (HL),C ; + LD (RPP),HL + INC DE + EX DE,HL + LD C,(HL) + INC HL + LD B,(HL) + INC HL + JP NEXTS1 ; Save & NEXT + +W_COUNT: ; Convert string at addr to addr + length + .BYTE $85,"COUN",'T'+$80 + .WORD W_DOES +C_COUNT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate address + .WORD C_1PLUS ; Add 1 (points to string start) + .WORD C_SWAP ; Get address back + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TYPE: ; Output n bytes from addr + .BYTE $84,"TYP",'E'+$80 + .WORD W_COUNT +C_TYPE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QUERYDUP ; Copy length if length <> 0 + .WORD C_0BRANCH ; Branch if length = 0 + .WORD B0005-$ ; 0018h + .WORD C_OVER ; Copy address to stack top + .WORD C_PLUS ; Add to length + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_LDO ; Put start & end loop values on RPP +B004F: + .WORD C_I ; Copy LOOP index to data stack + .WORD C_CFETCH ; Get byte from string + .WORD C_EMIT ; Output CHR from stack + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD B004F-$ ; FFF8h + .WORD C_BRANCH ; Done so branch to next + .WORD B0006-$ ; 0004h +B0005: + .WORD C_DROP ; Drop string address +B0006: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TRAILING: + .BYTE $89,"-TRAILIN",'G'+$80 + .WORD W_TYPE +C_TRAILING: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate top value on stack + .WORD C_ZERO ; Put zero on stack + .WORD C_LDO ; Put start & end loop values on RPP +B0009: + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_PLUS ; n1 + n2 + .WORD C_1 ; Put 1 on stack + .WORD C_MINUS + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_BL ; Leaves ASCII for space on stack + .WORD C_MINUS + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0007-$ ; 0008h + .WORD C_LEAVE ; Quit loop by making index = limit + .WORD C_BRANCH ; Add following offset to BC + .WORD B0008-$ ; 0006h +B0007: + .WORD C_1 ; Put 1 on stack + .WORD C_MINUS +B0008: + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD B0009-$ ; FFE0h + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CQUOTE: ; Output following string + .BYTE $84,"<.",22h,'>'+$80 + .WORD W_TRAILING +C_CQUOTE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_RFETCH ; Copy return stack top to data stack + .WORD C_COUNT ; Convert string at addr to addr + length + .WORD C_DUP ; Duplicate top value on stack + .WORD C_1PLUS ; 1 plus + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_PLUS ; Add length of string +1 + .WORD C_MOVER ; Move value from data to return stack + .WORD C_TYPE ; Output n bytes from addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QUOTE: ; Accept following text + .BYTE $C2,".",$22+$80 + .WORD W_CQUOTE +C_QUOTE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0022 + .WORD C_STATE ; Push STATE addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B000A-$ ; 0012h + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_CQUOTE + .WORD C_WORD + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_1PLUS ; 1 plus + .WORD C_ALLOT + .WORD C_BRANCH ; Add following offset to BC + .WORD B000B-$ ; 0008h +B000A: + .WORD C_WORD + .WORD C_COUNT ; Convert string at addr to addr + length + .WORD C_TYPE ; Output n bytes from addr +B000B: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_EXPECT: + .BYTE $86,"EXPEC",'T'+$80 + .WORD W_QUOTE +C_EXPECT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_OVER ; Copy buffer start addr + .WORD C_PLUS ; Add to length to give start,end + .WORD C_OVER ; Copy start + .WORD C_LDO ; Put start & end loop values on RPP +B0012: + .WORD C_KEY ; Wait for key, value on stack + .WORD C_DUP ; Duplicate key value + .WORD C_LIT ; Push backspace addr + .WORD BACKSPACE + .WORD C_FETCH ; Get backspace value + .WORD C_EQUALS ; Was it backspace ? + .WORD C_0BRANCH ; If not then jump + .WORD B000C-$ ; 002Ah + .WORD C_DROP ; Drop top value from stack + .WORD C_DUP ; Duplicate top value on stack + .WORD C_I ; Copy LOOP index to data stack + .WORD C_EQUALS + .WORD C_DUP ; Duplicate top value on stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_2 + .WORD C_MINUS + .WORD C_PLUS ; n1 + n2 + .WORD C_MOVER ; Move value from data to return stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B000D-$ ; 00$0A + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0007h + .WORD C_BRANCH ; Add following offset to BC + .WORD B000E-$ ; 0006h +B000D: + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0008h +B000E: + .WORD C_BRANCH ; Add following offset to BC + .WORD B000F-$ ; 0028h +B000C: + .WORD C_DUP ; Duplicate key value + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 00$0D ; CR + .WORD C_EQUALS ; Was it cariage return + .WORD C_0BRANCH ; If not then jump + .WORD B0010-$ ; 000Eh + .WORD C_LEAVE ; Quit loop by making index = limit + .WORD C_DROP ; Drop top value from stack + .WORD C_BL ; Leaves ASCII for space on stack + .WORD C_ZERO ; Put zero on stack + .WORD C_BRANCH ; Add following offset to BC + .WORD B0011-$ ; 0004h +B0010: + .WORD C_DUP ; Duplicate key value +B0011: + .WORD C_I ; Copy LOOP index to data stack + .WORD C_CSTORE ; Store byte at addr + .WORD C_ZERO ; Put zero on stack + .WORD C_I ; Copy LOOP index to data stack + .WORD C_1PLUS ; 1 plus + .WORD C_STORE ; Store word at addr +B000F: + .WORD C_EMIT ; Output CHR from stack + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD B0012-$ ; FF9Eh + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QUERY: + .BYTE $85,"QUER",'Y'+$80 + .WORD W_EXPECT +C_QUERY: + .WORD E_COLON ; Interpret following word sequence + .WORD C_TIB ; Put TIB addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0050 ; Max line length 50h + .WORD C_EXPECT ; Get line + .WORD C_ZERO ; Put zero on stack + .WORD C_TOIN ; Current input buffer offset + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_NULL: + .BYTE $C1,$80 + .WORD W_QUERY +C_NULL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0013-$ ; 002Ah + .WORD C_1 ; Put 1 on stack + .WORD C_BLK + .WORD C_PLUSSTORE ; Add n1 to addr + .WORD C_ZERO ; Put zero on stack + .WORD C_TOIN ; Current input buffer offset + .WORD C_STORE ; Store word at addr + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_BSCR ; Number of buffers per block on stack + .WORD C_1 ; Put 1 on stack + .WORD C_MINUS + .WORD C_AND ; AND + .WORD C_0EQUALS ; =0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0014-$ ; 0008h + .WORD C_QEXEC ; Error not if not in execute mode + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_DROP ; Drop top value from stack +B0014: + .WORD C_BRANCH ; Add following offset to BC + .WORD B0015-$ ; 0006h +B0013: + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_DROP ; Drop top value from stack +B0015: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_FILL: ; Fill with byte n bytes from addr + .BYTE $84,"FIL",'L'+$80 + .WORD W_NULL +C_FILL: + .WORD 2+$ ; Vector to code + LD L,C ; Save BC for now + LD H,B ; + POP DE ; get byte + POP BC ; get n + EX (SP),HL ; get addr and save BC + EX DE,HL ; +NEXT_BYTE: + LD A,B ; Test count + OR C ; + JR Z,NO_COUNT ; If 0 we're done + LD A,L ; Byte into A + LD (DE),A ; Save byte + INC DE ; Next addr + DEC BC ; Decr count + JR NEXT_BYTE ; Loop +NO_COUNT: + POP BC ; Get BC back + JP NEXT + +W_ERASE: ; Fill addr & length from stack with 0 + .BYTE $85,"ERAS",'E'+$80 + .WORD W_FILL +C_ERASE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_FILL ; Fill with byte n bytes from addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BLANKS: ; Fill addr & length from stack with [SP] + .BYTE $86,"BLANK",'S'+$80 + .WORD W_ERASE +C_BLANKS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BL ; Leaves ASCII for space on stack + .WORD C_FILL ; Fill with byte n bytes from addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_HOLD: + .BYTE $84,"HOL",'D'+$80 + .WORD W_BLANKS +C_HOLD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $FFFF + .WORD C_HLD + .WORD C_PLUSSTORE ; Add n1 to addr + .WORD C_HLD + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CSTORE ; Store byte at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_PAD: + .BYTE $83,"PA",'D'+$80 + .WORD W_HOLD +C_PAD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0044h + .WORD C_PLUS ; n1 + n2 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_WORD: + .BYTE $84,"WOR",'D'+$80 + .WORD W_PAD +C_WORD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0016-$ ; 000Ch + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_BLOCK + .WORD C_BRANCH ; Add following offset to BC + .WORD B0017-$ ; 0006h +B0016: + .WORD C_TIB + .WORD C_FETCH ; Get word from addr on stack +B0017: + .WORD C_TOIN ; Current input buffer offset + .WORD C_FETCH ; Get word from addr on stack + .WORD C_PLUS ; n1 + n2 + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_ENCLOSE + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0022h + .WORD C_BLANKS + .WORD C_TOIN ; Current input buffer offset + .WORD C_PLUSSTORE ; Add n1 to addr + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_MINUS + .WORD C_MOVER ; Move value from data to return stack + .WORD C_RFETCH ; Return stack top to data stack + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_CSTORE ; Store byte at addr + .WORD C_PLUS ; n1 + n2 + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_1PLUS ; 1 plus + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_CMOVE ; Move block + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CONVERT: + .BYTE $87,"CONVER",'T'+$80 + .WORD W_WORD +C_CONVERT: + .WORD E_COLON ; Interpret following word sequence +B001A: + .WORD C_1PLUS ; 1 plus + .WORD C_DUP ; Duplicate top value on stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_BASE ; Put BASE addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_DIGIT ; Convert digit n2 using base n1 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0018-$ ; 002Ch + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_BASE ; Put BASE addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_USTAR + .WORD C_DROP ; Drop top value from stack + .WORD C_ROT ; 3rd value down to top of stack + .WORD C_BASE ; Put BASE addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_USTAR + .WORD C_DPLUS + .WORD C_DPL + .WORD C_FETCH ; Get word from addr on stack + .WORD C_1PLUS ; 1 plus + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0019-$ ; 0008h + .WORD C_1 ; Put 1 on stack + .WORD C_DPL + .WORD C_PLUSSTORE ; Add n1 to addr +B0019: + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_BRANCH ; Add following offset to BC + .WORD B001A-$ ; FF$C6 +B0018: + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_NUMBER: + .BYTE $86,"NUMBE",'R'+$80 + .WORD W_CONVERT +C_NUMBER: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_ZERO ; Put zero on stack + .WORD C_ROT ; 3rd value down to top of stack + .WORD C_DUP ; Duplicate top value on stack + .WORD C_1PLUS ; 1 plus + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 002Dh ; '-' + .WORD C_EQUALS ; Is first chr = '-' + .WORD C_DUP ; Duplicate negative flag + .WORD C_MOVER ; Move value from data to return stack + .WORD C_PLUS ; n1 + n2 + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $FFFF ;-1 +B001C: + .WORD C_DPL + .WORD C_STORE ; Store word at addr + .WORD C_CONVERT + .WORD C_DUP ; Duplicate top value on stack + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_BL ; Leaves ASCII for space on stack + .WORD C_MINUS + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B001B-$ ; 0016h + .WORD C_DUP ; Duplicate top value on stack + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 002Eh ; '.' + .WORD C_MINUS + .WORD C_ZERO ; Put zero on stack + .WORD C_QERROR + .WORD C_ZERO ; Put zero on stack + .WORD C_BRANCH ; Add following offset to BC + .WORD B001C-$ ; FFDCh +B001B: + .WORD C_DROP ; Drop top value from stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B001D-$ ; 0004h + .WORD C_DNEGATE +B001D: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MFIND: + .BYTE $85,"-FIN",'D'+$80 + .WORD W_NUMBER +C_MFIND: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BL ; Leaves ASCII for space on stack + .WORD C_WORD + .WORD C_CONTEXT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_FIND ; Find word & return vector,byte & flag + .WORD C_DUP ; Duplicate top value on stack + .WORD C_0EQUALS ; =0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B001E-$ ; 00$0A + .WORD C_DROP ; Drop top value from stack + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_LATEST ; Push top words NFA + .WORD C_FIND ; Find word & return vector,byte & flag +B001E: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CABORT: + .BYTE $87,"'+$80 + .WORD W_MFIND +C_CABORT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ABORT + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ERROR: + .BYTE $85,"ERRO",'R'+$80 + .WORD W_CABORT +C_ERROR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_WARNING ; Put WARNING addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0LESS ; Less than 0 leaves true + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B001F-$ ; 0004h + .WORD C_CABORT +B001F: + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_COUNT ; Convert string at addr to addr + length + .WORD C_TYPE ; Output n bytes from addr + .WORD C_CQUOTE ; Output following string + .BYTE S_END7-S_START7 +S_START7: + .BYTE "? " +S_END7: + .WORD C_MESSAGE ; Output message + .WORD C_SPSTORE ; Set initial stack pointer value + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_QUERYDUP + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0020-$ ; 0008h + .WORD C_TOIN ; Current input buffer offset + .WORD C_FETCH ; Get word from addr on stack + .WORD C_SWAP ; Swap top 2 values on stack +B0020: + .WORD C_QUIT + +W_ID: ; Print definition name from name field addr + .BYTE $83,"ID",'.'+$80 + .WORD W_ERROR +C_ID: + .WORD E_COLON ; Interpret following word sequence + .WORD C_COUNT ; Convert string at addr to addr + length + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 001Fh ; Max length is 1Fh + .WORD C_AND ; AND lenght with 1Fh + .WORD C_TYPE ; Output n bytes from addr + .WORD C_SPACE ; Output space + .WORD C_STOP ; Pop BC from return stack (=next) + +C_XXX1: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MFIND ; Find name returns PFA,length,true or false + .WORD C_0BRANCH ; Branch if name not found + .WORD B0021-$ ; 0010h + .WORD C_DROP ; Drop length + .WORD C_NFA ; Convert PFA to NFA + .WORD C_ID ; Print definition name from name field addr + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0004 ; Message 4, name defined twice + .WORD C_MESSAGE ; Output message + .WORD C_SPACE ; Output space +B0021: + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_DUP ; Duplicate top value on stack + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_WIDTH + .WORD C_FETCH ; Get word from addr on stack + .WORD C_MIN + .WORD C_1PLUS ; 1 plus + .WORD C_ALLOT ; Which ever is smallest width or namelength + .WORD C_DUP ; Duplicate top value on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $00A0 + .WORD C_TOGGLE ; XOR (addr) with byte + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_1 ; Put 1 on stack + .WORD C_MINUS + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0080 + .WORD C_TOGGLE ; XOR (addr) with byte + .WORD C_LATEST ; Push top words NFA + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_CURRENT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STORE ; Store word at addr + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_2PLUS ; 2 plus + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CCOMPILE: + .BYTE $89,"[COMPILE",']'+$80 + .WORD W_ID +C_CCOMPILE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MFIND + .WORD C_0EQUALS ; =0 + .WORD C_ZERO ; Put zero on stack + .WORD C_QERROR + .WORD C_DROP ; Drop top value from stack + .WORD C_CFA ; Convert PFA to CFA + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LITERAL: + .BYTE $C7,"LITERA",'L'+$80 + .WORD W_CCOMPILE +C_LITERAL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_STATE ; Push STATE addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0022-$ ; 0008h + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD C_COMMA ; Reserve 2 bytes and save n +B0022: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DLITERAL: + .BYTE $C8,"DLITERA",'L'+$80 + .WORD W_LITERAL +C_DLITERAL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_STATE ; Push STATE addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0023-$ ; 0008h + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_LITERAL + .WORD C_LITERAL +B0023: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QSTACK: + .BYTE $86,"?STAC",'K'+$80 + .WORD W_DLITERAL +C_QSTACK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_S0 ; Push S0 (initial data stack pointer) + .WORD C_FETCH ; Get word from addr on stack + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_ULESS ; IF stack-1 < stack_top leave true flag + .WORD C_1 ; Put 1 on stack + .WORD C_QERROR + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0080 + .WORD C_PLUS ; n1 + n2 + .WORD C_ULESS ; IF stack-1 < stack_top leave true flag + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0007 + .WORD C_QERROR + .WORD C_STOP ; Pop BC from return stack (=next) + +W_INTERPRET: + .BYTE $89,"INTERPRE",'T'+$80 + .WORD W_QSTACK +C_INTERPRET: + .WORD E_COLON ; Interpret following word sequence +B002A: + .WORD C_MFIND ; Find name returns PFA,length,true or false + .WORD C_0BRANCH ; Branch if name not found + .WORD NO_NAME-$ + .WORD C_STATE ; STATE addr on stack + .WORD C_FETCH ; Get STATE + .WORD C_LESSTHAN ; Is it quit compile word ? + .WORD C_0BRANCH ; If so then branch + .WORD B0025-$ ; + .WORD C_CFA ; Convert PFA to CFA + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_BRANCH ; Add following offset to BC + .WORD B0026-$ ; +B0025: + .WORD C_CFA ; Convert PFA to CFA + .WORD C_EXECUTE ; Jump to address on stack +B0026: + .WORD C_QSTACK ; Error message if stack underflow + .WORD C_BRANCH ; Add following offset to BC + .WORD B0027-$ ; +NO_NAME: + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_NUMBER ; Convert string at addr to double + .WORD C_DPL ; + .WORD C_FETCH ; Get word from addr on stack + .WORD C_1PLUS ; 1 plus + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0028-$ ; + .WORD C_DLITERAL + .WORD C_BRANCH ; Add following offset to BC + .WORD B0029-$ ; +B0028: + .WORD C_DROP ; Drop top value from stack + .WORD C_LITERAL +B0029: + .WORD C_QSTACK ; Error message if stack underflow +B0027: + .WORD C_BRANCH ; Add following offset to BC + .WORD B002A-$ ; FF$C2 + +W_IMMEDIATE: + .BYTE $89,"IMMEDIAT",'E'+$80 + .WORD W_INTERPRET +C_IMMEDIATE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LATEST ; Push top words NFA + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0040 + .WORD C_TOGGLE ; XOR (addr) with byte + .WORD C_STOP ; Pop BC from return stack (=next) + +W_VOCABULARY: + .BYTE 8Ah,"VOCABULAR",'Y'+$80 + .WORD W_IMMEDIATE +C_VOCABULARY: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CREATE + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $A081 + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_CURRENT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CFA ; Convert PFA to CFA + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_VOC_LINK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_VOC_LINK + .WORD C_STORE ; Store word at addr + .WORD C_DOES + .WORD C_2PLUS ; 2 plus + .WORD C_CONTEXT + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +C_LINK: + .WORD C_2PLUS ; 2 plus + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CONTEXT + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_FORTH: + .BYTE $C5,"FORT",'H'+$80 + .WORD W_VOCABULARY +C_FORTH: + .WORD X_DOES + .WORD C_LINK + + .BYTE $81,' '+$80 + .WORD FLAST+2 +E_FORTH: + .WORD $0000 + +W_DEFINITIONS: ; Set CURRENT as CONTEXT vocabulary + .BYTE 8Bh,"DEFINITION",'S'+$80 + .WORD W_FORTH +C_DEFINITIONS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CONTEXT ; Get CONTEXT addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CURRENT ; Get CURRENT addr + .WORD C_STORE ; Set CURRENT as the context vocabulary + .WORD C_STOP ; Pop BC from return stack (=next) + +W_OPENBRKT: + .BYTE $C1,'('+$80 + .WORD W_DEFINITIONS +C_OPENBRKT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0029 + .WORD C_WORD + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) +;--------------------------------------------------------------------------------------- +; This it the last thing ever executed and is the interpreter +; outer loop. This NEVER quits. +;--------------------------------------------------------------------------------------- +W_QUIT: .BYTE $84,"QUI",'T'+$80 + .WORD W_OPENBRKT +C_QUIT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_BLK ; Get current BLK pointer + .WORD C_STORE ; Set BLK to 0 + .WORD C_LEFTBRKT ; Set STATE to execute +B002C: + .WORD C_RPSTORE ; Set initial return stack pointer + .WORD C_CR ; Output [CR][LF] + .WORD C_QUERY ; Get string from input, ends in CR + .WORD C_INTERPRET ; Interpret input stream + .WORD C_STATE ; Push STATE addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0EQUALS ; =0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD S_END8-$ ; 0007h + .WORD C_CQUOTE ; Output following string + .BYTE S_END8-S_START8 +S_START8: + .BYTE "OK" +S_END8: + .WORD C_BRANCH ; Add following offset to BC + .WORD B002C-$ ; FFE7h + +W_ABORT: + .BYTE $85,"ABOR",'T'+$80 + .WORD W_QUIT +C_ABORT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UABORT ; Put UABORT on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_EXECUTE ; Jump to address on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +CF_UABORT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SPSTORE ; Set initial stack pointer value + .WORD C_DECIMAL ; Sets decimal mode + .WORD C_QSTACK ; Error message if stack underflow + .WORD C_CR ; Output [CR][LF] + .WORD C_CQUOTE ; Output following string + .BYTE S_END1-S_START1 ; String length +S_START1: + .BYTE "* Z80 FORTH *" +S_END1: + .WORD C_FORTH + .WORD C_DEFINITIONS ; Set CURRENT as CONTEXT vocabulary + .WORD C_QUIT + +W_WARM: + .BYTE $84,"WAR",'M'+$80 + .WORD W_ABORT +C_WARM: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD WORD1 ; Start of detault table + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD S0 ; S0 addr + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD START_TABLE-WORD1 ; (000Ch) Table length + .WORD C_CMOVE ; Move block + .WORD C_ABORT + +X_COLD: + LD HL,START_TABLE ; Copy table to ram + LD DE,FLAST ; Where the table's going + LD BC,NEXTS2-START_TABLE ; Bytes to copy + LDIR ; + LD HL,W_TASK ; Copy TASK to ram + LD DE,VOCAB_BASE ; Where it's going + LD BC,W_TASKEND-W_TASK ; Bytes to copy + LDIR ; + LD BC,FIRSTWORD ; BC to first forth word + LD HL,(WORD1) ; Get stack pointer + LD SP,HL ; Set it + JP NEXT + +FIRSTWORD: + .WORD C_COLD + +W_COLD: .BYTE $84,"COL",'D'+$80 + .WORD W_WARM + .WORD X_COLD +C_COLD: .WORD E_COLON ; Interpret following word sequence + .WORD C_EBUFFERS ; Clear pseudo disk buffer + .WORD C_ZERO ; Put zero on stack + .WORD C_OFFSET ; Put disk block offset on stack + .WORD C_STORE ; Clear disk block offset + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD WORD1 ; Start of default table + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD S0 ; S0 addr + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD START_TABLE-WORD1 ; Block length on stack (0010h) + .WORD C_CMOVE ; Move block + .WORD C_ABORT + +W_SINGTODUB: ; Change single number to double + .BYTE $84,"S->",'D'+$80 + .WORD W_COLD +C_SINGTODUB: + .WORD 2+$ ; Vector to code + POP DE ; Get number + LD HL,$0000 ; Assume +ve extend + LD A,D ; Check sign + AND $80 ; + JR Z,IS_POS ; Really +ve so jump + DEC HL ; Make -ve extension +IS_POS: + JP NEXTS2 ; Save both & NEXT + +W_PLUSMINUS: + .BYTE $82,"+",'-'+$80 + .WORD W_SINGTODUB +C_PLUSMINUS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_0LESS ; Less than 0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B002D-$ ; 0004h + .WORD C_NEGATE ; Form 2s complement of n +B002D: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DPLUSMINUS: ; Add sign of n to double + .BYTE $83,"D+",'-'+$80 + .WORD W_PLUSMINUS +C_DPLUSMINUS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_0LESS ; Less than 0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B002E-$ ; 0004h + .WORD C_DNEGATE +B002E: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ABS: + .BYTE $83,"AB",'S'+$80 + .WORD W_DPLUSMINUS +C_ABS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate top value on stack + .WORD C_PLUSMINUS + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DABS: + .BYTE $84,"DAB",'S'+$80 + .WORD W_ABS +C_DABS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate top value on stack + .WORD C_DPLUSMINUS ; Add sign of n to double + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MIN: + .BYTE $83,"MI",'N'+$80 + .WORD W_DABS +C_MIN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_2DUP ; Dup top 2 values on stack + .WORD C_GREATER + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B002F-$ ; 0004h + .WORD C_SWAP ; Swap top 2 values on stack +B002F: + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MAX: + .BYTE $83,"MA",'X'+$80 + .WORD W_MIN +C_MAX: + .WORD E_COLON ; Interpret following word sequence + .WORD C_2DUP ; Dup top 2 values on stack + .WORD C_LESSTHAN + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0030-$ ; 0004h + .WORD C_SWAP ; Swap top 2 values on stack +B0030: + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MTIMES: + .BYTE $82,"M",'*'+$80 + .WORD W_MAX +C_MTIMES: + .WORD E_COLON ; Interpret following word sequence + .WORD C_2DUP ; Dup top 2 values on stack + .WORD C_XOR ; Works out sign of result + .WORD C_MOVER ; Move value from data to return stack + .WORD C_ABS + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_ABS + .WORD C_USTAR + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_DPLUSMINUS ; Add sign of n to double + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MDIV: + .BYTE $82,"M",'/'+$80 + .WORD W_MTIMES +C_MDIV: + .WORD E_COLON ; Interpret following word sequence + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_DABS + .WORD C_RFETCH ; Return stack top to data stack + .WORD C_ABS + .WORD C_UMOD ; Unsigned divide & MOD + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_RFETCH ; Return stack top to data stack + .WORD C_XOR ; XOR + .WORD C_PLUSMINUS + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_PLUSMINUS + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TIMES: + .BYTE $81,'*'+$80 + .WORD W_MDIV +C_TIMES: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MTIMES + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DIVMOD: + .BYTE $84,"/MO",'D'+$80 + .WORD W_TIMES +C_DIVMOD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_SINGTODUB ; Change single number to double + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_MDIV + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DIV: + .BYTE $81,'/'+$80 + .WORD W_DIVMOD +C_DIV: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DIVMOD + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MOD: + .BYTE $83,"MO",'D'+$80 + .WORD W_DIV +C_MOD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DIVMOD + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TIMESDIVMOD: + .BYTE $85,"*/MO",'D'+$80 + .WORD W_MOD +C_TIMESDIVMOD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_MTIMES + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_MDIV + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TIMESDIV: + .BYTE $82,"*",'/'+$80 + .WORD W_TIMESDIVMOD +C_TIMESDIV: + .WORD E_COLON ; Interpret following word sequence + .WORD C_TIMESDIVMOD + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MDIVMOD: + .BYTE $85,"M/MO",'D'+$80 + .WORD W_TIMESDIV +C_MDIVMOD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_ZERO ; Put zero on stack + .WORD C_RFETCH ; Return stack top to data stack + .WORD C_UMOD ; Unsigned divide & MOD + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_UMOD ; Unsigned divide & MOD + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CLINE: + .BYTE $86,"'+$80 + .WORD W_MDIVMOD +C_CLINE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_CL ; Put characters/line on stack + .WORD C_BBUF ; Put bytes per block on stack + .WORD C_TIMESDIVMOD + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_BSCR ; Number of buffers per block on stack + .WORD C_TIMES + .WORD C_PLUS ; n1 + n2 + .WORD C_BLOCK + .WORD C_PLUS ; n1 + n2 + .WORD C_CL ; Put characters/line on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DOTLINE: + .BYTE $85,".LIN",'E'+$80 + .WORD W_CLINE +C_DOTLINE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CLINE + .WORD C_TRAILING + .WORD C_TYPE ; Output n bytes from addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MESSAGE: + .BYTE $87,"MESSAG",'E'+$80 + .WORD W_DOTLINE +C_MESSAGE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_WARNING ; Put WARNING addr on stack + .WORD C_FETCH ; Get WARNING value + .WORD C_0BRANCH ; If WARNING = 0 output MSG # n + .WORD B0031-$ ; 001Eh + .WORD C_QUERYDUP + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0032-$ ; 0014h + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0004 + .WORD C_OFFSET ; Put disk block offset on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_BSCR ; Number of buffers per block on stack + .WORD C_DIV + .WORD C_MINUS + .WORD C_DOTLINE ; Output line from screen + .WORD C_SPACE ; Output space + +B0032: .WORD C_BRANCH ; Add following offset to BC + .WORD B0033-$ ; 00$0D + +B0031: .WORD C_CQUOTE ; Output following string + .BYTE S_END2-S_START2 +S_START2: .BYTE "MSG # " +S_END2: .WORD C_DOT +B0033: .WORD C_STOP ; Pop BC from return stack (=next) + +W_PORTIN: ; Fetch data from port + .BYTE $82,"P",'@'+$80 + .WORD W_MESSAGE +C_PORTIN: + .WORD 2+$ ; Vector to code + POP DE ; Get port addr + LD HL,PAT+1 ; Save in port in code + LD (HL),E ; + CALL PAT ; Call port in routine + LD L,A ; Save result + LD H,$00 ; + JP NEXTS1 ; Save & NEXT + +W_PORTOUT: ; Save data to port + .BYTE $82,"P",'!'+$80 + .WORD W_PORTIN +C_PORTOUT: + .WORD 2+$ ; Vector to code + POP DE ; Get port addr + LD HL,PST+1 ; Save in port out code + LD (HL),E ; + POP HL ; + LD A,L ; Byte to A + CALL PST ; Call port out routine + JP NEXT + +W_USE: .BYTE $83,"US",'E'+$80 + .WORD W_PORTOUT +C_USE: .WORD X_USER ; Put next word on stack then do next + .WORD USE-SYSTEM + +W_PREV: .BYTE $84,"PRE",'V'+$80 + .WORD W_USE +C_PREV: .WORD X_USER ; Put next word on stack then do next + .WORD PREV-SYSTEM + +W_PLUSBUF: + .BYTE $84,"+BU",'F'+$80 + .WORD W_PREV +C_PLUSBUF: + .WORD NEXT + +W_UPDATE: + .BYTE $86,"UPDAT",'E'+$80 + .WORD W_PLUSBUF +C_UPDATE: + .WORD NEXT + +W_EBUFFERS: ; Clear pseudo disk buffer + .BYTE $8D,"EMPTY-BUFFER",'S'+$80 + .WORD W_UPDATE +C_EBUFFERS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_FIRST ; Start of pseudo disk onto stack + .WORD C_LIMIT ; End of pseudo disk onto stack + .WORD C_OVER ; Start to top of stack + .WORD C_MINUS ; Work out buffer length + .WORD C_ERASE ; Fill addr & length from stack with 0 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BUFFER: + .BYTE $86,"BUFFE",'R'+$80 + .WORD W_EBUFFERS +C_BUFFER: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BLOCK + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BLOCK: ; Put address of block n (+ offset) on stack + .BYTE $85,"BLOC",'K'+$80 + .WORD W_BUFFER +C_BLOCK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD DISK_END/BLOCK_SIZE-DISK_START/BLOCK_SIZE + ; Max number of blocks + .WORD C_MOD ; MOD to max number + .WORD C_OFFSET ; Put address of disk block offset on stack + .WORD C_FETCH ; Get disk block offset + .WORD C_PLUS ; Add offset to block # + .WORD C_BBUF ; Put bytes per block on stack + .WORD C_TIMES ; Bytes times block number + .WORD C_FIRST ; Put address of first block on stack + .WORD C_PLUS ; Add address of first to byte offset + .WORD C_STOP ; Pop BC from return stack (=next) + +W_RW: + .BYTE $83,"R/",'W'+$80 + .WORD W_BLOCK +C_RW: + .WORD E_COLON ; Interpret following word sequence + .WORD C_URW ; + .WORD C_FETCH ; Get word from addr on stack + .WORD C_EXECUTE ; Jump to address on stack + .WORD C_STOP ; Pop BC from return stack (=next) +CF_URW: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DROP ; Drop top value from stack + .WORD C_DROP ; Drop top value from stack + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_FLUSH: + .BYTE $85,"FLUS",'H'+$80 + .WORD W_RW +C_FLUSH: + .WORD E_COLON ; Interpret following word sequence + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DUMP: + .BYTE $84,"DUM",'P'+$80 + .WORD W_FLUSH +C_DUMP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_LDO ; Put start & end loop values on RPP +B0051: + .WORD C_CR ; Output [CR][LF] + .WORD C_DUP ; Duplicate top value on stack + .WORD C_ZERO ; Put zero on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0005h + .WORD C_DDOTR + .WORD C_SPACE ; Output space + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0004h + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_ZERO ; Put zero on stack + .WORD C_LDO ; Put start & end loop values on RPP +B0050: + .WORD C_DUP ; Duplicate top value on stack + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_3 + .WORD C_DOTR + .WORD C_1PLUS ; 1 plus + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD B0050-$ ; FFF4h + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_PLOOP ; Loop + stack & branch if not done + .WORD B0051-$ ; FFD4h + .WORD C_DROP ; Drop top value from stack + .WORD C_CR ; Output [CR][LF] + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LOAD: + .BYTE $84,"LOA",'D'+$80 + .WORD W_DUMP +C_LOAD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BLK ; Get current block number (0 = keyboard) + .WORD C_FETCH ; Get word from addr on stack + .WORD C_MOVER ; Save it for now + .WORD C_TOIN ; Current input buffer offset + .WORD C_FETCH ; Get word from addr on stack + .WORD C_MOVER ; Save it for now + .WORD C_ZERO ; Put zero on stack + .WORD C_TOIN ; Current input buffer offset + .WORD C_STORE ; Set to zero + .WORD C_BSCR ; Number of buffers per block on stack + .WORD C_TIMES ; Multiply block to load by buffers/block + .WORD C_BLK ; Get BLK pointer + .WORD C_STORE ; Make load block current input stream + .WORD C_INTERPRET ; Interpret input stream + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_TOIN ; Current input buffer offset + .WORD C_STORE ; Store word at addr + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_BLK ; Current block + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_NEXTSCREEN: + .BYTE $C3,"--",'>'+$80 + .WORD W_LOAD +C_NEXTSCREEN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QLOADING + .WORD C_ZERO ; Put zero on stack + .WORD C_TOIN ; Current input buffer offset + .WORD C_STORE ; Store word at addr + .WORD C_BSCR ; Number of buffers per block on stack + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_MOD + .WORD C_MINUS + .WORD C_BLK + .WORD C_PLUSSTORE ; Add n1 to addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TICK: + .BYTE $81,$2C+$80 + .WORD W_NEXTSCREEN +C_TICK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MFIND ; Find name returns PFA,length,true or false + .WORD C_0EQUALS ; =0 + .WORD C_ZERO ; Put zero on stack + .WORD C_QERROR + .WORD C_DROP ; Drop top value from stack + .WORD C_LITERAL + .WORD C_STOP ; Pop BC from return stack (=next) + +W_FORGET: + .BYTE $86,"FORGE",'T'+$80 + .WORD W_TICK +C_FORGET: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CURRENT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CONTEXT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_MINUS + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0018h + .WORD C_QERROR + .WORD C_TICK + .WORD C_DUP ; Duplicate top value on stack + .WORD C_FENCE + .WORD C_FETCH ; Get word from addr on stack + .WORD C_LESSTHAN + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0015h + .WORD C_QERROR + .WORD C_DUP ; Duplicate top value on stack + .WORD C_NFA ; Convert PFA to NFA + .WORD C_DP ; Dictionary pointer addr on stack + .WORD C_STORE ; Store word at addr + .WORD C_LFA + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CONTEXT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BACK: + .BYTE $84,"BAC",'K'+$80 + .WORD W_FORGET +C_BACK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_MINUS + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BEGIN: + .BYTE $C5,"BEGI",'N'+$80 + .WORD W_BACK +C_BEGIN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QCOMP ; Error if not in compile mode + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_1 ; Put 1 on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ENDIF: + .BYTE $C5,"ENDI",'F'+$80 + .WORD W_BEGIN +C_ENDIF: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QCOMP ; Error if not in compile mode + .WORD C_2 + .WORD C_QPAIRS + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_MINUS + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_THEN: + .BYTE $C4,"THE",'N'+$80 + .WORD W_ENDIF +C_THEN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ENDIF + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DO: + .BYTE $C2,"D",'O'+$80 + .WORD W_THEN +C_DO: + .WORD E_COLON ; Interpret following word sequence + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_LDO ; Put start & end loop values on RPP + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_3 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LOOP: + .BYTE $C4,"LOO",'P'+$80 + .WORD W_DO +C_LOOP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_3 + .WORD C_QPAIRS + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD C_BACK + .WORD C_STOP ; Pop BC from return stack (=next) + +W_PLUSLOOP: + .BYTE $C5,"+LOO",'P'+$80 + .WORD W_LOOP +C_PLUSLOOP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_3 + .WORD C_QPAIRS + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_PLOOP ; Loop + stack & branch if not done + .WORD C_BACK + .WORD C_STOP ; Pop BC from return stack (=next) + +W_UNTIL: + .BYTE $C5,"UNTI",'L'+$80 + .WORD W_PLUSLOOP +C_UNTIL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_1 ; Put 1 on stack + .WORD C_QPAIRS + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD C_BACK + .WORD C_STOP ; Pop BC from return stack (=next) + +W_END: + .BYTE $C3,"EN",'D'+$80 + .WORD W_UNTIL +C_END: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UNTIL + .WORD C_STOP ; Pop BC from return stack (=next) + +W_AGAIN: + .BYTE $C5,"AGAI",'N'+$80 + .WORD W_END +C_AGAIN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_1 ; Put 1 on stack + .WORD C_QPAIRS + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_BRANCH ; Add following offset to BC + .WORD C_BACK + .WORD C_STOP ; Pop BC from return stack (=next) + +W_REPEAT: + .BYTE $C6,"REPEA",'T'+$80 + .WORD W_AGAIN +C_REPEAT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_AGAIN + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_2 + .WORD C_MINUS + .WORD C_ENDIF + .WORD C_STOP ; Pop BC from return stack (=next) + +W_IF: + .BYTE $C2,"I",'F'+$80 + .WORD W_REPEAT +C_IF: + .WORD E_COLON ; Interpret following word sequence + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_ZERO ; Put zero on stack + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_2 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ELSE: + .BYTE $C4,"ELS",'E'+$80 + .WORD W_IF +C_ELSE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_2 + .WORD C_QPAIRS + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_BRANCH ; Add following offset to BC + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_ZERO ; Put zero on stack + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_2 + .WORD C_ENDIF + .WORD C_2 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_WHILE: .BYTE $C5,"WHIL",'E'+$80 + .WORD W_ELSE +C_WHILE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_IF + .WORD C_2PLUS ; 2 plus + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SPACES: + .BYTE $86,"SPACE",'S'+$80 + .WORD W_WHILE +C_SPACES: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_MAX + .WORD C_QUERYDUP + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0034-$ ; 000Ch + .WORD C_ZERO ; Put zero on stack + .WORD C_LDO ; Put start & end loop values on RPP +B0035: .WORD C_SPACE ; Output space + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD B0035-$ ; FFFCh +B0034: .WORD C_STOP ; Pop BC from return stack (=next) + +W_LESSHARP: + .BYTE $82,"<",'#'+$80 + .WORD W_SPACES +C_LESSHARP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_PAD ; Save intermediate string address + .WORD C_HLD + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SHARPGT: + .BYTE $82,"#",'>'+$80 + .WORD W_LESSHARP +C_SHARPGT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DROP ; Drop top value from stack + .WORD C_DROP ; Drop top value from stack + .WORD C_HLD + .WORD C_FETCH ; Get word from addr on stack + .WORD C_PAD ; Save intermediate string address + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_MINUS + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SIGN: + .BYTE $84,"SIG",'N'+$80 + .WORD W_SHARPGT +C_SIGN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ROT ; 3rd valu down to top of stack + .WORD C_0LESS ; Less than 0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0036-$ ; 0008h + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 002Dh + .WORD C_HOLD +B0036: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SHARP: + .BYTE $81,'#'+$80 + .WORD W_SIGN +C_SHARP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BASE ; Put BASE addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_MDIVMOD + .WORD C_ROT ; 3rd valu down to top of stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0009h + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_LESSTHAN + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0037-$ ; 0008h + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0007h + .WORD C_PLUS ; n1 + n2 +B0037: + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0030 + .WORD C_PLUS ; n1 + n2 + .WORD C_HOLD + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SHARPS: + .BYTE $82,"#",'S'+$80 + .WORD W_SHARP +C_SHARPS: + .WORD E_COLON ; Interpret following word sequence +B0038: + .WORD C_SHARP + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_OR ; OR + .WORD C_0EQUALS ; =0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0038-$ ; FFF4h + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DDOTR: + .BYTE $83,"D.",'R'+$80 + .WORD W_SHARPS +C_DDOTR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_DABS + .WORD C_LESSHARP + .WORD C_SHARPS + .WORD C_SIGN + .WORD C_SHARPGT + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_MINUS + .WORD C_SPACES + .WORD C_TYPE ; Output n bytes from addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DOTR: + .BYTE $82,".",'R'+$80 + .WORD W_DDOTR +C_DOTR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_SINGTODUB ; Change single number to double + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_DDOTR + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DDOT: + .BYTE $82,"D",'.'+$80 + .WORD W_DOTR +C_DDOT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_DDOTR + .WORD C_SPACE ; Output space + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DOT: + .BYTE $81,'.'+$80 + .WORD W_DDOT +C_DOT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SINGTODUB ; Change single number to double + .WORD C_DDOT + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QUESTION: + .BYTE $81,'?'+$80 + .WORD W_DOT +C_QUESTION: + .WORD E_COLON ; Interpret following word sequence + .WORD C_FETCH ; Get word from addr on stack + .WORD C_DOT + .WORD C_STOP ; Pop BC from return stack (=next) + +W_UDOT: ; Output as unsigned value + .BYTE $82,"U",'.'+$80 + .WORD W_QUESTION +C_UDOT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_DDOT ; Output double value + .WORD C_STOP ; Pop BC from return stack (=next) + +W_VLIST: + .BYTE $85,"VLIS",'T'+$80 + .WORD W_UDOT +C_VLIST: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CONTEXT ; Leave vocab pointer on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CR ; Output [CR][LF] +B0039: + .WORD C_DUP ; Duplicate top value on stack + .WORD C_PFA ; Convert NFA to PFA + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_ID ; Print definition name from name field addr + .WORD C_LFA ; Convert param addr to link addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_DUP ; Duplicate top value on stack + .WORD C_0EQUALS ; =0 + .WORD C_TERMINAL ; Check for break key + .WORD C_OR ; OR + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0039-$ ; FFE2h + .WORD C_DROP ; Drop top value from stack + .WORD C_CR ; Output [CR][LF] + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LIST: + .BYTE $84,"LIS",'T'+$80 + .WORD W_VLIST +C_LIST: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BASE ; Put BASE addr on stack + .WORD C_FETCH ; Put current base on stack + .WORD C_SWAP ; Get number of list screen to top + .WORD C_DECIMAL ; Sets decimal mode + .WORD C_CR ; Output [CR][LF] + .WORD C_DUP ; Duplicate top value on stack + .WORD C_SCR ; Set most recently listed + .WORD C_STORE ; Store word at addr + .WORD C_CQUOTE ; Output following string + .BYTE S_END3-S_START3 +S_START3: + .BYTE "SCR # " +S_END3: + .WORD C_DOT ; Output the screen number + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0010 ; 16 lines to do + .WORD C_ZERO ; From 0 to 15 + .WORD C_LDO ; Put start & end loop values on RPP +DO_LINE: + .WORD C_CR ; Output [CR][LF] + .WORD C_I ; Line number onto data stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0003 ; Fromat right justified 3 characters + .WORD C_DOTR ; Output formatted + .WORD C_SPACE ; Output space + .WORD C_I ; Line number onto data stack + .WORD C_SCR ; Get screen number + .WORD C_FETCH ; Get word from addr on stack + .WORD C_DOTLINE ; Output line from screen + .WORD C_TERMINAL ; Check for break key + .WORD C_0BRANCH ; Jump if no break key + .WORD NO_BRK-$ + .WORD C_LEAVE ; Else set loop index to limit (quit loop) +NO_BRK: + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD DO_LINE-$ + .WORD C_CR ; Output [CR][LF] + .WORD C_BASE ; Put BASE addr on stack + .WORD C_STORE ; Restore original base + .WORD C_STOP ; Pop BC from return stack (=next) + +W_INDEX: + .BYTE $85,"INDE",'X'+$80 + .WORD W_LIST +C_INDEX: + .WORD E_COLON ; Interpret following word sequence + .WORD C_1PLUS ; 1 plus + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_LDO ; Put start & end loop values on RPP +B003D: + .WORD C_CR ; Output [CR][LF] + .WORD C_I ; Copy LOOP index to data stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0003h + .WORD C_DOTR + .WORD C_SPACE ; Output space + .WORD C_ZERO ; Put zero on stack + .WORD C_I ; Copy LOOP index to data stack + .WORD C_DOTLINE ; Output line from screen + .WORD C_TERMINAL ; Check for break key + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B003C-$ ; 0004h + .WORD C_LEAVE ; Quit loop by making index = limit +B003C: + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD B003D-$ ; FFE4h + .WORD C_CR ; Output [CR][LF] + .WORD C_STOP ; Pop BC from return stack (=next) + +W_INT: + .BYTE $C4,"; IN",'T'+$80 + .WORD W_INDEX +C_INT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_WHATSTACK ; Check stack pointer, error if not ok + .WORD C_COMPILE ; Compile next word into dictionary + .WORD X_INT + .WORD C_LEFTBRKT ; Set STATE to execute + .WORD C_SMUDGE + .WORD C_STOP ; Pop BC from return stack (=next) + +X_INT: + .WORD 2+$ ; Vector to code + LD HL,INTFLAG + RES 6,(HL) + EI + JP X_STOP + +W_INTFLAG: + .BYTE $87,"INTFLA",'G'+$80 + .WORD W_INT +C_INTFLAG: + .WORD X_USER ; Put next word on stack then do next + .WORD INTFLAG-SYSTEM + +W_INTVECT: + .BYTE $87,"INTVEC",'T'+$80 + .WORD W_INTFLAG +C_INTVECT: + .WORD X_USER ; Put next word on stack then do next + .WORD INTVECT-SYSTEM + +W_CPU: + .BYTE $84,".CP",'U'+$80 + .WORD W_INTVECT +C_CPU: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CQUOTE ; Output following string + .BYTE S_END4-S_START4 +S_START4: + .BYTE "Z80 " +S_END4: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_2SWAP: + .BYTE $85,"2SWA",'P'+$80 + .WORD W_CPU +C_2SWAP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ROT ; 3rd valu down to top of stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_ROT ; 3rd valu down to top of stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_2OVER: + .BYTE $85,"2OVE",'R'+$80 + .WORD W_2SWAP +C_2OVER: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_2DUP ; Dup top 2 values on stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_2SWAP + .WORD C_STOP ; Pop BC from return stack (=next) + +W_EXIT: + .BYTE $84,"EXI",'T'+$80 + .WORD W_2OVER +C_EXIT: + .WORD X_STOP + +W_J: ; Push outer loop value on stack + .BYTE $81,'J'+$80 + .WORD W_EXIT +C_J: + .WORD 2+$ ; Vector to code + LD HL,(RPP) ; Get return stack pointer + INC HL ; Skip inner loop values + INC HL ; + INC HL ; + INC HL ; + JP X_I2 + +W_ROLL: + .BYTE $84,"ROL",'L'+$80 + .WORD W_J +C_ROLL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate top value on stack + .WORD C_ZERO ; Put zero on stack + .WORD C_GREATER + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B003E-$ ; 002Ch + .WORD C_DUP ; Duplicate top value on stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_PICK + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_ZERO ; Put zero on stack + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_LDO ; Put start & end loop values on RPP +B003F: + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_I ; Copy LOOP index to data stack + .WORD C_DUP ; Duplicate top value on stack + .WORD C_PLUS ; n1 + n2 + .WORD C_PLUS ; n1 + n2 + .WORD C_DUP ; Duplicate top value on stack + .WORD C_2MINUS ; 2 minus + .WORD C_FETCH ; Get word from addr on stack + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_STORE ; Store word at addr + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $FFFF + .WORD C_PLOOP ; Loop + stack & branch if not done + .WORD B003F-$ ; FFE6h +B003E: + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DEPTH: + .BYTE $85,"DEPT",'H'+$80 + .WORD W_ROLL +C_DEPTH: + .WORD E_COLON ; Interpret following word sequence + .WORD C_S0 ; Push S0 (initial data stack pointer) + .WORD C_FETCH ; Get word from addr on stack + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_MINUS + .WORD C_2 + .WORD C_DIV + .WORD C_1MINUS ; 1 minus + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DLESSTHAN: + .BYTE $82,"D",'<'+$80 + .WORD W_DEPTH +C_DLESSTHAN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ROT ; 3rd valu down to top of stack + .WORD C_2DUP ; Dup top 2 values on stack + .WORD C_EQUALS + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0040-$ ; 00$0A + .WORD C_2DROP ; Drop top two values from stack + .WORD C_ULESS ; IF stack-1 < stack_top leave true flag + .WORD C_BRANCH ; Add following offset to BC + .WORD B0041-$ ; 0008h +B0040: + .WORD C_2SWAP + .WORD C_2DROP ; Drop top two values from stack + .WORD C_GREATER +B0041: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_0GREATER: + .BYTE $82,"0",'>'+$80 + .WORD W_DLESSTHAN +C_0GREATER: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_GREATER + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DOTS: + .BYTE $82,".",'S'+$80 + .WORD W_0GREATER +C_DOTS + .WORD E_COLON ; Interpret following word sequence + .WORD C_CR ; Output [CR][LF] + .WORD C_DEPTH + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0042-$ ; 0020h + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_2MINUS ; 2 minus + .WORD C_S0 ; Push S0 (initial data stack pointer) + .WORD C_FETCH ; Get word from addr on stack + .WORD C_2MINUS ; 2 minus + .WORD C_LDO ; Put start & end loop values on RPP +B0043: + .WORD C_I ; Copy LOOP index to data stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_DOT + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $FFFE + .WORD C_PLOOP ; Loop + stack & branch if not done + .WORD B0043-$ ; FFF4h + .WORD C_BRANCH ; Add following offset to BC + .WORD S_END5-$ ; 0011h +B0042: + .WORD C_CQUOTE ; Output following string + .BYTE S_END5-S_START5 +S_START5: + .BYTE "STACK EMPTY " +S_END5: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CODE: + .BYTE $84,"COD",'E'+$80 + .WORD W_DOTS +C_CODE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QEXEC ; Error not if not in execute mode + .WORD C_XXX1 + .WORD C_SPSTORE ; Set initial stack pointer value + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ENDCODE: + .BYTE $88,"END-COD",'E'+$80 + .WORD W_CODE +C_ENDCODE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CURRENT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CONTEXT + .WORD C_STORE ; Store word at addr + .WORD C_QEXEC ; Error not if not in execute mode + .WORD C_WHATSTACK ; Check stack pointer, error if not ok + .WORD C_SMUDGE + .WORD C_STOP ; Pop BC from return stack (=next) + +W_NEXT: + .BYTE $C4,"NEX",'T'+$80 + .WORD W_ENDCODE +C_NEXT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $00C3 ; Jump instruction + .WORD C_CCOMMA ; Save as 8 bit value + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD NEXT ; The address of NEXT + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_STOP ; Pop BC from return stack (=next) + +W_IM2: ; Set interrupt mode 2 + .BYTE $83,"IM",'2'+$80 + .WORD W_NEXT +C_IM2: + .WORD 2+$ ; Vector to code + IM 2 ; Mode 2 + JP NEXT + +W_IM1: ; Set interrupt mode 1 + .BYTE $83,"IM",'1'+$80 + .WORD W_IM2 +C_IM1: + .WORD 2+$ ; Vector to code + IM 1 ; Mode 1 + JP NEXT + +W_IM0: ; Set interrupt mode 0 + .BYTE $83,"IM",'0'+$80 + .WORD W_IM1 +C_IM0: + .WORD 2+$ ; Vector to code + IM 0 ; Mode 0 + JP NEXT + +W_DI: ; Disable interrupt + .BYTE $82,"D",'I'+$80 + .WORD W_IM0 +C_DI: + .WORD 2+$ ; Vector to code + DI ; Disable interrupt + JP NEXT + +W_EI: ; Enable interrupt + .BYTE $82,"E",'I'+$80 + .WORD W_DI +C_EI: + .WORD 2+$ ; Vector to code + EI ; Enable interrupt + JP NEXT + +W_MON: ; Jump to m/c monitor + .BYTE $83,"MO",'N'+$80 + .WORD W_EI +C_MON: + .WORD 2+$ + JP MONSTART + +W_LLOAD: + .BYTE $85,"LLOA",'D'+$80 + .WORD W_MON +C_LLOAD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BLOCK ; Get block address + .WORD C_LIT ; Enter loop with null + .WORD $0000 ; +LL_BEGIN: + .WORD C_DUP ; Dup key + .WORD C_0BRANCH ; If null then don't store + .WORD LL_NULL-$ + .WORD C_DUP ; Dup key again + .WORD C_LIT ; Compare to [CR] + .WORD $000D ; + .WORD C_EQUALS + .WORD C_0BRANCH ; If not [CR] then jump + .WORD LL_STORE-$ ; + .WORD C_DROP ; Drop the [CR] + .WORD C_CL ; Get characters per line + .WORD C_PLUS ; Add to current addr + .WORD C_CL ; Make CL MOD value + .WORD C_NEGATE ; Form 2s complement of n + .WORD C_AND ; Mask out bits + .WORD C_BRANCH ; Done this bit so jump + .WORD NO_STORE-$ +LL_STORE: + .WORD C_OVER ; Get address to store at + .WORD C_STORE ; Save chr +NO_STORE: + .WORD C_1PLUS ; Next addres + .WORD C_BRANCH ; Done so jump + .WORD LL_CHAR-$ +LL_NULL: + .WORD C_DROP ; Was null so drop it +LL_CHAR: + .WORD C_KEY ; Get key + .WORD C_DUP ; Duplicate it + .WORD C_LIT ; Compare with [CTRL] Z + .WORD $001A + .WORD C_EQUALS + .WORD C_0BRANCH ; If not EOF then jump + .WORD LL_BEGIN-$ ; + .WORD C_DROP ; Drop EOF character + .WORD C_DROP ; Drop next address + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TASK: + .BYTE $84,"TAS",'K'+$80 + .WORD W_LLOAD +C_TASK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_STOP ; Pop BC from return stack (=next) +W_TASKEND: + +W_EDITI: + +W_CLEAR: ; Clear block n + .BYTE $85,"CLEA",'R'+$80 + .WORD W_TASK +C_CLEAR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate number + .WORD C_SCR ; Get SCR addr + .WORD C_STORE ; Store screen number + .WORD C_BLOCK ; Get the address of the block + .WORD C_BBUF ; Put number of bytes/block on stack + .WORD C_ERASE ; Clear the block + .WORD C_STOP ; Pop BC from return stack (=next) + +CF_UKEY: ; Get key onto stack + .WORD 2+$ ; Vector to code + CALL CHR_RD ; User key in routine + LD L,A ; Put key on stack + LD H,$00 ; + JP NEXTS1 ; Save & NEXT + +CF_UEMIT: ; Chr from stack to output + .WORD 2+$ ; Vector to code + POP HL ; Get CHR to output + LD A,L ; Put in A + PUSH BC ; Save regs + PUSH DE ; + CALL CHR_WR ; User output routine + POP DE ; Restore regs + POP BC ; + JP NEXT ; + +CF_UCR: ; CR output + .WORD 2+$ ; Vector to code + PUSH BC ; Save regs + PUSH DE ; Just in case + LD A,$0D ; Carrage return + CALL CHR_WR ; User output routine + LD A,$0A ; Line feed + CALL CHR_WR ; User output routine + POP DE ; Get regs back + POP BC ; + JP NEXT ; Next + +CF_UQTERMINAL: ; Test for user break + .WORD 2+$ ; Vector to code + PUSH BC ; Save regs + PUSH DE ; Just in case + CALL BREAKKEY ; User break test routine + POP DE ; Get regs back + POP BC ; + LD H,$00 ; Clear H + LD L,A ; Result in L + JP NEXTS1 ; Store it & Next + +;------------------------------------------------------------------------------ +; SERIAL I/O ROUTINES +; Change these to suit your target system ..... +;------------------------------------------------------------------------------ +;------------------------------------------------------------------------------ +; RXA - Receive a byte over SIO/0 Ch A +;------------------------------------------------------------------------------ +RXA CALL CKSIOA ; Get the status word + JR NC,RXA ; Loop until a character arrives + IN A,($74) ; Get the character + RET ; Char ready in A +;------------------------------------------------------------------------------ +; TXA - Transmit a byte over SIO/0 Ch A +;------------------------------------------------------------------------------ +TXA PUSH AF ; Store character + CALL CKSIOA ; See if SIO channel A is finished transmitting + JR Z,TXA+1 ; Loop until SIO flag signals ready + POP AF ; Retrieve character + OUT ($74),A ; Output the character + RET +;------------------------------------------------------------------------------ +; Check SIO Channel A status flag, RX char ready=CY, TX buffer clear=NZ +;------------------------------------------------------------------------------ +CKSIOA XOR A ; Zeroize A + OUT ($76),A ; Select Register 0 + IN A,($76) ; Retrieve Status Word + RRCA ; RX status into CY flag + BIT 1,A ; TX Buffer Empty into Z flag + RET +;------------------------------------------------------------------------------ +CHR_RD: CALL RXA ; GET A CHARACTER + CP $61 ; Is UCASE already? + JR C,CHR_RD1 ; It is, leave it alone + CP $7A ; <= "z" ? + JR NC,CHR_RD1 ; + AND $5F ; It's A-Z, or a-z make it upper case +CHR_RD1 RET + +NO_BUF_KEY: + JP RXA ; GET A CHARACTER + +BREAKKEY: CALL CKSIOA ; CHECK USART + JR NC,NO_KEY ; NOTHING + IN A,($74) ; READ THE CHARACTER + CP $03 ; BREAK? + JR Z,WAS_BRK ; YES + CP $61 ; Is UCASE already? + JR C,BRK01 ; It is, leave it alone + CP $7A ; <= "z" ? + JR NC,BRK01 + AND $5F ; It's A-Z, or a-z make it upper case +BRK01 RET ; ELSE RETURN WITH KEY + +NO_KEY: XOR A ; Wasn't break, or no key, so clear + RET + +WAS_BRK: LD A,$01 ; Was break so set flag + RET + +CHR_WR: RST 08H ; WRITE CHARACTER + RET +;------------------------------------------------------------------------------ +FINIS .END diff --git a/doug/src/baseline.arf b/doug/src/baseline.arf new file mode 100755 index 00000000..d276c14d --- /dev/null +++ b/doug/src/baseline.arf @@ -0,0 +1,17 @@ +-mjx +-i baseline.ihx +-k /usr/local/share/sdcc/lib/z80 +-l z80 +-b _CCPB03 = 0xD000 +-b _BDOSB01 = 0xD800 +-b _CBIOS = 0xE600 +-b _DBGMON = 0x8000 +crt0.rel +baseline.rel +ns16550.rel +i8255.rel +dbgmon.rel +ccpb03.rel +bdosb01.rel +cbios.rel +-e diff --git a/doug/src/baseline.c b/doug/src/baseline.c new file mode 100755 index 00000000..69260939 --- /dev/null +++ b/doug/src/baseline.c @@ -0,0 +1,68 @@ +/* + * baseline.c - Diagnostic EPROM for the N8VEM SBC V2 + * + */ + +#include +#include +#include +#include "portab.h" +#include "sbcv2.h" +#include "ns16550.h" + +/* #include "cpmbdos.h" */ + +/* THESE ARE USED BY THE LIBRARY ROUTINES */ +char getchar(void) +{ +/* + struct BDOSCALL cread = { C_READ, { (unsigned int)0 } }; + return cpmbdos(&cread); +*/ + return 0; +} +void outchar(char c) +{ + if(c) ; +/* + struct BDOSCALL cwrite = { C_WRITE, { (unsigned int)c } }; + cpmbdos(&cwrite); +*/ +} + + +void xdisable(void) +{ +} + +void xenable(void) +{ +} + +void intmode(U8 xmode) +{ + if(xmode); +} + +int main(void) +{ + pMPCL_ROM = 0x80; + pMPCL_RAM = 0x81; + + memcpy(0,0x0E5,0x2000); + + pMPCL_ROM = 0x80; + pMPCL_RAM = 0x00; + + xdisable(); + intmode(1); + pMPCL_ROM = 0x00; + pMPCL_RAM = 0x00; + + memcpy(RAMTARG_CPM,ROMSTART_CPM,CCPSIZ_CPM); + + pMPCL_ROM = 0x80; + pMPCL_RAM = 0x00; + return (0); +} + diff --git a/doug/src/bdosb01.arf b/doug/src/bdosb01.arf new file mode 100755 index 00000000..7c5391de --- /dev/null +++ b/doug/src/bdosb01.arf @@ -0,0 +1,6 @@ +-mjx +-i bdosb01.ihx +-k /usr/local/share/sdcc/lib/z80 +-l z80 +bdosb01.rel +-e diff --git a/doug/src/bdosb01.lst b/doug/src/bdosb01.lst new file mode 100755 index 00000000..f2388aa7 --- /dev/null +++ b/doug/src/bdosb01.lst @@ -0,0 +1,2675 @@ + 1 .title bdosb01.s derived from bdosb01.asm + 2 .sbttl by Douglas Goodall for N8VEM use '11 + 3 + 4 .module bdosb01 + 5 .optsdcc -mz80 + 6 + 7 ;-------------------------------------------------------- + 8 ; Public variables in this module + 9 ;-------------------------------------------------------- + 10 .globl _bdos + 11 ;-------------------------------------------------------- + 12 ; special function registers + 13 ;-------------------------------------------------------- + 14 ;-------------------------------------------------------- + 15 ; ram data + 16 ;-------------------------------------------------------- + 17 .area _DATA + 18 ;-------------------------------------------------------- + 19 ; overlayable items in ram + 20 ;-------------------------------------------------------- + 21 .area _OVERLAY + 22 ;-------------------------------------------------------- + 23 ; external initialized ram data + 24 ;-------------------------------------------------------- + 25 ;-------------------------------------------------------- + 26 ; global & static initialisations + 27 ;-------------------------------------------------------- + 28 .area _HOME + 29 .area _GSINIT + 30 .area _GSFINAL + 31 .area _GSINIT + 32 ;-------------------------------------------------------- + 33 ; Home + 34 ;-------------------------------------------------------- + 35 .area _HOME + 36 .area _HOME + 37 ;-------------------------------------------------------- + 38 ; code + 39 ;-------------------------------------------------------- + 40 .area _CODE + 41 ;bdos.c:1: void bdos(void) + 42 ; --------------------------------- + 43 ; Function bdos + 44 ; --------------------------------- + 0000 45 _bdos_start:: + 0000 46 _bdos: + 47 + 48 ;dwg-start; + 49 .area _DATA + 50 ;dwg-end; + 51 + 0001 52 ENDFIL = 1 ;FILL FULL BDOS LENGTH + 53 ; + 0003 54 IOBYTE = 3 ; I/O DEFINITION BYTE. + 0004 55 TDRIVE = 4 ; CURRENT DRIVE NAME AND USER NUMBER. + 0005 56 ENTRY = 5 ; ENTRY POINT FOR THE CP/M BDOS. + 005C 57 TFCB = 0x5C ; DEFAULT FILE CONTROL BLOCK. + 0080 58 TBUFF = 0x80 ; I/O BUFFER AND COMMAND LINE STORAGE. + 0100 59 TBASE = 0x100 ; TRANSIANT PROGRAM STORAGE AREA. + 60 ; + 61 ; SET CONTROL CHARACTER .EQUATES. + 62 ; + 0041 63 ASCIIA = 0x41 + 0040 64 AT = 0x40 + 0003 65 CNTRLC = 3 ; CONTROL-C + 0005 66 CNTRLE = 05 ; CONTROL-E + 0008 67 BS = 08 ; BACKSPACE + 0009 68 TAB = 09 ; TAB + 000A 69 LF = 0x0A ; LINE FEED + 000C 70 FF = 0x0C ; FORM FEED + 000D 71 CR = 0x0D ; CARRIAGE RETURN + 0010 72 CNTRLP = 0x10 ; CONTROL-P + 0012 73 CNTRLR = 0x12 ; CONTROL-R + 0013 74 CNTRLS = 0x13 ; CONTROL-S + 0015 75 CNTRLU = 0x15 ; CONTROL-U + 0018 76 CNTRLX = 0x18 ; CONTROL-X + 001A 77 CNTRLZ = 0x1A ; CONTROL-Z (END-OF-FILE MARK) + 0020 78 SPACE = 0x20 + 0023 79 POUND = 0x23 + 0024 80 DOLLAR = 0x24 + 003F 81 QUESTION = 0x3f + 005E 82 UP = 0x5E + 007F 83 DEL = 0x7F ; RUBOUT + 84 + 85 ; CPM ORIGIN CALCULATE + 86 + 003B 87 NK = 59 ;SYSTEM SIZE + 9C00 88 BASE = (NK*1024)-0x5000 + D000 89 CCPO = BASE+0x3400 ;CCP ORIGIN + D800 90 BDOSO = BASE+0x3C00 ;BDOS ORIGIN + E600 91 BIOSO = BASE+0x4A00 ;BIOS ORIGIN + 92 + 93 ;dwg-begin; + 94 + 95 ; .area _CODE + 96 .area _BDOSB01 + 97 + 98 ;dwg-end; + 99 + 100 ;dwg; .ORG BDOSO + 0000 00 00 00 00 00 00 101 .DB 0,0,0,0,0,0 ;OLD SERIAL NUMBER + 102 ; + 103 ;************************************************************** + 104 ;* + 105 ;* B D O S E N T R Y + 106 ;* + 107 ;************************************************************** + 108 ; + 0006 C3r11s00 109 FBASE: JP FBASE1 + 110 ; + 111 ; BDOS ERROR TABLE. + 112 ; + 0009r99s00 113 BADSCTR:.DW ERROR1 ; BAD SECTOR ON READ OR WRITE. + 000BrA5s00 114 BADSLCT:.DW ERROR2 ; BAD DISK SELECT. + 000DrABs00 115 RODISK: .DW ERROR3 ; DISK IS READ ONLY. + 000FrB1s00 116 ROFILE: .DW ERROR4 ; FILE IS READ ONLY. + 117 ; + 118 ; ENTRY INTO BDOS. (DE) OR (E) ARE THE PARAMETERS PASSED. THE + 119 ; FUNCTION NUMBER DESIRED IS IN REGISTER (C). + 120 ; E contains drive number if passing this + 0011 EB 121 FBASE1: EX DE,HL ; SAVE THE (DE) PARAMETERS. + 0012 22r43s03 122 LD (PARAMS),HL + 0015 EB 123 EX DE,HL + 0016 7B 124 LD A,E ; AND SAVE REGISTER (E) IN PARTICULAR. + 0017 32rD6s0D 125 LD (EPARAM),A + 001A 21 00 00 126 LD HL,#0 + 001D 22r45s03 127 LD (STATUS),HL ; CLEAR RETURN STATUS. + 0020 39 128 ADD HL,SP + 0021 22r0Fs03 129 LD (USRSTACK),HL ; SAVE USERS STACK POINTER. + 0024 31r41s03 130 LD SP,#STKAREA ; AND SET OUR OWN. + 0027 AF 131 XOR A ; CLEAR AUTO SELECT STORAGE SPACE. + 0028 32rE0s0D 132 LD (AUTOFLAG),A + 002B 32rDEs0D 133 LD (AUTO),A + 002E 21r74s0D 134 LD HL,#GOBACK ; SET RETURN ADDRESS. + 0031 E5 135 PUSH HL + 0032 79 136 LD A,C ; GET FUNCTION NUMBER. + 0033 FE 29 137 CP #NFUNCTS ; VALID FUNCTION NUMBER? + 0035 D0 138 RET NC + 0036 4B 139 LD C,E ; KEEP SINGLE REGISTER FUNCTION HERE. + 0037 21r47s00 140 LD HL,#FUNCTNS ; NOW LOOK THRU THE FUNCTION TABLE. + 003A 5F 141 LD E,A + 003B 16 00 142 LD D,#0 ; (DE)=FUNCTION NUMBER. + 003D 19 143 ADD HL,DE + 003E 19 144 ADD HL,DE ; (HL)=(START OF TABLE)+2*(FUNCTION NUMBER). + 003F 5E 145 LD E,(HL) + 0040 23 146 INC HL + 0041 56 147 LD D,(HL) ; NOW (DE)=ADDRESS FOR THIS FUNCTION. + 0042 2Ar43s03 148 LD HL,(PARAMS) ; RETRIEVE PARAMETERS. + 0045 EB 149 EX DE,HL ; NOW (DE) HAS THE ORIGINAL PARAMETERS. + 0046 E9 150 JP (HL) ; EXECUTE DESIRED FUNCTION. + 151 ; + 152 ; BDOS FUNCTION JUMP TABLE. + 153 ; + 0029 154 NFUNCTS = 41 ; NUMBER OF FUNCTIONS IN FOLLOWIN TABLE. + 155 ; + 0047 03 E6rC8s02r90s01 156 FUNCTNS:.DW WBOOT,GETCON,OUTCON,GETRDR,PUNCH,LIST,DIRCIO,GETIOB + rCEs02 12 E6 0F E6 + rD4s02rEDs02 + 0057rF3s02rF8s02rE1s01 157 .DW SETIOB,PRTSTR,R.DBUFF,GETCSTS,GETVER,RSTDSK,SETDSK,OPENFIL + rFEs02r7Es0Cr83s0C + r45s0Cr9Cs0C + 0067rA5s0CrABs0CrC8s0C 158 .DW CLOSEFIL,GETFST,GETNXT,DELFILE,READSEQ,WRTSEQ,FCREATE + rD7s0CrE0s0CrE6s0C + rECs0C + 0075rF5s0CrFEs0Cr04s0D 159 .DW RENFILE,GETLOG,GETCRNT,PUTDMA,GETALOC,WRTPRTD,GETROV,SETATTR + r0As0Dr11s0Dr2Cs05 + r17s0Dr1Ds0D + 0085r26s0Dr2Ds0Dr41s0D 160 .DW GETPARM,GETUSER,RDRANDOM,WTRANDOM,FILESIZE,SETRAN,LOGOFF,RTN + r47s0Dr4Ds0Dr0Es0C + r53s0Dr04s03 + 0095r04s03r9Bs0D 161 .DW RTN,WTSPECL + 162 ; + 163 ; BDOS ERROR MESSAGE SECTION. + 164 ; + 0099 21rCAs00 165 ERROR1: LD HL,#BADSEC ; BAD SECTOR MESSAGE. + 009C CDrE5s00 166 CALL PRTERR ; PRINT IT AND GET A 1 CHAR RESPONCE. + 009F FE 03 167 CP #CNTRLC ; RE-BOOT R.EQUEST (CONTROL-C)? + 00A1 CA 00 00 168 JP Z,0 ; YES. + 00A4 C9 169 RET ; NO, RETURN TO RETRY I/O FUNCTION. + 170 ; + 00A5 21rD5s00 171 ERROR2: LD HL,#BADSEL ; BAD DRIVE SELECTED. + 00A8 C3rB4s00 172 JP ERROR5 + 173 ; + 00AB 21rE1s00 174 ERROR3: LD HL,#DISKRO ; DISK IS READ ONLY. + 00AE C3rB4s00 175 JP ERROR5 + 176 ; + 00B1 21rDCs00 177 ERROR4: LD HL,#FILERO ; FILE IS READ ONLY. + 178 ; + 00B4 CDrE5s00 179 ERROR5: CALL PRTERR + 00B7 C3 00 00 180 JP 0 ; ALWAYS REBOOT ON THESE ERRORS. + 181 ; + 00BA 42 44 4F 53 20 45 182 BDOSERR: .ascii "BDOS ERR ON " + 52 52 20 4F 4E 20 + 00C6 20 3A 20 24 183 BDOSDRV: .ascii " : $" + 00CA 42 41 44 20 53 45 184 BADSEC: .ascii "BAD SECTOR$" + 43 54 4F 52 24 + 00D5 53 45 4C 45 43 54 185 BADSEL: .ascii "SELECT$" + 24 + 00DC 46 49 4C 45 20 186 FILERO: .ascii "FILE " + 00E1 52 2F 4F 24 187 DISKRO: .ascii "R/O$" + 188 ; + 189 ; PRINT BDOS ERROR MESSAGE. + 190 ; + 00E5 E5 191 PRTERR: PUSH HL ; SAVE SECOND MESSAGE POINTER. + 00E6 CDrC9s01 192 CALL OUTCRLF ; SEND (CR)(LF). + 00E9 3Ar42s03 193 LD A,(ACTIVE) ; GET ACTIVE DRIVE. + 00EC C6 41 194 ADD A,#ASCIIA ; MAKE ASCII. + 00EE 32rC6s00 195 LD (BDOSDRV),A ; AND PUT IN MESSAGE. + 00F1 01rBAs00 196 LD BC,#BDOSERR ; AND PRINT IT. + 00F4 CDrD3s01 197 CALL PRTMESG + 00F7 C1 198 POP BC ; PRINT SECOND MESSAGE LINE NOW. + 00F8 CDrD3s01 199 CALL PRTMESG + 200 ; + 201 ; GET AN INPUT CHARACTER. WE WILL CHECK OUR 1 CHARACTER + 202 ; BUFFER FIRST. THIS MAY BE SET BY THE CONSOLE STATUS ROUTINE. + 203 ; + 00FB 21r0Es03 204 GETCHAR:LD HL,#CHARBUF ; CHECK CHARACTER BUFFER. + 00FE 7E 205 LD A,(HL) ; ANYTHING PRESENT ALREADY? + 00FF 36 00 206 LD (HL),#0 ; ...EITHER CASE CLEAR IT. + 0101 B7 207 OR A + 0102 C0 208 RET NZ ; YES, USE IT. + 0103 C3 09 E6 209 JP CONIN ; NOPE, GO GET A CHARACTER RESPONCE. + 210 ; + 211 ; INPUT AND ECHO A CHARACTER. + 212 ; + 0106 CDrFBs00 213 GETECHO:CALL GETCHAR ; INPUT A CHARACTER. + 0109 CDr14s01 214 CALL CHKCHAR ; CARRIAGE CONTROL? + 010C D8 215 RET C ; NO, A REGULAR CONTROL CHAR SO DON'T ECHO. + 010D F5 216 PUSH AF ; OK, SAVE CHARACTER NOW. + 010E 4F 217 LD C,A + 010F CDr90s01 218 CALL OUTCON ; AND ECHO IT. + 0112 F1 219 POP AF ; GET CHARACTER AND RETURN. + 0113 C9 220 RET + 221 ; + 222 ; CHECK CHARACTER IN (A). SET THE ZERO FLAG ON A CARRIAGE + 223 ; CONTROL CHARACTER AND THE CARRY FLAG ON ANY OTHER CONTROL + 224 ; CHARACTER. + 225 ; + 0114 FE 0D 226 CHKCHAR:CP #CR ; CHECK FOR CARRIAGE RETURN, LINE FEED, BACKSPACE, + 0116 C8 227 RET Z ; OR A TAB. + 0117 FE 0A 228 CP #LF + 0119 C8 229 RET Z + 011A FE 09 230 CP #TAB + 011C C8 231 RET Z + 011D FE 08 232 CP #BS + 011F C8 233 RET Z + 0120 FE 20 234 CP #SPACE ; OTHER CONTROL CHAR? SET CARRY FLAG. + 0122 C9 235 RET + 236 ; + 237 ; CHECK THE CONSOLE DURING OUTPUT. HALT ON A CONTROL-S, THEN + 238 ; REBOOT ON A CONTROL-C. IF ANYTHING ELSE IS READY, CLEAR THE + 239 ; ZERO FLAG AND RETURN (THE CALLING ROUTINE MAY WANT TO DO + 240 ; SOMETHING). + 241 ; + 0123 242 CKCONSOL: + 0123 3Ar0Es03 243 LD A,(CHARBUF) ; CHECK BUFFER. + 0126 B7 244 OR A ; IF ANYTHING, JUST RETURN WITHOUT CHECKING. + 0127 C2r45s01 245 JP NZ,CKCON2 + 012A CD 06 E6 246 CALL CONST ; NOTHING IN BUFFER. CHECK CONSOLE. + 012D E6 01 247 AND #0x01 ; LOOK AT BIT 0. + 012F C8 248 RET Z ; RETURN IF NOTHING. + 0130 CD 09 E6 249 CALL CONIN ; OK, GET IT. + 0133 FE 13 250 CP #CNTRLS ; IF NOT CONTROL-S, RETURN WITH ZERO CLEARED. + 0135 C2r42s01 251 JP NZ,CKCON1 + 0138 CD 09 E6 252 CALL CONIN ; HALT PROCESSING UNTIL ANOTHER CHAR + 013B FE 03 253 CP #CNTRLC ; IS TYPED. CONTROL-C? + 013D CA 00 00 254 JP Z,0 ; YES, REBOOT NOW. + 0140 AF 255 XOR A ; NO, JUST PRETEND NOTHING WAS EVER READY. + 0141 C9 256 RET + 0142 32r0Es03 257 CKCON1: LD (CHARBUF),A ; SAVE CHARACTER IN BUFFER FOR LATER PROCESSING. + 0145 3E 01 258 CKCON2: LD A,#1 ; SET (A) TO NON ZERO TO MEAN SOMETHING IS READY. + 0147 C9 259 RET + 260 ; + 261 ; OUTPUT (C) TO THE SCREEN. IF THE PRINTER FLIP-FLOP FLAG + 262 ; IS SET, WE WILL SEND CHARACTER TO PRINTER ALSO. THE CONSOLE + 263 ; WILL BE CHECKED IN THE PROCESS. + 264 ; + 0148 3Ar0As03 265 OUTCHAR:LD A,(OUTFLAG) ; CHECK OUTPUT FLAG. + 014B B7 266 OR A ; ANYTHING AND WE WON'T GENERATE OUTPUT. + 014C C2r62s01 267 JP NZ,OUTCHR1 + 014F C5 268 PUSH BC + 0150 CDr23s01 269 CALL CKCONSOL ; CHECK CONSOLE (WE DON'T CARE WHATS THERE). + 0153 C1 270 POP BC + 0154 C5 271 PUSH BC + 0155 CD 0C E6 272 CALL CONOUT ; OUTPUT (C) TO THE SCREEN. + 0158 C1 273 POP BC + 0159 C5 274 PUSH BC + 015A 3Ar0Ds03 275 LD A,(PRTFLAG) ; CHECK PRINTER FLIP-FLOP FLAG. + 015D B7 276 OR A + 015E C4 0F E6 277 CALL NZ,LIST ; PRINT IT ALSO IF NON-ZERO. + 0161 C1 278 POP BC + 0162 79 279 OUTCHR1:LD A,C ; UPDATE CURSORS POSITION. + 0163 21r0Cs03 280 LD HL,#CURPOS + 0166 FE 7F 281 CP #DEL ; RUBOUTS DON'T DO ANYTHING HERE. + 0168 C8 282 RET Z + 0169 34 283 INC (HL) ; BUMP LINE POINTER. + 016A FE 20 284 CP #SPACE ; AND RETURN IF A NORMAL CHARACTER. + 016C D0 285 RET NC + 016D 35 286 DEC (HL) ; RESTORE AND CHECK FOR THE START OF THE LINE. + 016E 7E 287 LD A,(HL) + 016F B7 288 OR A + 0170 C8 289 RET Z ; INGNORE CONTROL CHARACTERS AT THE START OF THE LINE. + 0171 79 290 LD A,C + 0172 FE 08 291 CP #BS ; IS IT A BACKSPACE? + 0174 C2r79s01 292 JP NZ,OUTCHR2 + 0177 35 293 DEC (HL) ; YES, BACKUP POINTER. + 0178 C9 294 RET + 0179 FE 0A 295 OUTCHR2:CP #LF ; IS IT A LINE FEED? + 017B C0 296 RET NZ ; IGNORE ANYTHING ELSE. + 017C 36 00 297 LD (HL),#0 ; RESET POINTER TO START OF LINE. + 017E C9 298 RET + 299 ; + 300 ; OUTPUT (A) TO THE SCREEN. IF IT IS A CONTROL CHARACTER + 301 ; (OTHER THAN CARRIAGE CONTROL), USE ^X FORMAT. + 302 ; + 017F 79 303 SHOWIT: LD A,C + 0180 CDr14s01 304 CALL CHKCHAR ; CHECK CHARACTER. + 0183 D2r90s01 305 JP NC,OUTCON ; NOT A CONTROL, USE NORMAL OUTPUT. + 0186 F5 306 PUSH AF + 0187 0E 5E 307 LD C,#UP ; FOR A CONTROL CHARACTER, PRECEED IT WITH '^'. + 0189 CDr48s01 308 CALL OUTCHAR + 018C F1 309 POP AF + 018D F6 40 310 OR #AT ; AND THEN USE THE LETTER .EQUIVELANT. + 018F 4F 311 LD C,A + 312 ; + 313 ; FUNCTION TO OUTPUT (C) TO THE CONSOLE DEVICE AND EXPAND TABS + 314 ; IF NECESSARY. + 315 ; + 0190 79 316 OUTCON: LD A,C + 0191 FE 09 317 CP #TAB ; IS IT A TAB? + 0193 C2r48s01 318 JP NZ,OUTCHAR ; USE REGULAR OUTPUT. + 0196 0E 20 319 OUTCON1:LD C,#SPACE ; YES IT IS, USE SPACES INSTEAD. + 0198 CDr48s01 320 CALL OUTCHAR + 019B 3Ar0Cs03 321 LD A,(CURPOS) ; GO UNTIL THE CURSOR IS AT A MULTIPLE OF 8 + 322 + 019E E6 07 323 AND #7 ; POSITION. + 01A0 C2r96s01 324 JP NZ,OUTCON1 + 01A3 C9 325 RET + 326 ; + 327 ; ECHO A BACKSPACE CHARACTER. ERASE THE PREVOIUS CHARACTER + 328 ; ON THE SCREEN. + 329 ; + 01A4 CDrACs01 330 BACKUP: CALL BACKUP1 ; BACKUP THE SCREEN 1 PLACE. + 01A7 0E 20 331 LD C,#SPACE ; THEN BLANK THAT CHARACTER. + 01A9 CD 0C E6 332 CALL CONOUT + 01AC 0E 08 333 BACKUP1:LD C,#BS ; THEN BACK SPACE ONCE MORE. + 01AE C3 0C E6 334 JP CONOUT + 335 ; + 336 ; SIGNAL A DELETED LINE. PRINT A '#' AT THE END AND START + 337 ; OVER. + 338 ; + 01B1 0E 23 339 NEWLINE:LD C,#POUND + 01B3 CDr48s01 340 CALL OUTCHAR ; PRINT THIS. + 01B6 CDrC9s01 341 CALL OUTCRLF ; START NEW LINE. + 01B9 3Ar0Cs03 342 NEWLN1: LD A,(CURPOS) ; MOVE THE CURSOR TO THE STARTING POSITION. + 01BC 21r0Bs03 343 LD HL,#STARTING + 01BF BE 344 CP (HL) + 01C0 D0 345 RET NC ; THERE YET? + 01C1 0E 20 346 LD C,#SPACE + 01C3 CDr48s01 347 CALL OUTCHAR ; NOPE, KEEP GOING. + 01C6 C3rB9s01 348 JP NEWLN1 + 349 ; + 350 ; OUTPUT A (CR) (LF) TO THE CONSOLE DEVICE (SCREEN). + 351 ; + 01C9 0E 0D 352 OUTCRLF:LD C,#CR + 01CB CDr48s01 353 CALL OUTCHAR + 01CE 0E 0A 354 LD C,#LF + 01D0 C3r48s01 355 JP OUTCHAR + 356 ; + 357 ; PRINT MESSAGE POINTED TO BY (BC). IT WILL END WITH A '$'. + 358 ; + 01D3 0A 359 PRTMESG:LD A,(BC) ; CHECK FOR TERMINATING CHARACTER. + 01D4 FE 24 360 CP #DOLLAR + 01D6 C8 361 RET Z + 01D7 03 362 INC BC + 01D8 C5 363 PUSH BC ; OTHERWISE, BUMP POINTER AND PRINT IT. + 01D9 4F 364 LD C,A + 01DA CDr90s01 365 CALL OUTCON + 01DD C1 366 POP BC + 01DE C3rD3s01 367 JP PRTMESG + 368 ; + 369 ; FUNCTION TO EXECUTE A BUFFERED READ. + 370 ; + 01E1 3Ar0Cs03 371 R.DBUFF: LD A,(CURPOS) ; USE PRESENT LOCATION AS STARTING ONE. + 01E4 32r0Bs03 372 LD (STARTING),A + 01E7 2Ar43s03 373 LD HL,(PARAMS) ; GET THE MAXIMUM BUFFER SPACE. + 01EA 4E 374 LD C,(HL) + 01EB 23 375 INC HL ; POINT TO FIRST AVAILABLE SPACE. + 01EC E5 376 PUSH HL ; AND SAVE. + 01ED 06 00 377 LD B,#0 ; KEEP A CHARACTER COUNT. + 01EF C5 378 R.DBUF1: PUSH BC + 01F0 E5 379 PUSH HL + 01F1 CDrFBs00 380 R.DBUF2: CALL GETCHAR ; GET THE NEXT INPUT CHARACTER. + 01F4 E6 7F 381 AND #0x7F ; STRIP BIT 7. + 01F6 E1 382 POP HL ; RESET REGISTERS. + 01F7 C1 383 POP BC + 01F8 FE 0D 384 CP #CR ; EN OF THE LINE? + 01FA CArC1s02 385 JP Z,R.DBUF17 + 01FD FE 0A 386 CP #LF + 01FF CArC1s02 387 JP Z,R.DBUF17 + 0202 FE 08 388 CP #BS ; HOW ABOUT A BACKSPACE? + 0204 C2r16s02 389 JP NZ,R.DBUF3 + 0207 78 390 LD A,B ; YES, BUT IGNORE AT THE BEGINNING OF THE LINE. + 0208 B7 391 OR A + 0209 CArEFs01 392 JP Z,R.DBUF1 + 020C 05 393 DEC B ; OK, UPDATE COUNTER. + 020D 3Ar0Cs03 394 LD A,(CURPOS) ; IF WE BACKSPACE TO THE START OF THE LINE, + 0210 32r0As03 395 LD (OUTFLAG),A ; TREAT AS A CANCEL (CONTROL-X). + 0213 C3r70s02 396 JP R.DBUF10 + 0216 FE 7F 397 R.DBUF3: CP #DEL ; USER TYPED A RUBOUT? + 0218 C2r26s02 398 JP NZ,R.DBUF4 + 021B 78 399 LD A,B ; IGNORE AT THE START OF THE LINE. + 021C B7 400 OR A + 021D CArEFs01 401 JP Z,R.DBUF1 + 0220 7E 402 LD A,(HL) ; OK, ECHO THE PREVOIUS CHARACTER. + 0221 05 403 DEC B ; AND RESET POINTERS (COUNTERS). + 0222 2B 404 DEC HL + 0223 C3rA9s02 405 JP R.DBUF15 + 0226 FE 05 406 R.DBUF4: CP #CNTRLE ; PHYSICAL END OF LINE? + 0228 C2r37s02 407 JP NZ,R.DBUF5 + 022B C5 408 PUSH BC ; YES, DO IT. + 022C E5 409 PUSH HL + 022D CDrC9s01 410 CALL OUTCRLF + 0230 AF 411 XOR A ; AND UPDATE STARTING POSITION. + 0231 32r0Bs03 412 LD (STARTING),A + 0234 C3rF1s01 413 JP R.DBUF2 + 0237 FE 10 414 R.DBUF5: CP #CNTRLP ; CONTROL-P? + 0239 C2r48s02 415 JP NZ,R.DBUF6 + 023C E5 416 PUSH HL ; YES, FLIP THE PRINT FLAG FILP-FLOP BYTE. + 023D 21r0Ds03 417 LD HL,#PRTFLAG + 0240 3E 01 418 LD A,#1 ; PRTFLAG=1-PRTFLAG + 0242 96 419 SUB (HL) + 0243 77 420 LD (HL),A + 0244 E1 421 POP HL + 0245 C3rEFs01 422 JP R.DBUF1 + 0248 FE 18 423 R.DBUF6: CP #CNTRLX ; CONTROL-X (CANCEL)? + 024A C2r5Fs02 424 JP NZ,R.DBUF8 + 024D E1 425 POP HL + 024E 3Ar0Bs03 426 R.DBUF7: LD A,(STARTING) ; YES, BACKUP THE CURSOR TO HERE. + 0251 21r0Cs03 427 LD HL,#CURPOS + 0254 BE 428 CP (HL) + 0255 D2rE1s01 429 JP NC,R.DBUFF ; DONE YET? + 0258 35 430 DEC (HL) ; NO, DECREMENT POINTER AND OUTPUT BACK UP ONE SPACE. + 0259 CDrA4s01 431 CALL BACKUP + 025C C3r4Es02 432 JP R.DBUF7 + 025F FE 15 433 R.DBUF8: CP #CNTRLU ; CNTROL-U (CANCEL LINE)? + 0261 C2r6Bs02 434 JP NZ,R.DBUF9 + 0264 CDrB1s01 435 CALL NEWLINE ; START A NEW LINE. + 0267 E1 436 POP HL + 0268 C3rE1s01 437 JP R.DBUFF + 026B FE 12 438 R.DBUF9: CP #CNTRLR ; CONTROL-R? + 026D C2rA6s02 439 JP NZ,R.DBUF14 + 0270 C5 440 R.DBUF10:PUSH BC ; YES, START A NEW LINE AND RETYPE THE OLD ONE. + 0271 CDrB1s01 441 CALL NEWLINE + 0274 C1 442 POP BC + 0275 E1 443 POP HL + 0276 E5 444 PUSH HL + 0277 C5 445 PUSH BC + 0278 78 446 R.DBUF11:LD A,B ; DONE WHOLE LINE YET? + 0279 B7 447 OR A + 027A CAr8As02 448 JP Z,R.DBUF12 + 027D 23 449 INC HL ; NOPE, GET NEXT CHARACTER. + 027E 4E 450 LD C,(HL) + 027F 05 451 DEC B ; COUNT IT. + 0280 C5 452 PUSH BC + 0281 E5 453 PUSH HL + 0282 CDr7Fs01 454 CALL SHOWIT ; AND DISPLAY IT. + 0285 E1 455 POP HL + 0286 C1 456 POP BC + 0287 C3r78s02 457 JP R.DBUF11 + 028A E5 458 R.DBUF12:PUSH HL ; DONE WITH LINE. IF WE WERE DISPLAYING + 028B 3Ar0As03 459 LD A,(OUTFLAG) ; THEN UPDATE CURSOR POSITION. + 028E B7 460 OR A + 028F CArF1s01 461 JP Z,R.DBUF2 + 0292 21r0Cs03 462 LD HL,#CURPOS ; BECAUSE THIS LINE IS SHORTER, WE MUST + 0295 96 463 SUB (HL) ; BACK UP THE CURSOR (NOT THE SCREEN HOWEVER) + 0296 32r0As03 464 LD (OUTFLAG),A ; SOME NUMBER OF POSITIONS. + 0299 CDrA4s01 465 R.DBUF13:CALL BACKUP ; NOTE THAT AS LONG AS (OUTFLAG) IS NON + 029C 21r0As03 466 LD HL,#OUTFLAG ; ZERO, THE SCREEN WILL NOT BE CHANGED. + 029F 35 467 DEC (HL) + 02A0 C2r99s02 468 JP NZ,R.DBUF13 + 02A3 C3rF1s01 469 JP R.DBUF2 ; NOW JUST GET THE NEXT CHARACTER. + 470 ; + 471 ; JUST A NORMAL CHARACTER, PUT THIS IN OUR BUFFER AND ECHO. + 472 ; + 02A6 23 473 R.DBUF14:INC HL + 02A7 77 474 LD (HL),A ; STORE CHARACTER. + 02A8 04 475 INC B ; AND COUNT IT. + 02A9 C5 476 R.DBUF15:PUSH BC + 02AA E5 477 PUSH HL + 02AB 4F 478 LD C,A ; ECHO IT NOW. + 02AC CDr7Fs01 479 CALL SHOWIT + 02AF E1 480 POP HL + 02B0 C1 481 POP BC + 02B1 7E 482 LD A,(HL) ; WAS IT AN ABORT R.EQUEST? + 02B2 FE 03 483 CP #CNTRLC ; CONTROL-C ABORT? + 02B4 78 484 LD A,B + 02B5 C2rBDs02 485 JP NZ,R.DBUF16 + 02B8 FE 01 486 CP #1 ; ONLY IF AT START OF LINE. + 02BA CA 00 00 487 JP Z,0 + 02BD B9 488 R.DBUF16:CP C ; NOPE, HAVE WE FILLED THE BUFFER? + 02BE DArEFs01 489 JP C,R.DBUF1 + 02C1 E1 490 R.DBUF17:POP HL ; YES END THE LINE AND RETURN. + 02C2 70 491 LD (HL),B + 02C3 0E 0D 492 LD C,#CR + 02C5 C3r48s01 493 JP OUTCHAR ; OUTPUT (CR) AND RETURN. + 494 ; + 495 ; FUNCTION TO GET A CHARACTER FROM THE CONSOLE DEVICE. + 496 ; + 02C8 CDr06s01 497 GETCON: CALL GETECHO ; GET AND ECHO. + 02CB C3r01s03 498 JP SETSTAT ; SAVE STATUS AND RETURN. + 499 ; + 500 ; FUNCTION TO GET A CHARACTER FROM THE TAPE READER DEVICE. + 501 ; + 02CE CD 15 E6 502 GETRDR: CALL READER ; GET A CHARACTER FROM READER, SET STATUS AND RETURN. + 02D1 C3r01s03 503 JP SETSTAT + 504 ; + 505 ; FUNCTION TO PERFORM DIRECT CONSOLE I/O. IF (C) CONTAINS (FF) + 506 ; THEN THIS IS AN INPUT R.EQUEST. IF (C) CONTAINS (FE) THEN + 507 ; THIS IS A STATUS R.EQUEST. OTHERWISE WE ARE TO OUTPUT (C). + 508 ; + 02D4 79 509 DIRCIO: LD A,C ; TEST FOR (FF). + 02D5 3C 510 INC A + 02D6 CArE0s02 511 JP Z,DIRC1 + 02D9 3C 512 INC A ; TEST FOR (FE). + 02DA CA 06 E6 513 JP Z,CONST + 02DD C3 0C E6 514 JP CONOUT ; JUST OUTPUT (C). + 02E0 CD 06 E6 515 DIRC1: CALL CONST ; THIS IS AN INPUT R.EQUEST. + 02E3 B7 516 OR A + 02E4 CAr91s0D 517 JP Z,GOBACK1 ; NOT READY? JUST RETURN (DIRECTLY). + 02E7 CD 09 E6 518 CALL CONIN ; YES, GET CHARACTER. + 02EA C3r01s03 519 JP SETSTAT ; SET STATUS AND RETURN. + 520 ; + 521 ; FUNCTION TO RETURN THE I/O BYTE. + 522 ; + 02ED 3A 03 00 523 GETIOB: LD A,(IOBYTE) + 02F0 C3r01s03 524 JP SETSTAT + 525 ; + 526 ; FUNCTION TO SET THE I/O BYTE. + 527 ; + 02F3 21 03 00 528 SETIOB: LD HL,#IOBYTE + 02F6 71 529 LD (HL),C + 02F7 C9 530 RET + 531 ; + 532 ; FUNCTION TO PRINT THE CHARACTER STRING POINTED TO BY (DE) + 533 ; ON THE CONSOLE DEVICE. THE STRING ENDS WITH A '$'. + 534 ; + 02F8 EB 535 PRTSTR: EX DE,HL + 02F9 4D 536 LD C,L + 02FA 44 537 LD B,H ; NOW (BC) POINTS TO IT. + 02FB C3rD3s01 538 JP PRTMESG + 539 ; + 540 ; FUNCTION TO INTERIGATE THE CONSOLE DEVICE. + 541 ; + 02FE CDr23s01 542 GETCSTS:CALL CKCONSOL + 543 ; + 544 ; GET HERE TO SET THE STATUS AND RETURN TO THE CLEANUP + 545 ; SECTION. THEN BACK TO THE USER. + 546 ; + 0301 32r45s03 547 SETSTAT:LD (STATUS),A + 0304 C9 548 RTN: RET + 549 ; + 550 ; SET THE STATUS TO 1 (READ OR WRITE ERROR CODE). + 551 ; + 0305 3E 01 552 IOERR1: LD A,#1 + 0307 C3r01s03 553 JP SETSTAT + 554 ; + 030A 00 555 OUTFLAG:.DB 0 ; OUTPUT FLAG (NON ZERO MEANS NO OUTPUT). + 030B 556 STARTING: + 030B 02 557 .DB 2 ; STARTING POSITION FOR CURSOR. + 030C 00 558 CURPOS: .DB 0 ; CURSOR POSITION (0=START OF LINE). + 030D 00 559 PRTFLAG:.DB 0 ; PRINTER FLAG (CONTROL-P TOGGLE). LIST IF NON ZERO. + 030E 00 560 CHARBUF:.DB 0 ; SINGLE INPUT CHARACTER BUFFER. + 561 ; + 562 ; STACK AREA FOR BDOS CALLS. + 563 ; + 030F 564 USRSTACK: + 030F 00 00 565 .DW 0 ; SAVE USERS STACK POINTER HERE. + 566 ; + 0311 00 00 00 00 00 00 567 .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 0329 00 00 00 00 00 00 568 .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 0341 569 STKAREA: ; END OF STACK AREA. + 570 ; + 0341 00 571 USERNO: .DB 0 ; CURRENT USER NUMBER. + 0342 00 572 ACTIVE: .DB 0 ; CURRENTLY ACTIVE DRIVE. + 0343 00 00 573 PARAMS: .DW 0 ; SAVE (DE) PARAMETERS HERE ON ENTRY. + 0345 00 00 574 STATUS: .DW 0 ; STATUS RETURNED FROM BDOS FUNCTION. + 575 ; + 576 ; SELECT ERROR OCCURED, JUMP TO ERROR ROUTINE. + 577 ; + 0347 21r0Bs00 578 SLCTERR:LD HL,#BADSLCT + 579 ; + 580 ; JUMP TO (HL) INDIRECTLY. + 581 ; + 034A 5E 582 JUMPHL: LD E,(HL) + 034B 23 583 INC HL + 034C 56 584 LD D,(HL) ; NOW (DE) CONTAIN THE DESIRED ADDRESS. + 034D EB 585 EX DE,HL + 034E E9 586 JP (HL) + 587 ; + 588 ; BLOCK MOVE. (DE) TO (HL), (C) BYTES TOTAL. + 589 ; + 034F 0C 590 DE2HL: INC C ; IS COUNT DOWN TO ZERO? + 0350 0D 591 DE2HL1: DEC C + 0351 C8 592 RET Z ; YES, WE ARE DONE. + 0352 1A 593 LD A,(DE) ; NO, MOVE ONE MORE BYTE. + 0353 77 594 LD (HL),A + 0354 13 595 INC DE + 0355 23 596 INC HL + 0356 C3r50s03 597 JP DE2HL1 ; AND REPEAT. + 598 ; + 599 ; SELECT THE DESIRED DRIVE. + 600 ; + 0359 3Ar42s03 601 SELECT: LD A,(ACTIVE) ; GET ACTIVE DISK. + 035C 4F 602 LD C,A + 035D CD 1B E6 603 CALL SELDSK ; SELECT IT. + 0360 7C 604 LD A,H ; VALID DRIVE? + 0361 B5 605 OR L ; VALID DRIVE? + 0362 C8 606 RET Z ; RETURN IF NOT. + 607 ; + 608 ; HERE, THE BIOS RETURNED THE ADDRESS OF THE PARAMETER BLOCK + 609 ; IN (HL). WE WILL EXTRACT THE NECESSARY POINTERS AND SAVE THEM. + 610 ; + 0363 5E 611 LD E,(HL) ; YES, GET ADDRESS OF TRANSLATION TABLE INTO (DE). + 0364 23 612 INC HL + 0365 56 613 LD D,(HL) + 0366 23 614 INC HL + 0367 22rB3s0D 615 LD (SCRATCH1),HL ; SAVE POINTERS TO SCRATCH AREAS. + 036A 23 616 INC HL + 036B 23 617 INC HL + 036C 22rB5s0D 618 LD (SCRATCH2),HL ; DITTO. + 036F 23 619 INC HL + 0370 23 620 INC HL + 0371 22rB7s0D 621 LD (SCRATCH3),HL ; DITTO. + 0374 23 622 INC HL + 0375 23 623 INC HL + 0376 EB 624 EX DE,HL ; NOW SAVE THE TRANSLATION TABLE ADDRESS. + 0377 22rD0s0D 625 LD (XLATE),HL + 037A 21rB9s0D 626 LD HL,#DIRBUF ; PUT THE NEXT 8 BYTES HERE. + 037D 0E 08 627 LD C,#8 ; THEY CONSIST OF THE DIRECTORY BUFFER + 037F CDr4Fs03 628 CALL DE2HL ; POINTER, PARAMETER BLOCK POINTER, + 0382 2ArBBs0D 629 LD HL,(DISKPB) ; CHECK AND ALLOCATION VECTORS. + 0385 EB 630 EX DE,HL + 0386 21rC1s0D 631 LD HL,#SECTORS ; MOVE PARAMETER BLOCK INTO OUR RAM. + 0389 0E 0F 632 LD C,#15 ; IT IS 15 BYTES LONG. + 038B CDr4Fs03 633 CALL DE2HL + 038E 2ArC6s0D 634 LD HL,(DSKSIZE) ; CHECK DISK SIZE. + 0391 7C 635 LD A,H ; MORE THAN 256 BLOCKS ON THIS? + 0392 21rDDs0D 636 LD HL,#BIGDISK + 0395 36 FF 637 LD (HL),#0x0FF ; SET TO SAMLL. + 0397 B7 638 OR A + 0398 CAr9Ds03 639 JP Z,SELECT1 + 039B 36 00 640 LD (HL),#0 ; WRONG, SET TO LARGE. + 039D 3E FF 641 SELECT1:LD A,#0x0FF ; CLEAR THE ZERO FLAG. + 039F B7 642 OR A + 03A0 C9 643 RET + 644 ; + 645 ; ROUTINE TO HOME THE DISK TRACK HEAD AND CLEAR POINTERS. + 646 ; + 03A1 CD 18 E6 647 HOMEDRV:CALL HOME ; HOME THE HEAD. + 03A4 AF 648 XOR A + 03A5 2ArB5s0D 649 LD HL,(SCRATCH2) ; SET OUR TRACK POINTER ALSO. + 03A8 77 650 LD (HL),A + 03A9 23 651 INC HL + 03AA 77 652 LD (HL),A + 03AB 2ArB7s0D 653 LD HL,(SCRATCH3) ; AND OUR SECTOR POINTER. + 03AE 77 654 LD (HL),A + 03AF 23 655 INC HL + 03B0 77 656 LD (HL),A + 03B1 C9 657 RET + 658 ; + 659 ; DO THE ACTUAL DISK READ AND CHECK THE ERROR RETURN STATUS. + 660 ; + 03B2 CD 27 E6 661 DOREAD: CALL READ + 03B5 C3rBBs03 662 JP IORET + 663 ; + 664 ; DO THE ACTUAL DISK WRITE AND HANDLE ANY BIOS ERROR. + 665 ; + 03B8 CD 2A E6 666 DOWRITE:CALL WRITE + 03BB B7 667 IORET: OR A + 03BC C8 668 RET Z ; RETURN UNLESS AN ERROR OCCURED. + 03BD 21r09s00 669 LD HL,#BADSCTR ; BAD READ/WRITE ON THIS SECTOR. + 03C0 C3r4As03 670 JP JUMPHL + 671 ; + 672 ; ROUTINE TO SELECT THE TRACK AND SECTOR THAT THE DESIRED + 673 ; BLOCK NUMBER FALLS IN. + 674 ; + 03C3 2ArEAs0D 675 TRKSEC: LD HL,(FILEPOS) ; GET POSITION OF LAST ACCESSED FILE + 03C6 0E 02 676 LD C,#2 ; IN DIRECTORY AND COMPUTE SECTOR #. + 03C8 CDrEAs04 677 CALL SHIFTR ; SECTOR #=FILE-POSITION/4. + 03CB 22rE5s0D 678 LD (BLKNMBR),HL ; SAVE THIS AS THE BLOCK NUMBER OF INTEREST. + 03CE 22rECs0D 679 LD (CKSUMTBL),HL ; WHAT'S IT DOING HERE TOO? + 680 ; + 681 ; IF THE SECTOR NUMBER HAS ALREADY BEEN SET (BLKNMBR), ENTER + 682 ; AT THIS POINT. + 683 ; + 03D1 21rE5s0D 684 TRKSEC1:LD HL,#BLKNMBR + 03D4 4E 685 LD C,(HL) ; MOVE SECTOR NUMBER INTO (BC). + 03D5 23 686 INC HL + 03D6 46 687 LD B,(HL) + 03D7 2ArB7s0D 688 LD HL,(SCRATCH3) ; GET CURRENT SECTOR NUMBER AND + 03DA 5E 689 LD E,(HL) ; MOVE THIS INTO (DE). + 03DB 23 690 INC HL + 03DC 56 691 LD D,(HL) + 03DD 2ArB5s0D 692 LD HL,(SCRATCH2) ; GET CURRENT TRACK NUMBER. + 03E0 7E 693 LD A,(HL) ; AND THIS INTO (HL). + 03E1 23 694 INC HL + 03E2 66 695 LD H,(HL) + 03E3 6F 696 LD L,A + 03E4 79 697 TRKSEC2:LD A,C ; IS DESIRED SECTOR BEFORE CURRENT ONE? + 03E5 93 698 SUB E + 03E6 78 699 LD A,B + 03E7 9A 700 SBC A,D + 03E8 D2rFAs03 701 JP NC,TRKSEC3 + 03EB E5 702 PUSH HL ; YES, DECREMENT SECTORS BY ONE TRACK. + 03EC 2ArC1s0D 703 LD HL,(SECTORS) ; GET SECTORS PER TRACK. + 03EF 7B 704 LD A,E + 03F0 95 705 SUB L + 03F1 5F 706 LD E,A + 03F2 7A 707 LD A,D + 03F3 9C 708 SBC A,H + 03F4 57 709 LD D,A ; NOW WE HAVE BACKED UP ONE FULL TRACK. + 03F5 E1 710 POP HL + 03F6 2B 711 DEC HL ; ADJUST TRACK COUNTER. + 03F7 C3rE4s03 712 JP TRKSEC2 + 03FA E5 713 TRKSEC3:PUSH HL ; DESIRED SECTOR IS AFTER CURRENT ONE. + 03FB 2ArC1s0D 714 LD HL,(SECTORS) ; GET SECTORS PER TRACK. + 03FE 19 715 ADD HL,DE ; BUMP SECTOR POINTER TO NEXT TRACK. + 03FF DAr0Fs04 716 JP C,TRKSEC4 + 0402 79 717 LD A,C ; IS DESIRED SECTOR NOW BEFORE CURRENT ONE? + 0403 95 718 SUB L + 0404 78 719 LD A,B + 0405 9C 720 SBC A,H + 0406 DAr0Fs04 721 JP C,TRKSEC4 + 0409 EB 722 EX DE,HL ; NOT YES, INCREMENT TRACK COUNTER + 040A E1 723 POP HL ; AND CONTINUE UNTIL IT IS. + 040B 23 724 INC HL + 040C C3rFAs03 725 JP TRKSEC3 + 726 ; + 727 ; HERE WE HAVE DETERMINED THE TRACK NUMBER THAT CONTAINS THE + 728 ; DESIRED SECTOR. + 729 ; + 040F E1 730 TRKSEC4:POP HL ; GET TRACK NUMBER (HL). + 0410 C5 731 PUSH BC + 0411 D5 732 PUSH DE + 0412 E5 733 PUSH HL + 0413 EB 734 EX DE,HL + 0414 2ArCEs0D 735 LD HL,(OFFSET) ; ADJUST FOR FIRST TRACK OFFSET. + 0417 19 736 ADD HL,DE + 0418 44 737 LD B,H + 0419 4D 738 LD C,L + 041A CD 1E E6 739 CALL SETTRK ; SELECT THIS TRACK. + 041D D1 740 POP DE ; RESET CURRENT TRACK POINTER. + 041E 2ArB5s0D 741 LD HL,(SCRATCH2) + 0421 73 742 LD (HL),E + 0422 23 743 INC HL + 0423 72 744 LD (HL),D + 0424 D1 745 POP DE + 0425 2ArB7s0D 746 LD HL,(SCRATCH3) ; RESET THE FIRST SECTOR ON THIS TRACK. + 0428 73 747 LD (HL),E + 0429 23 748 INC HL + 042A 72 749 LD (HL),D + 042B C1 750 POP BC + 042C 79 751 LD A,C ; NOW SUBTRACT THE DESIRED ONE. + 042D 93 752 SUB E ; TO MAKE IT RELATIVE (1-# SECTORS/TRACK). + 042E 4F 753 LD C,A + 042F 78 754 LD A,B + 0430 9A 755 SBC A,D + 0431 47 756 LD B,A + 0432 2ArD0s0D 757 LD HL,(XLATE) ; TRANSLATE THIS SECTOR ACCORDING TO THIS TABLE. + 0435 EB 758 EX DE,HL + 0436 CD 30 E6 759 CALL SECTRN ; LET THE BIOS TRANSLATE IT. + 0439 4D 760 LD C,L + 043A 44 761 LD B,H + 043B C3 21 E6 762 JP SETSEC ; AND SELECT IT. + 763 ; + 764 ; COMPUTE BLOCK NUMBER FROM RECORD NUMBER (SAVNREC) AND + 765 ; EXTENT NUMBER (SAVEXT). + 766 ; + 043E 767 GETBLOCK: + 043E 21rC3s0D 768 LD HL,#BLKSHFT ; GET LOGICAL TO PHYSICAL CONVERSION. + 0441 4E 769 LD C,(HL) ; NOTE THAT THIS IS BASE 2 LOG OF RATIO. + 0442 3ArE3s0D 770 LD A,(SAVNREC) ; GET RECORD NUMBER. + 0445 B7 771 GETBLK1:OR A ; COMPUTE (A)=(A)/2^BLKSHFT. + 0446 1F 772 RRA + 0447 0D 773 DEC C + 0448 C2r45s04 774 JP NZ,GETBLK1 + 044B 47 775 LD B,A ; SAVE RESULT IN (B). + 044C 3E 08 776 LD A,#8 + 044E 96 777 SUB (HL) + 044F 4F 778 LD C,A ; COMPUTE (C)=8-BLKSHFT. + 0450 3ArE2s0D 779 LD A,(SAVEXT) + 0453 0D 780 GETBLK2:DEC C ; COMPUTE (A)=SAVEXT*2^(8-BLKSHFT). + 0454 CAr5Cs04 781 JP Z,GETBLK3 + 0457 B7 782 OR A + 0458 17 783 RLA + 0459 C3r53s04 784 JP GETBLK2 + 045C 80 785 GETBLK3:ADD A,B + 045D C9 786 RET + 787 ; + 788 ; ROUTINE TO EXTRACT THE (BC) BLOCK BYTE FROM THE FCB POINTED + 789 ; TO BY (PARAMS). IF THIS IS A BIG-DISK, THEN THESE ARE 16 BIT + 790 ; BLOCK NUMBERS, ELSE THEY ARE 8 BIT NUMBERS. + 791 ; NUMBER IS RETURNED IN (HL). + 792 ; + 045E 2Ar43s03 793 EXTBLK: LD HL,(PARAMS) ; GET FCB ADDRESS. + 0461 11 10 00 794 LD DE,#16 ; BLOCK NUMBERS START 16 BYTES INTO FCB. + 0464 19 795 ADD HL,DE + 0465 09 796 ADD HL,BC + 0466 3ArDDs0D 797 LD A,(BIGDISK) ; ARE WE USING A BIG-DISK? + 0469 B7 798 OR A + 046A CAr71s04 799 JP Z,EXTBLK1 + 046D 6E 800 LD L,(HL) ; NO, EXTRACT AN 8 BIT NUMBER FROM THE FCB. + 046E 26 00 801 LD H,#0 + 0470 C9 802 RET + 0471 09 803 EXTBLK1:ADD HL,BC ; YES, EXTRACT A 16 BIT NUMBER. + 0472 5E 804 LD E,(HL) + 0473 23 805 INC HL + 0474 56 806 LD D,(HL) + 0475 EB 807 EX DE,HL ; RETURN IN (HL). + 0476 C9 808 RET + 809 ; + 810 ; COMPUTE BLOCK NUMBER. + 811 ; + 0477 CDr3Es04 812 COMBLK: CALL GETBLOCK + 047A 4F 813 LD C,A + 047B 06 00 814 LD B,#0 + 047D CDr5Es04 815 CALL EXTBLK + 0480 22rE5s0D 816 LD (BLKNMBR),HL + 0483 C9 817 RET + 818 ; + 819 ; CHECK FOR A ZERO BLOCK NUMBER (UNUSED). + 820 ; + 0484 2ArE5s0D 821 CHKBLK: LD HL,(BLKNMBR) + 0487 7D 822 LD A,L ; IS IT ZERO? + 0488 B4 823 OR H + 0489 C9 824 RET + 825 ; + 826 ; ADJUST PHYSICAL BLOCK (BLKNMBR) AND CONVERT TO LOGICAL + 827 ; SECTOR (LOGSECT). THIS IS THE STARTING SECTOR OF THIS BLOCK. + 828 ; THE ACTUAL SECTOR OF INTEREST IS THEN ADDED TO THIS AND THE + 829 ; RESULTING SECTOR NUMBER IS STORED BACK IN (BLKNMBR). THIS + 830 ; WILL STILL HAVE TO BE ADJUSTED FOR THE TRACK NUMBER. + 831 ; + 048A 3ArC3s0D 832 LOGICAL:LD A,(BLKSHFT) ; GET LOG2(PHYSICAL/LOGICAL SECTORS). + 048D 2ArE5s0D 833 LD HL,(BLKNMBR) ; GET PHYSICAL SECTOR DESIRED. + 0490 29 834 LOGICL1:ADD HL,HL ; COMPUTE LOGICAL SECTOR NUMBER. + 0491 3D 835 DEC A ; NOTE LOGICAL SECTORS ARE 128 BYTES LONG. + 0492 C2r90s04 836 JP NZ,LOGICL1 + 0495 22rE7s0D 837 LD (LOGSECT),HL ; SAVE LOGICAL SECTOR. + 0498 3ArC4s0D 838 LD A,(BLKMASK) ; GET BLOCK MASK. + 049B 4F 839 LD C,A + 049C 3ArE3s0D 840 LD A,(SAVNREC) ; GET NEXT SECTOR TO ACCESS. + 049F A1 841 AND C ; EXTRACT THE RELATIVE POSITION WITHIN PHYSICAL BLOCK. + 04A0 B5 842 OR L ; AND ADD IT TOO LOGICAL SECTOR. + 04A1 6F 843 LD L,A + 04A2 22rE5s0D 844 LD (BLKNMBR),HL ; AND STORE. + 04A5 C9 845 RET + 846 ; + 847 ; SET (HL) TO POINT TO EXTENT BYTE IN FCB. + 848 ; + 04A6 2Ar43s03 849 SETEXT: LD HL,(PARAMS) + 04A9 11 0C 00 850 LD DE,#12 ; IT IS THE TWELTH BYTE. + 04AC 19 851 ADD HL,DE + 04AD C9 852 RET + 853 ; + 854 ; SET (HL) TO POINT TO RECORD COUNT BYTE IN FCB AND (DE) TO + 855 ; NEXT RECORD NUMBER BYTE. + 856 ; + 04AE 2Ar43s03 857 SETHLDE:LD HL,(PARAMS) + 04B1 11 0F 00 858 LD DE,#15 ; RECORD COUNT BYTE (#15). + 04B4 19 859 ADD HL,DE + 04B5 EB 860 EX DE,HL + 04B6 21 11 00 861 LD HL,#17 ; NEXT RECORD NUMBER (#32). + 04B9 19 862 ADD HL,DE + 04BA C9 863 RET + 864 ; + 865 ; SAVE CURRENT FILE DATA FROM FCB. + 866 ; + 04BB CDrAEs04 867 STRDATA:CALL SETHLDE + 04BE 7E 868 LD A,(HL) ; GET AND STORE RECORD COUNT BYTE. + 04BF 32rE3s0D 869 LD (SAVNREC),A + 04C2 EB 870 EX DE,HL + 04C3 7E 871 LD A,(HL) ; GET AND STORE NEXT RECORD NUMBER BYTE. + 04C4 32rE1s0D 872 LD (SAVNXT),A + 04C7 CDrA6s04 873 CALL SETEXT ; POINT TO EXTENT BYTE. + 04CA 3ArC5s0D 874 LD A,(EXTMASK) ; GET EXTENT MASK. + 04CD A6 875 AND (HL) + 04CE 32rE2s0D 876 LD (SAVEXT),A ; AND SAVE EXTENT HERE. + 04D1 C9 877 RET + 878 ; + 879 ; SET THE NEXT RECORD TO ACCESS. IF (MODE) IS SET TO 2, THEN + 880 ; THE LAST RECORD BYTE (SAVNREC) HAS THE CORRECT NUMBER TO ACCESS. + 881 ; FOR S.EQUENTIAL ACCESS, (MODE) WILL BE .EQUAL TO 1. + 882 ; + 04D2 CDrAEs04 883 SETNREC:CALL SETHLDE + 04D5 3ArD5s0D 884 LD A,(MODE) ; GET S.EQUENTIAL FLAG (=1). + 04D8 FE 02 885 CP #2 ; A 2 INDICATES THAT NO ADDER IS NEEDED. + 04DA C2rDEs04 886 JP NZ,STNREC1 + 04DD AF 887 XOR A ; CLEAR ADDER (RANDOM ACCESS?). + 04DE 4F 888 STNREC1:LD C,A + 04DF 3ArE3s0D 889 LD A,(SAVNREC) ; GET LAST RECORD NUMBER. + 04E2 81 890 ADD A,C ; INCREMENT RECORD COUNT. + 04E3 77 891 LD (HL),A ; AND SET FCB'S NEXT RECORD BYTE. + 04E4 EB 892 EX DE,HL + 04E5 3ArE1s0D 893 LD A,(SAVNXT) ; GET NEXT RECORD BYTE FROM STORAGE. + 04E8 77 894 LD (HL),A ; AND PUT THIS INTO FCB AS NUMBER OF RECORDS USED. + 04E9 C9 895 RET + 896 ; + 897 ; SHIFT (HL) RIGHT (C) BITS. + 898 ; + 04EA 0C 899 SHIFTR: INC C + 04EB 0D 900 SHIFTR1:DEC C + 04EC C8 901 RET Z + 04ED 7C 902 LD A,H + 04EE B7 903 OR A + 04EF 1F 904 RRA + 04F0 67 905 LD H,A + 04F1 7D 906 LD A,L + 04F2 1F 907 RRA + 04F3 6F 908 LD L,A + 04F4 C3rEBs04 909 JP SHIFTR1 + 910 ; + 911 ; COMPUTE THE CHECK-SUM FOR THE DIRECTORY BUFFER. RETURN + 912 ; INTEGER SUM IN (A). + 913 ; + 04F7 914 CHECKSUM: + 04F7 0E 80 915 LD C,#128 ; LENGTH OF BUFFER. + 04F9 2ArB9s0D 916 LD HL,(DIRBUF) ; GET ITS LOCATION. + 04FC AF 917 XOR A ; CLEAR SUMMATION BYTE. + 04FD 86 918 CHKSUM1:ADD A,(HL) ; AND COMPUTE SUM IGNORING CARRIES. + 04FE 23 919 INC HL + 04FF 0D 920 DEC C + 0500 C2rFDs04 921 JP NZ,CHKSUM1 + 0503 C9 922 RET + 923 ; + 924 ; SHIFT (HL) LEFT (C) BITS. + 925 ; + 0504 0C 926 SHIFTL: INC C + 0505 0D 927 SHIFTL1:DEC C + 0506 C8 928 RET Z + 0507 29 929 ADD HL,HL ; SHIFT LEFT 1 BIT. + 0508 C3r05s05 930 JP SHIFTL1 + 931 ; + 932 ; ROUTINE TO SET A BIT IN A 16 BIT VALUE CONTAINED IN (BC). + 933 ; THE BIT SET DEPENDS ON THE CURRENT DRIVE SELECTION. + 934 ; + 050B C5 935 SETBIT: PUSH BC ; SAVE 16 BIT WORD. + 050C 3Ar42s03 936 LD A,(ACTIVE) ; GET ACTIVE DRIVE. + 050F 4F 937 LD C,A + 0510 21 01 00 938 LD HL,#1 + 0513 CDr04s05 939 CALL SHIFTL ; SHIFT BIT 0 INTO PLACE. + 0516 C1 940 POP BC ; NOW 'OR' THIS WITH THE ORIGINAL WORD. + 0517 79 941 LD A,C + 0518 B5 942 OR L + 0519 6F 943 LD L,A ; LOW BYTE DONE, DO HIGH BYTE. + 051A 78 944 LD A,B + 051B B4 945 OR H + 051C 67 946 LD H,A + 051D C9 947 RET + 948 ; + 949 ; EXTRACT THE WRITE PROTECT STATUS BIT FOR THE CURRENT DRIVE. + 950 ; THE RESULT IS RETURNED IN (A), BIT 0. + 951 ; + 051E 2ArADs0D 952 GETWPRT:LD HL,(WRTPRT) ; GET STATUS BYTES. + 0521 3Ar42s03 953 LD A,(ACTIVE) ; WHICH DRIVE IS CURRENT? + 0524 4F 954 LD C,A + 0525 CDrEAs04 955 CALL SHIFTR ; SHIFT STATUS SUCH THAT BIT 0 IS THE + 0528 7D 956 LD A,L ; ONE OF INTEREST FOR THIS DRIVE. + 0529 E6 01 957 AND #1 ; AND ISOLATE IT. + 052B C9 958 RET + 959 ; + 960 ; FUNCTION TO WRITE PROTECT THE CURRENT DISK. + 961 ; + 052C 21rADs0D 962 WRTPRTD:LD HL,#WRTPRT ; POINT TO STATUS WORD. + 052F 4E 963 LD C,(HL) ; SET (BC) .EQUAL TO THE STATUS. + 0530 23 964 INC HL + 0531 46 965 LD B,(HL) + 0532 CDr0Bs05 966 CALL SETBIT ; AND SET THIS BIT ACCORDING TO CURRENT DRIVE. + 0535 22rADs0D 967 LD (WRTPRT),HL ; THEN SAVE. + 0538 2ArC8s0D 968 LD HL,(DIRSIZE) ; NOW SAVE DIRECTORY SIZE LIMIT. + 053B 23 969 INC HL ; REMEMBER THE LAST ONE. + 053C EB 970 EX DE,HL + 053D 2ArB3s0D 971 LD HL,(SCRATCH1) ; AND STORE IT HERE. + 0540 73 972 LD (HL),E ; PUT LOW BYTE. + 0541 23 973 INC HL + 0542 72 974 LD (HL),D ; THEN HIGH BYTE. + 0543 C9 975 RET + 976 ; + 977 ; CHECK FOR A READ ONLY FILE. + 978 ; + 0544 CDr5Es05 979 CHKROFL:CALL FCB2HL ; SET (HL) TO FILE ENTRY IN DIRECTORY BUFFER. + 0547 11 09 00 980 CKROF1: LD DE,#9 ; LOOK AT BIT 7 OF THE NINTH BYTE. + 054A 19 981 ADD HL,DE + 054B 7E 982 LD A,(HL) + 054C 17 983 RLA + 054D D0 984 RET NC ; RETURN IF OK. + 054E 21r0Fs00 985 LD HL,#ROFILE ; ELSE, PRINT ERROR MESSAGE AND TERMINATE. + 0551 C3r4As03 986 JP JUMPHL + 987 ; + 988 ; CHECK THE WRITE PROTECT STATUS OF THE ACTIVE DISK. + 989 ; + 0554 CDr1Es05 990 CHKWPRT:CALL GETWPRT + 0557 C8 991 RET Z ; RETURN IF OK. + 0558 21r0Ds00 992 LD HL,#RODISK ; ELSE PRINT MESSAGE AND TERMINATE. + 055B C3r4As03 993 JP JUMPHL + 994 ; + 995 ; ROUTINE TO SET (HL) POINTING TO THE PROPER ENTRY IN THE + 996 ; DIRECTORY BUFFER. + 997 ; + 055E 2ArB9s0D 998 FCB2HL: LD HL,(DIRBUF) ; GET ADDRESS OF BUFFER. + 0561 3ArE9s0D 999 LD A,(FCBPOS) ; RELATIVE POSITION OF FILE. + 1000 ; + 1001 ; ROUTINE TO ADD (A) TO (HL). + 1002 ; + 0564 85 1003 ADDA2HL:ADD A,L + 0565 6F 1004 LD L,A + 0566 D0 1005 RET NC + 0567 24 1006 INC H ; TAKE CARE OF ANY CARRY. + 0568 C9 1007 RET + 1008 ; + 1009 ; ROUTINE TO GET THE 'S2' BYTE FROM THE FCB SUPPLIED IN + 1010 ; THE INITIAL PARAMETER SPECIFICATION. + 1011 ; + 0569 2Ar43s03 1012 GETS2: LD HL,(PARAMS) ; GET ADDRESS OF FCB. + 056C 11 0E 00 1013 LD DE,#14 ; RELATIVE POSITION OF 'S2'. + 056F 19 1014 ADD HL,DE + 0570 7E 1015 LD A,(HL) ; EXTRACT THIS BYTE. + 0571 C9 1016 RET + 1017 ; + 1018 ; CLEAR THE 'S2' BYTE IN THE FCB. + 1019 ; + 0572 CDr69s05 1020 CLEARS2:CALL GETS2 ; THIS SETS (HL) POINTING TO IT. + 0575 36 00 1021 LD (HL),#0 ; NOW CLEAR IT. + 0577 C9 1022 RET + 1023 ; + 1024 ; SET BIT 7 IN THE 'S2' BYTE OF THE FCB. + 1025 ; + 0578 CDr69s05 1026 SETS2B7:CALL GETS2 ; GET THE BYTE. + 057B F6 80 1027 OR #0x80 ; AND SET BIT 7. + 057D 77 1028 LD (HL),A ; THEN STORE. + 057E C9 1029 RET + 1030 ; + 1031 ; COMPARE (FILEPOS) WITH (SCRATCH1) AND SET FLAGS BASED ON + 1032 ; THE DIFFERENCE. THIS CHECKS TO SEE IF THERE ARE MORE FILE + 1033 ; NAMES IN THE DIRECTORY. WE ARE AT (FILEPOS) AND THERE ARE + 1034 ; (SCRATCH1) OF THEM TO CHECK. + 1035 ; + 057F 2ArEAs0D 1036 MOREFLS:LD HL,(FILEPOS) ; WE ARE HERE. + 0582 EB 1037 EX DE,HL + 0583 2ArB3s0D 1038 LD HL,(SCRATCH1) ; AND DON'T GO PAST HERE. + 0586 7B 1039 LD A,E ; COMPUTE DIFFERENCE BUT DON'T KEEP. + 0587 96 1040 SUB (HL) + 0588 23 1041 INC HL + 0589 7A 1042 LD A,D + 058A 9E 1043 SBC A,(HL) ; SET CARRY IF NO MORE NAMES. + 058B C9 1044 RET + 1045 ; + 1046 ; CALL THIS ROUTINE TO PREVENT (SCRATCH1) FROM BEING GREATER + 1047 ; THAN (FILEPOS). + 1048 ; + 058C CDr7Fs05 1049 CHKNMBR:CALL MOREFLS ; SCRATCH1 TOO BIG? + 058F D8 1050 RET C + 0590 13 1051 INC DE ; YES, RESET IT TO (FILEPOS). + 0591 72 1052 LD (HL),D + 0592 2B 1053 DEC HL + 0593 73 1054 LD (HL),E + 0594 C9 1055 RET + 1056 ; + 1057 ; COMPUTE (HL)=(DE)-(HL) + 1058 ; + 0595 7B 1059 SUBHL: LD A,E ; COMPUTE DIFFERENCE. + 0596 95 1060 SUB L + 0597 6F 1061 LD L,A ; STORE LOW BYTE. + 0598 7A 1062 LD A,D + 0599 9C 1063 SBC A,H + 059A 67 1064 LD H,A ; AND THEN HIGH BYTE. + 059B C9 1065 RET + 1066 ; + 1067 ; SET THE DIRECTORY CHECKSUM BYTE. + 1068 ; + 059C 0E FF 1069 SETDIR: LD C,#0xFF + 1070 ; + 1071 ; ROUTINE TO SET OR COMPARE THE DIRECTORY CHECKSUM BYTE. IF + 1072 ; (C)=0FFH, THEN THIS WILL SET THE CHECKSUM BYTE. ELSE THE BYTE + 1073 ; WILL BE CHECKED. IF THE CHECK FAILS (THE DISK HAS BEEN CHANGED), + 1074 ; THEN THIS DISK WILL BE WRITE PROTECTED. + 1075 ; + 059E 1076 CHECKDIR: + 059E 2ArECs0D 1077 LD HL,(CKSUMTBL) + 05A1 EB 1078 EX DE,HL + 05A2 2ArCCs0D 1079 LD HL,(ALLOC1) + 05A5 CDr95s05 1080 CALL SUBHL + 05A8 D0 1081 RET NC ; OK IF (CKSUMTBL) > (ALLOC1), SO RETURN. + 05A9 C5 1082 PUSH BC + 05AA CDrF7s04 1083 CALL CHECKSUM ; ELSE COMPUTE CHECKSUM. + 05AD 2ArBDs0D 1084 LD HL,(CHKVECT) ; GET ADDRESS OF CHECKSUM TABLE. + 05B0 EB 1085 EX DE,HL + 05B1 2ArECs0D 1086 LD HL,(CKSUMTBL) + 05B4 19 1087 ADD HL,DE ; SET (HL) TO POINT TO BYTE FOR THIS DRIVE. + 05B5 C1 1088 POP BC + 05B6 0C 1089 INC C ; SET OR CHECK ? + 05B7 CArC4s05 1090 JP Z,CHKDIR1 + 05BA BE 1091 CP (HL) ; CHECK THEM. + 05BB C8 1092 RET Z ; RETURN IF THEY ARE THE SAME. + 05BC CDr7Fs05 1093 CALL MOREFLS ; NOT THE SAME, DO WE CARE? + 05BF D0 1094 RET NC + 05C0 CDr2Cs05 1095 CALL WRTPRTD ; YES, MARK THIS AS WRITE PROTECTED. + 05C3 C9 1096 RET + 05C4 77 1097 CHKDIR1:LD (HL),A ; JUST SET THE BYTE. + 05C5 C9 1098 RET + 1099 ; + 1100 ; DO A WRITE TO THE DIRECTORY OF THE CURRENT DISK. + 1101 ; + 05C6 1102 DIRWRITE: + 05C6 CDr9Cs05 1103 CALL SETDIR ; SET CHECKSUM BYTE. + 05C9 CDrE0s05 1104 CALL DIRDMA ; SET DIRECTORY DMA ADDRESS. + 05CC 0E 01 1105 LD C,#1 ; TELL THE BIOS TO ACTUALLY WRITE. + 05CE CDrB8s03 1106 CALL DOWRITE ; THEN DO THE WRITE. + 05D1 C3rDAs05 1107 JP DEFDMA + 1108 ; + 1109 ; READ FROM THE DIRECTORY. + 1110 ; + 05D4 CDrE0s05 1111 DIRREAD:CALL DIRDMA ; SET THE DIRECTORY DMA ADDRESS. + 05D7 CDrB2s03 1112 CALL DOREAD ; AND READ IT. + 1113 ; + 1114 ; ROUTINE TO SET THE DMA ADDRESS TO THE USERS CHOICE. + 1115 ; + 05DA 21rB1s0D 1116 DEFDMA: LD HL,#USERDMA ; RESET THE DEFAULT DMA ADDRESS AND RETURN. + 05DD C3rE3s05 1117 JP DIRDMA1 + 1118 ; + 1119 ; ROUTINE TO SET THE DMA ADDRESS FOR DIRECTORY WORK. + 1120 ; + 05E0 21rB9s0D 1121 DIRDMA: LD HL,#DIRBUF + 1122 ; + 1123 ; SET THE DMA ADDRESS. ON ENTRY, (HL) POINTS TO + 1124 ; WORD CONTAINING THE DESIRED DMA ADDRESS. + 1125 ; + 05E3 4E 1126 DIRDMA1:LD C,(HL) + 05E4 23 1127 INC HL + 05E5 46 1128 LD B,(HL) ; SETUP (BC) AND GO TO THE BIOS TO SET IT. + 05E6 C3 24 E6 1129 JP SETDMA + 1130 ; + 1131 ; MOVE THE DIRECTORY BUFFER INTO USER'S DMA SPACE. + 1132 ; + 05E9 2ArB9s0D 1133 MOVEDIR:LD HL,(DIRBUF) ; BUFFER IS LOCATED HERE, AND + 05EC EB 1134 EX DE,HL + 05ED 2ArB1s0D 1135 LD HL,(USERDMA) ; PUT IT HERE. + 05F0 0E 80 1136 LD C,#128 ; THIS IS ITS LENGTH. + 05F2 C3r4Fs03 1137 JP DE2HL ; MOVE IT NOW AND RETURN. + 1138 ; + 1139 ; CHECK (FILEPOS) AND SET THE ZERO FLAG IF IT .EQUALS 0FFFFH. + 1140 ; + 05F5 1141 CKFILPOS: + 05F5 21rEAs0D 1142 LD HL,#FILEPOS + 05F8 7E 1143 LD A,(HL) + 05F9 23 1144 INC HL + 05FA BE 1145 CP (HL) ; ARE BOTH BYTES THE SAME? + 05FB C0 1146 RET NZ + 05FC 3C 1147 INC A ; YES, BUT ARE THEY EACH 0FFH? + 05FD C9 1148 RET + 1149 ; + 1150 ; SET LOCATION (FILEPOS) TO 0FFFFH. + 1151 ; + 05FE 1152 STFILPOS: + 05FE 21 FF FF 1153 LD HL,#0x0FFFF + 0601 22rEAs0D 1154 LD (FILEPOS),HL + 0604 C9 1155 RET + 1156 ; + 1157 ; MOVE ON TO THE NEXT FILE POSITION WITHIN THE CURRENT + 1158 ; DIRECTORY BUFFER. IF NO MORE EXIST, SET POINTER TO 0FFFFH + 1159 ; AND THE CALLING ROUTINE WILL CHECK FOR THIS. ENTER WITH (C) + 1160 ; .EQUAL TO 0FFH TO CAUSE THE CHECKSUM BYTE TO BE SET, ELSE WE + 1161 ; WILL CHECK THIS DISK AND SET WRITE PROTECT IF CHECKSUMS ARE + 1162 ; NOT THE SAME (APPLIES ONLY IF ANOTHER DIRECTORY SECTOR MUST + 1163 ; BE READ). + 1164 ; + 0605 2ArC8s0D 1165 NXENTRY:LD HL,(DIRSIZE) ; GET DIRECTORY ENTRY SIZE LIMIT. + 0608 EB 1166 EX DE,HL + 0609 2ArEAs0D 1167 LD HL,(FILEPOS) ; GET CURRENT COUNT. + 060C 23 1168 INC HL ; GO ON TO THE NEXT ONE. + 060D 22rEAs0D 1169 LD (FILEPOS),HL + 0610 CDr95s05 1170 CALL SUBHL ; (HL)=(DIRSIZE)-(FILEPOS) + 0613 D2r19s06 1171 JP NC,NXENT1 ; IS THERE MORE ROOM LEFT? + 0616 C3rFEs05 1172 JP STFILPOS ; NO. SET THIS FLAG AND RETURN. + 0619 3ArEAs0D 1173 NXENT1: LD A,(FILEPOS) ; GET FILE POSITION WITHIN DIRECTORY. + 061C E6 03 1174 AND #3 ; ONLY LOOK WITHIN THIS SECTOR (ONLY 4 ENTRIES FIT). + 061E 06 05 1175 LD B,#5 ; CONVERT TO RELATIVE POSITION (32 BYTES EACH). + 0620 87 1176 NXENT2: ADD A,A ; NOTE THAT THIS IS NOT EFFICIENT CODE. + 0621 05 1177 DEC B ; 5 'ADD A'S WOULD BE BETTER. + 0622 C2r20s06 1178 JP NZ,NXENT2 + 0625 32rE9s0D 1179 LD (FCBPOS),A ; SAVE IT AS POSITION OF FCB. + 0628 B7 1180 OR A + 0629 C0 1181 RET NZ ; RETURN IF WE ARE WITHIN BUFFER. + 062A C5 1182 PUSH BC + 062B CDrC3s03 1183 CALL TRKSEC ; WE NEED THE NEXT DIRECTORY SECTOR. + 062E CDrD4s05 1184 CALL DIRREAD + 0631 C1 1185 POP BC + 0632 C3r9Es05 1186 JP CHECKDIR + 1187 ; + 1188 ; ROUTINE TO TO GET A BIT FROM THE DISK SPACE ALLOCATION + 1189 ; MAP. IT IS RETURNED IN (A), BIT POSITION 0. ON ENTRY TO HERE, + 1190 ; SET (BC) TO THE BLOCK NUMBER ON THE DISK TO CHECK. + 1191 ; ON RETURN, (D) WILL CONTAIN THE ORIGINAL BIT POSITION FOR + 1192 ; THIS BLOCK NUMBER AND (HL) WILL POINT TO THE ADDRESS FOR IT. + 1193 ; + 0635 1194 CKBITMAP: + 0635 79 1195 LD A,C ; DETERMINE BIT NUMBER OF INTEREST. + 0636 E6 07 1196 AND #7 ; COMPUTE (D)=(E)=(C AND 7)+1. + 0638 3C 1197 INC A + 0639 5F 1198 LD E,A ; SAVE PARTICULAR BIT NUMBER. + 063A 57 1199 LD D,A + 1200 ; + 1201 ; COMPUTE (BC)=(BC)/8. + 1202 ; + 063B 79 1203 LD A,C + 063C 0F 1204 RRCA ; NOW SHIFT RIGHT 3 BITS. + 063D 0F 1205 RRCA + 063E 0F 1206 RRCA + 063F E6 1F 1207 AND #0x1F ; AND CLEAR BITS 7,6,5. + 0641 4F 1208 LD C,A + 0642 78 1209 LD A,B + 0643 87 1210 ADD A,A ; NOW SHIFT (B) INTO BITS 7,6,5. + 0644 87 1211 ADD A,A + 0645 87 1212 ADD A,A + 0646 87 1213 ADD A,A + 0647 87 1214 ADD A,A + 0648 B1 1215 OR C ; AND ADD IN (C). + 0649 4F 1216 LD C,A ; OK, (C) HA BEEN COMPLETED. + 064A 78 1217 LD A,B ; IS THERE A BETTER WAY OF DOING THIS? + 064B 0F 1218 RRCA + 064C 0F 1219 RRCA + 064D 0F 1220 RRCA + 064E E6 1F 1221 AND #0x1F + 0650 47 1222 LD B,A ; AND NOW (B) IS COMPLETED. + 1223 ; + 1224 ; USE THIS AS AN OFFSET INTO THE DISK SPACE ALLOCATION + 1225 ; TABLE. + 1226 ; + 0651 2ArBFs0D 1227 LD HL,(ALOCVECT) + 0654 09 1228 ADD HL,BC + 0655 7E 1229 LD A,(HL) ; NOW GET CORRECT BYTE. + 0656 07 1230 CKBMAP1:RLCA ; GET CORRECT BIT INTO POSITION 0. + 0657 1D 1231 DEC E + 0658 C2r56s06 1232 JP NZ,CKBMAP1 + 065B C9 1233 RET + 1234 ; + 1235 ; SET OR CLEAR THE BIT MAP SUCH THAT BLOCK NUMBER (BC) WILL BE MARKED + 1236 ; AS USED. ON ENTRY, IF (E)=0 THEN THIS BIT WILL BE CLEARED, IF IT .EQUALS + 1237 ; 1 THEN IT WILL BE SET (DON'T USE ANYOTHER VALUES). + 1238 ; + 065C 1239 STBITMAP: + 065C D5 1240 PUSH DE + 065D CDr35s06 1241 CALL CKBITMAP ; GET THE BYTE OF INTEREST. + 0660 E6 FE 1242 AND #0x0FE ; CLEAR THE AFFECTED BIT. + 0662 C1 1243 POP BC + 0663 B1 1244 OR C ; AND NOW SET IT ACORDING TO (C). + 1245 ; + 1246 ; ENTRY TO RESTORE THE ORIGINAL BIT POSITION AND THEN STORE + 1247 ; IN TABLE. (A) CONTAINS THE VALUE, (D) CONTAINS THE BIT + 1248 ; POSITION (1-8), AND (HL) POINTS TO THE ADDRESS WITHIN THE + 1249 ; SPACE ALLOCATION TABLE FOR THIS BYTE. + 1250 ; + 0664 0F 1251 STBMAP1:RRCA ; RESTORE ORIGINAL BIT POSITION. + 0665 15 1252 DEC D + 0666 C2r64s06 1253 JP NZ,STBMAP1 + 0669 77 1254 LD (HL),A ; AND STOR BYTE IN TABLE. + 066A C9 1255 RET + 1256 ; + 1257 ; SET/CLEAR SPACE USED BITS IN ALLOCATION MAP FOR THIS FILE. + 1258 ; ON ENTRY, (C)=1 TO SET THE MAP AND (C)=0 TO CLEAR IT. + 1259 ; + 066B CDr5Es05 1260 SETFILE:CALL FCB2HL ; GET ADDRESS OF FCB + 066E 11 10 00 1261 LD DE,#16 + 0671 19 1262 ADD HL,DE ; GET TO BLOCK NUMBER BYTES. + 0672 C5 1263 PUSH BC + 0673 0E 11 1264 LD C,#17 ; CHECK ALL 17 BYTES (MAX) OF TABLE. + 0675 D1 1265 SETFL1: POP DE + 0676 0D 1266 DEC C ; DONE ALL BYTES YET? + 0677 C8 1267 RET Z + 0678 D5 1268 PUSH DE + 0679 3ArDDs0D 1269 LD A,(BIGDISK) ; CHECK DISK SIZE FOR 16 BIT BLOCK NUMBERS. + 067C B7 1270 OR A + 067D CAr88s06 1271 JP Z,SETFL2 + 0680 C5 1272 PUSH BC ; ONLY 8 BIT NUMBERS. SET (BC) TO THIS ONE. + 0681 E5 1273 PUSH HL + 0682 4E 1274 LD C,(HL) ; GET LOW BYTE FROM TABLE, ALWAYS + 0683 06 00 1275 LD B,#0 ; SET HIGH BYTE TO ZERO. + 0685 C3r8Es06 1276 JP SETFL3 + 0688 0D 1277 SETFL2: DEC C ; FOR 16 BIT BLOCK NUMBERS, ADJUST COUNTER. + 0689 C5 1278 PUSH BC + 068A 4E 1279 LD C,(HL) ; NOW GET BOTH THE LOW AND HIGH BYTES. + 068B 23 1280 INC HL + 068C 46 1281 LD B,(HL) + 068D E5 1282 PUSH HL + 068E 79 1283 SETFL3: LD A,C ; BLOCK USED? + 068F B0 1284 OR B + 0690 CAr9Ds06 1285 JP Z,SETFL4 + 0693 2ArC6s0D 1286 LD HL,(DSKSIZE) ; IS THIS BLOCK NUMBER WITHIN THE + 0696 7D 1287 LD A,L ; SPACE ON THE DISK? + 0697 91 1288 SUB C + 0698 7C 1289 LD A,H + 0699 98 1290 SBC A,B + 069A D4r5Cs06 1291 CALL NC,STBITMAP ; YES, SET THE PROPER BIT. + 069D E1 1292 SETFL4: POP HL ; POINT TO NEXT BLOCK NUMBER IN FCB. + 069E 23 1293 INC HL + 069F C1 1294 POP BC + 06A0 C3r75s06 1295 JP SETFL1 + 1296 ; + 1297 ; CONSTRUCT THE SPACE USED ALLOCATION BIT MAP FOR THE ACTIVE + 1298 ; DRIVE. IF A FILE NAME STARTS WITH '$' AND IT IS UNDER THE + 1299 ; CURRENT USER NUMBER, THEN (STATUS) IS SET TO MINUS 1. OTHERWISE + 1300 ; IT IS NOT SET AT ALL. + 1301 ; + 06A3 2ArC6s0D 1302 BITMAP: LD HL,(DSKSIZE) ; COMPUTE SIZE OF ALLOCATION TABLE. + 06A6 0E 03 1303 LD C,#3 + 06A8 CDrEAs04 1304 CALL SHIFTR ; (HL)=(HL)/8. + 06AB 23 1305 INC HL ; AT LEASE 1 BYTE. + 06AC 44 1306 LD B,H + 06AD 4D 1307 LD C,L ; SET (BC) TO THE ALLOCATION TABLE LENGTH. + 1308 ; + 1309 ; INITIALIZE THE BITMAP FOR THIS DRIVE. RIGHT NOW, THE FIRST + 1310 ; TWO BYTES ARE SPECIFIED BY THE DISK PARAMETER BLOCK. HOWEVER + 1311 ; A PATCH COULD BE ENTERED HERE IF IT WERE NECESSARY TO SETUP + 1312 ; THIS TABLE IN A SPECIAL MANNOR. FOR EXAMPLE, THE BIOS COULD + 1313 ; DETERMINE LOCATIONS OF 'BAD BLOCKS' AND SET THEM AS ALREADY + 1314 ; 'USED' IN THE MAP. + 1315 ; + 06AE 2ArBFs0D 1316 LD HL,(ALOCVECT) ; NOW ZERO OUT THE TABLE NOW. + 06B1 36 00 1317 BITMAP1:LD (HL),#0 + 06B3 23 1318 INC HL + 06B4 0B 1319 DEC BC + 06B5 78 1320 LD A,B + 06B6 B1 1321 OR C + 06B7 C2rB1s06 1322 JP NZ,BITMAP1 + 06BA 2ArCAs0D 1323 LD HL,(ALLOC0) ; GET INITIAL SPACE USED BY DIRECTORY. + 06BD EB 1324 EX DE,HL + 06BE 2ArBFs0D 1325 LD HL,(ALOCVECT) ; AND PUT THIS INTO MAP. + 06C1 73 1326 LD (HL),E + 06C2 23 1327 INC HL + 06C3 72 1328 LD (HL),D + 1329 ; + 1330 ; END OF INITIALIZATION PORTION. + 1331 ; + 06C4 CDrA1s03 1332 CALL HOMEDRV ; NOW HOME THE DRIVE. + 06C7 2ArB3s0D 1333 LD HL,(SCRATCH1) + 06CA 36 03 1334 LD (HL),#3 ; FORCE NEXT DIRECTORY R.EQUEST TO READ + 06CC 23 1335 INC HL ; IN A SECTOR. + 06CD 36 00 1336 LD (HL),#0 + 06CF CDrFEs05 1337 CALL STFILPOS ; CLEAR INITIAL FILE POSITION ALSO. + 06D2 0E FF 1338 BITMAP2:LD C,#0x0FF ; READ NEXT FILE NAME IN DIRECTORY + 06D4 CDr05s06 1339 CALL NXENTRY ; AND SET CHECKSUM BYTE. + 06D7 CDrF5s05 1340 CALL CKFILPOS ; IS THERE ANOTHER FILE? + 06DA C8 1341 RET Z + 06DB CDr5Es05 1342 CALL FCB2HL ; YES, GET ITS ADDRESS. + 06DE 3E E5 1343 LD A,#0x0E5 + 06E0 BE 1344 CP (HL) ; EMPTY FILE ENTRY? + 06E1 CArD2s06 1345 JP Z,BITMAP2 + 06E4 3Ar41s03 1346 LD A,(USERNO) ; NO, CORRECT USER NUMBER? + 06E7 BE 1347 CP (HL) + 06E8 C2rF6s06 1348 JP NZ,BITMAP3 + 06EB 23 1349 INC HL + 06EC 7E 1350 LD A,(HL) ; YES, DOES NAME START WITH A '$'? + 06ED D6 24 1351 SUB #DOLLAR + 06EF C2rF6s06 1352 JP NZ,BITMAP3 + 06F2 3D 1353 DEC A ; YES, SET ATATUS TO MINUS ONE. + 06F3 32r45s03 1354 LD (STATUS),A + 06F6 0E 01 1355 BITMAP3:LD C,#1 ; NOW SET THIS FILE'S SPACE AS USED IN BIT MAP. + 06F8 CDr6Bs06 1356 CALL SETFILE + 06FB CDr8Cs05 1357 CALL CHKNMBR ; KEEP (SCRATCH1) IN BOUNDS. + 06FE C3rD2s06 1358 JP BITMAP2 + 1359 ; + 1360 ; SET THE STATUS (STATUS) AND RETURN. + 1361 ; + 0701 1362 STSTATUS: + 0701 3ArD4s0D 1363 LD A,(FNDSTAT) + 0704 C3r01s03 1364 JP SETSTAT + 1365 ; + 1366 ; CHECK EXTENTS IN (A) AND (C). SET THE ZERO FLAG IF THEY + 1367 ; ARE THE SAME. THE NUMBER OF 16K CHUNKS OF DISK SPACE THAT + 1368 ; THE DIRECTORY EXTENT COVERS IS EXPRESSAD IS (EXTMASK+1). + 1369 ; NO REGISTERS ARE MODIFIED. + 1370 ; + 0707 C5 1371 SAMEXT: PUSH BC + 0708 F5 1372 PUSH AF + 0709 3ArC5s0D 1373 LD A,(EXTMASK) ; GET EXTENT MASK AND USE IT TO + 070C 2F 1374 CPL ; TO COMPARE BOTH EXTENT NUMBERS. + 070D 47 1375 LD B,A ; SAVE RESULTING MASK HERE. + 070E 79 1376 LD A,C ; MASK FIRST EXTENT AND SAVE IN (C). + 070F A0 1377 AND B + 0710 4F 1378 LD C,A + 0711 F1 1379 POP AF ; NOW MASK SECOND EXTENT AND COMPARE + 0712 A0 1380 AND B ; WITH THE FIRST ONE. + 0713 91 1381 SUB C + 0714 E6 1F 1382 AND #0x1F ; (* ONLY CHECK BUTS 0-4 *) + 0716 C1 1383 POP BC ; THE ZERO FLAG IS SET IF THEY ARE THE SAME. + 0717 C9 1384 RET ; RESTORE (BC) AND RETURN. + 1385 ; + 1386 ; SEARCH FOR THE FIRST OCCURENCE OF A FILE NAME. ON ENTRY, + 1387 ; REGISTER (C) SHOULD CONTAIN THE NUMBER OF BYTES OF THE FCB + 1388 ; THAT MUST MATCH. + 1389 ; + 0718 3E FF 1390 FINDFST:LD A,#0x0FF + 071A 32rD4s0D 1391 LD (FNDSTAT),A + 071D 21rD8s0D 1392 LD HL,#COUNTER ; SAVE CHARACTER COUNT. + 0720 71 1393 LD (HL),C + 0721 2Ar43s03 1394 LD HL,(PARAMS) ; GET FILENAME TO MATCH. + 0724 22rD9s0D 1395 LD (SAVEFCB),HL ; AND SAVE. + 0727 CDrFEs05 1396 CALL STFILPOS ; CLEAR INITIAL FILE POSITION (SET TO 0FFFFH). + 072A CDrA1s03 1397 CALL HOMEDRV ; HOME THE DRIVE. + 1398 ; + 1399 ; ENTRY TO LOCATE THE NEXT OCCURENCE OF A FILENAME WITHIN THE + 1400 ; DIRECTORY. THE DISK IS NOT EXPECTED TO HAVE BEEN CHANGED. IF + 1401 ; IT WAS, THEN IT WILL BE WRITE PROTECTED. + 1402 ; + 072D 0E 00 1403 FINDNXT:LD C,#0 ; WRITE PROTECT THE DISK IF CHANGED. + 072F CDr05s06 1404 CALL NXENTRY ; GET NEXT FILENAME ENTRY IN DIRECTORY. + 0732 CDrF5s05 1405 CALL CKFILPOS ; IS FILE POSITION = 0FFFFH? + 0735 CAr94s07 1406 JP Z,FNDNXT6 ; YES, EXIT NOW THEN. + 0738 2ArD9s0D 1407 LD HL,(SAVEFCB) ; SET (DE) POINTING TO FILENAME TO MATCH. + 073B EB 1408 EX DE,HL + 073C 1A 1409 LD A,(DE) + 073D FE E5 1410 CP #0x0E5 ; EMPTY DIRECTORY ENTRY? + 073F CAr4As07 1411 JP Z,FNDNXT1 ; (* ARE WE TRYING TO RESERECT ERASED ENTRIES? *) + 0742 D5 1412 PUSH DE + 0743 CDr7Fs05 1413 CALL MOREFLS ; MORE FILES IN DIRECTORY? + 0746 D1 1414 POP DE + 0747 D2r94s07 1415 JP NC,FNDNXT6 ; NO MORE. EXIT NOW. + 074A CDr5Es05 1416 FNDNXT1:CALL FCB2HL ; GET ADDRESS OF THIS FCB IN DIRECTORY. + 074D 3ArD8s0D 1417 LD A,(COUNTER) ; GET NUMBER OF BYTES (CHARACTERS) TO CHECK. + 0750 4F 1418 LD C,A + 0751 06 00 1419 LD B,#0 ; INITIALIZE BYTE POSITION COUNTER. + 0753 79 1420 FNDNXT2:LD A,C ; ARE WE DONE WITH THE COMPARE? + 0754 B7 1421 OR A + 0755 CAr83s07 1422 JP Z,FNDNXT5 + 0758 1A 1423 LD A,(DE) ; NO, CHECK NEXT BYTE. + 0759 FE 3F 1424 CP #QUESTION ; DON'T CARE ABOUT THIS CHARACTER? + 075B CAr7Cs07 1425 JP Z,FNDNXT4 + 075E 78 1426 LD A,B ; GET BYTES POSITION IN FCB. + 075F FE 0D 1427 CP #13 ; DON'T CARE ABOUT THE THIRTEENTH BYTE EITHER. + 0761 CAr7Cs07 1428 JP Z,FNDNXT4 + 0764 FE 0C 1429 CP #12 ; EXTENT BYTE? + 0766 1A 1430 LD A,(DE) + 0767 CAr73s07 1431 JP Z,FNDNXT3 + 076A 96 1432 SUB (HL) ; OTHERWISE COMPARE CHARACTERS. + 076B E6 7F 1433 AND #0x7F + 076D C2r2Ds07 1434 JP NZ,FINDNXT ; NOT THE SAME, CHECK NEXT ENTRY. + 0770 C3r7Cs07 1435 JP FNDNXT4 ; SO FAR SO GOOD, KEEP CHECKING. + 0773 C5 1436 FNDNXT3:PUSH BC ; CHECK THE EXTENT BYTE HERE. + 0774 4E 1437 LD C,(HL) + 0775 CDr07s07 1438 CALL SAMEXT + 0778 C1 1439 POP BC + 0779 C2r2Ds07 1440 JP NZ,FINDNXT ; NOT THE SAME, LOOK SOME MORE. + 1441 ; + 1442 ; SO FAR THE NAMES COMPARE. BUMP POINTERS TO THE NEXT BYTE + 1443 ; AND CONTINUE UNTIL ALL (C) CHARACTERS HAVE BEEN CHECKED. + 1444 ; + 077C 13 1445 FNDNXT4:INC DE ; BUMP POINTERS. + 077D 23 1446 INC HL + 077E 04 1447 INC B + 077F 0D 1448 DEC C ; ADJUST CHARACTER COUNTER. + 0780 C3r53s07 1449 JP FNDNXT2 + 0783 3ArEAs0D 1450 FNDNXT5:LD A,(FILEPOS) ; RETURN THE POSITION OF THIS ENTRY. + 0786 E6 03 1451 AND #3 + 0788 32r45s03 1452 LD (STATUS),A + 078B 21rD4s0D 1453 LD HL,#FNDSTAT + 078E 7E 1454 LD A,(HL) + 078F 17 1455 RLA + 0790 D0 1456 RET NC + 0791 AF 1457 XOR A + 0792 77 1458 LD (HL),A + 0793 C9 1459 RET + 1460 ; + 1461 ; FILENAME WAS NOT FOUND. SET APPROPRIATE STATUS. + 1462 ; + 0794 CDrFEs05 1463 FNDNXT6:CALL STFILPOS ; SET (FILEPOS) TO 0FFFFH. + 0797 3E FF 1464 LD A,#0x0FF ; SAY NOT LOCATED. + 0799 C3r01s03 1465 JP SETSTAT + 1466 ; + 1467 ; ERASE FILES FROM THE DIRECTORY. ONLY THE FIRST BYTE OF THE + 1468 ; FCB WILL BE AFFECTED. IT IS SET TO (E5). + 1469 ; + 079C CDr54s05 1470 ERAFILE:CALL CHKWPRT ; IS DISK WRITE PROTECTED? + 079F 0E 0C 1471 LD C,#12 ; ONLY COMPARE FILE NAMES. + 07A1 CDr18s07 1472 CALL FINDFST ; GET FIRST FILE NAME. + 07A4 CDrF5s05 1473 ERAFIL1:CALL CKFILPOS ; ANY FOUND? + 07A7 C8 1474 RET Z ; NOPE, WE MUST BE DONE. + 07A8 CDr44s05 1475 CALL CHKROFL ; IS FILE READ ONLY? + 07AB CDr5Es05 1476 CALL FCB2HL ; NOPE, GET ADDRESS OF FCB AND + 07AE 36 E5 1477 LD (HL),#0x0E5 ; SET FIRST BYTE TO 'EMPTY'. + 07B0 0E 00 1478 LD C,#0 ; CLEAR THE SPACE FROM THE BIT MAP. + 07B2 CDr6Bs06 1479 CALL SETFILE + 07B5 CDrC6s05 1480 CALL DIRWRITE ; NOW WRITE THE DIRECTORY SECTOR BACK OUT. + 07B8 CDr2Ds07 1481 CALL FINDNXT ; FIND THE NEXT FILE NAME. + 07BB C3rA4s07 1482 JP ERAFIL1 ; AND REPEAT PROCESS. + 1483 ; + 1484 ; LOOK THROUGH THE SPACE ALLOCATION MAP (BIT MAP) FOR THE + 1485 ; NEXT AVAILABLE BLOCK. START SEARCHING AT BLOCK NUMBER (BC-1). + 1486 ; THE SEARCH PROCEDURE IS TO LOOK FOR AN EMPTY BLOCK THAT IS + 1487 ; BEFORE THE STARTING BLOCK. IF NOT EMPTY, LOOK AT A LATER + 1488 ; BLOCK NUMBER. IN THIS WAY, WE RETURN THE CLOSEST EMPTY BLOCK + 1489 ; ON EITHER SIDE OF THE 'TARGET' BLOCK NUMBER. THIS WILL SPEED + 1490 ; ACCESS ON RANDOM DEVICES. FOR SERIAL DEVICES, THIS SHOULD BE + 1491 ; CHANGED TO LOOK IN THE FORWARD DIRECTION FIRST AND THEN START + 1492 ; AT THE FRONT AND SEARCH SOME MORE. + 1493 ; + 1494 ; ON RETURN, (DE)= BLOCK NUMBER THAT IS EMPTY AND (HL) =0 + 1495 ; IF NO EMPRY BLOCK WAS FOUND. + 1496 ; + 07BE 1497 FNDSPACE: + 07BE 50 1498 LD D,B ; SET (DE) AS THE BLOCK THAT IS CHECKED. + 07BF 59 1499 LD E,C + 1500 ; + 1501 ; LOOK BEFORE TARGET BLOCK. REGISTERS (BC) ARE USED AS THE LOWER + 1502 ; POINTER AND (DE) AS THE UPPER POINTER. + 1503 ; + 07C0 79 1504 FNDSPA1:LD A,C ; IS BLOCK 0 SPECIFIED? + 07C1 B0 1505 OR B + 07C2 CArD1s07 1506 JP Z,FNDSPA2 + 07C5 0B 1507 DEC BC ; NOPE, CHECK PREVIOUS BLOCK. + 07C6 D5 1508 PUSH DE + 07C7 C5 1509 PUSH BC + 07C8 CDr35s06 1510 CALL CKBITMAP + 07CB 1F 1511 RRA ; IS THIS BLOCK EMPTY? + 07CC D2rECs07 1512 JP NC,FNDSPA3 ; YES. USE THIS. + 1513 ; + 1514 ; NOTE THAT THE ABOVE LOGIC GETS THE FIRST BLOCK THAT IT FINDS + 1515 ; THAT IS EMPTY. THUS A FILE COULD BE WRITTEN 'BACKWARD' MAKING + 1516 ; IT VERY SLOW TO ACCESS. THIS COULD BE CHANGED TO LOOK FOR THE + 1517 ; FIRST EMPTY BLOCK AND THEN CONTINUE UNTIL THE START OF THIS + 1518 ; EMPTY SPACE IS LOCATED AND THEN USED THAT STARTING BLOCK. + 1519 ; THIS SHOULD HELP SPEED UP ACCESS TO SOME FILES ESPECIALLY ON + 1520 ; A WELL USED DISK WITH LOTS OF FAIRLY SMALL 'HOLES'. + 1521 ; + 07CF C1 1522 POP BC ; NOPE, CHECK SOME MORE. + 07D0 D1 1523 POP DE + 1524 ; + 1525 ; NOW LOOK AFTER TARGET BLOCK. + 1526 ; + 07D1 2ArC6s0D 1527 FNDSPA2:LD HL,(DSKSIZE) ; IS BLOCK (DE) WITHIN DISK LIMITS? + 07D4 7B 1528 LD A,E + 07D5 95 1529 SUB L + 07D6 7A 1530 LD A,D + 07D7 9C 1531 SBC A,H + 07D8 D2rF4s07 1532 JP NC,FNDSPA4 + 07DB 13 1533 INC DE ; YES, MOVE ON TO NEXT ONE. + 07DC C5 1534 PUSH BC + 07DD D5 1535 PUSH DE + 07DE 42 1536 LD B,D + 07DF 4B 1537 LD C,E + 07E0 CDr35s06 1538 CALL CKBITMAP ; CHECK IT. + 07E3 1F 1539 RRA ; EMPTY? + 07E4 D2rECs07 1540 JP NC,FNDSPA3 + 07E7 D1 1541 POP DE ; NOPE, CONTINUE SEARCHING. + 07E8 C1 1542 POP BC + 07E9 C3rC0s07 1543 JP FNDSPA1 + 1544 ; + 1545 ; EMPTY BLOCK FOUND. SET IT AS USED AND RETURN WITH (HL) + 1546 ; POINTING TO IT (TRUE?). + 1547 ; + 07EC 17 1548 FNDSPA3:RLA ; RESET BYTE. + 07ED 3C 1549 INC A ; AND SET BIT 0. + 07EE CDr64s06 1550 CALL STBMAP1 ; UPDATE BIT MAP. + 07F1 E1 1551 POP HL ; SET RETURN REGISTERS. + 07F2 D1 1552 POP DE + 07F3 C9 1553 RET + 1554 ; + 1555 ; FREE BLOCK WAS NOT FOUND. IF (BC) IS NOT ZERO, THEN WE HAVE + 1556 ; NOT CHECKED ALL OF THE DISK SPACE. + 1557 ; + 07F4 79 1558 FNDSPA4:LD A,C + 07F5 B0 1559 OR B + 07F6 C2rC0s07 1560 JP NZ,FNDSPA1 + 07F9 21 00 00 1561 LD HL,#0 ; SET 'NOT FOUND' STATUS. + 07FC C9 1562 RET + 1563 ; + 1564 ; MOVE A COMPLETE FCB ENTRY INTO THE DIRECTORY AND WRITE IT. + 1565 ; + 07FD 0E 00 1566 FCBSET: LD C,#0 + 07FF 1E 20 1567 LD E,#32 ; LENGTH OF EACH ENTRY. + 1568 ; + 1569 ; MOVE (E) BYTES FROM THE FCB POINTED TO BY (PARAMS) INTO + 1570 ; FCB IN DIRECTORY STARTING AT RELATIVE BYTE (C). THIS UPDATED + 1571 ; DIRECTORY BUFFER IS THEN WRITTEN TO THE DISK. + 1572 ; + 0801 D5 1573 UPDATE: PUSH DE + 0802 06 00 1574 LD B,#0 ; SET (BC) TO RELATIVE BYTE POSITION. + 0804 2Ar43s03 1575 LD HL,(PARAMS) ; GET ADDRESS OF FCB. + 0807 09 1576 ADD HL,BC ; COMPUTE STARTING BYTE. + 0808 EB 1577 EX DE,HL + 0809 CDr5Es05 1578 CALL FCB2HL ; GET ADDRESS OF FCB TO UPDATE IN DIRECTORY. + 080C C1 1579 POP BC ; SET (C) TO NUMBER OF BYTES TO CHANGE. + 080D CDr4Fs03 1580 CALL DE2HL + 0810 CDrC3s03 1581 UPDATE1:CALL TRKSEC ; DETERMINE THE TRACK AND SECTOR AFFECTED. + 0813 C3rC6s05 1582 JP DIRWRITE ; THEN WRITE THIS SECTOR OUT. + 1583 ; + 1584 ; ROUTINE TO CHANGE THE NAME OF ALL FILES ON THE DISK WITH A + 1585 ; SPECIFIED NAME. THE FCB CONTAINS THE CURRENT NAME AS THE + 1586 ; FIRST 12 CHARACTERS AND THE NEW NAME 16 BYTES INTO THE FCB. + 1587 ; + 0816 1588 CHGNAMES: + 0816 CDr54s05 1589 CALL CHKWPRT ; CHECK FOR A WRITE PROTECTED DISK. + 0819 0E 0C 1590 LD C,#12 ; MATCH FIRST 12 BYTES OF FCB ONLY. + 081B CDr18s07 1591 CALL FINDFST ; GET FIRST NAME. + 081E 2Ar43s03 1592 LD HL,(PARAMS) ; GET ADDRESS OF FCB. + 0821 7E 1593 LD A,(HL) ; GET USER NUMBER. + 0822 11 10 00 1594 LD DE,#16 ; MOVE OVER TO DESIRED NAME. + 0825 19 1595 ADD HL,DE + 0826 77 1596 LD (HL),A ; KEEP SAME USER NUMBER. + 0827 CDrF5s05 1597 CHGNAM1:CALL CKFILPOS ; ANY MATCHING FILE FOUND? + 082A C8 1598 RET Z ; NO, WE MUST BE DONE. + 082B CDr44s05 1599 CALL CHKROFL ; CHECK FOR READ ONLY FILE. + 082E 0E 10 1600 LD C,#16 ; START 16 BYTES INTO FCB. + 0830 1E 0C 1601 LD E,#12 ; AND UPDATE THE FIRST 12 BYTES OF DIRECTORY. + 0832 CDr01s08 1602 CALL UPDATE + 0835 CDr2Ds07 1603 CALL FINDNXT ; GET TE NEXT FILE NAME. + 0838 C3r27s08 1604 JP CHGNAM1 ; AND CONTINUE. + 1605 ; + 1606 ; UPDATE A FILES ATTRIBUTES. THE PROCEDURE IS TO SEARCH FOR + 1607 ; EVERY FILE WITH THE SAME NAME AS SHOWN IN FCB (IGNORING BIT 7) + 1608 ; AND THEN TO UPDATE IT (WHICH INCLUDES BIT 7). NO OTHER CHANGES + 1609 ; ARE MADE. + 1610 ; + 083B 1611 SAVEATTR: + 083B 0E 0C 1612 LD C,#12 ; MATCH FIRST 12 BYTES. + 083D CDr18s07 1613 CALL FINDFST ; LOOK FOR FIRST FILENAME. + 0840 CDrF5s05 1614 SAVATR1:CALL CKFILPOS ; WAS ONE FOUND? + 0843 C8 1615 RET Z ; NOPE, WE MUST BE DONE. + 0844 0E 00 1616 LD C,#0 ; YES, UPDATE THE FIRST 12 BYTES NOW. + 0846 1E 0C 1617 LD E,#12 + 0848 CDr01s08 1618 CALL UPDATE ; UPDATE FILENAME AND WRITE DIRECTORY. + 084B CDr2Ds07 1619 CALL FINDNXT ; AND GET THE NEXT FILE. + 084E C3r40s08 1620 JP SAVATR1 ; THEN CONTINUE UNTIL DONE. + 1621 ; + 1622 ; OPEN A FILE (NAME SPECIFIED IN FCB). + 1623 ; + 0851 0E 0F 1624 OPENIT: LD C,#15 ; COMPARE THE FIRST 15 BYTES. + 0853 CDr18s07 1625 CALL FINDFST ; GET THE FIRST ONE IN DIRECTORY. + 0856 CDrF5s05 1626 CALL CKFILPOS ; ANY AT ALL? + 0859 C8 1627 RET Z + 085A CDrA6s04 1628 OPENIT1:CALL SETEXT ; POINT TO EXTENT BYTE WITHIN USERS FCB. + 085D 7E 1629 LD A,(HL) ; AND GET IT. + 085E F5 1630 PUSH AF ; SAVE IT AND ADDRESS. + 085F E5 1631 PUSH HL + 0860 CDr5Es05 1632 CALL FCB2HL ; POINT TO FCB IN DIRECTORY. + 0863 EB 1633 EX DE,HL + 0864 2Ar43s03 1634 LD HL,(PARAMS) ; THIS IS THE USERS COPY. + 0867 0E 20 1635 LD C,#32 ; MOVE IT INTO USERS SPACE. + 0869 D5 1636 PUSH DE + 086A CDr4Fs03 1637 CALL DE2HL + 086D CDr78s05 1638 CALL SETS2B7 ; SET BIT 7 IN 'S2' BYTE (UNMODIFIED). + 0870 D1 1639 POP DE ; NOW GET THE EXTENT BYTE FROM THIS FCB. + 0871 21 0C 00 1640 LD HL,#12 + 0874 19 1641 ADD HL,DE + 0875 4E 1642 LD C,(HL) ; INTO (C). + 0876 21 0F 00 1643 LD HL,#15 ; NOW GET THE RECORD COUNT BYTE INTO (B). + 0879 19 1644 ADD HL,DE + 087A 46 1645 LD B,(HL) + 087B E1 1646 POP HL ; KEEP THE SAME EXTENT AS THE USER HAD ORIGINALLY. + 087C F1 1647 POP AF + 087D 77 1648 LD (HL),A + 087E 79 1649 LD A,C ; IS IT THE SAME AS IN THE DIRECTORY FCB? + 087F BE 1650 CP (HL) + 0880 78 1651 LD A,B ; IF YES, THEN USE THE SAME RECORD COUNT. + 0881 CAr8Bs08 1652 JP Z,OPENIT2 + 0884 3E 00 1653 LD A,#0 ; IF THE USER SPECIFIED AN EXTENT GREATER THAN + 0886 DAr8Bs08 1654 JP C,OPENIT2 ; THE ONE IN THE DIRECTORY, THEN SET RECORD COUNT TO 0. + 0889 3E 80 1655 LD A,#128 ; OTHERWISE SET TO MAXIMUM. + 088B 2Ar43s03 1656 OPENIT2:LD HL,(PARAMS) ; SET RECORD COUNT IN USERS FCB TO (A). + 088E 11 0F 00 1657 LD DE,#15 + 0891 19 1658 ADD HL,DE ; COMPUTE RELATIVE POSITION. + 0892 77 1659 LD (HL),A ; AND SET THE RECORD COUNT. + 0893 C9 1660 RET + 1661 ; + 1662 ; MOVE TWO BYTES FROM (DE) TO (HL) IF (AND ONLY IF) (HL) + 1663 ; POINT TO A ZERO VALUE (16 BIT). + 1664 ; RETURN WITH ZERO FLAG SET IT (DE) WAS MOVED. REGISTERS (DE) + 1665 ; AND (HL) ARE NOT CHANGED. HOWEVER (A) IS. + 1666 ; + 0894 1667 MOVEWORD: + 0894 7E 1668 LD A,(HL) ; CHECK FOR A ZERO WORD. + 0895 23 1669 INC HL + 0896 B6 1670 OR (HL) ; BOTH BYTES ZERO? + 0897 2B 1671 DEC HL + 0898 C0 1672 RET NZ ; NOPE, JUST RETURN. + 0899 1A 1673 LD A,(DE) ; YES, MOVE TWO BYTES FROM (DE) INTO + 089A 77 1674 LD (HL),A ; THIS ZERO SPACE. + 089B 13 1675 INC DE + 089C 23 1676 INC HL + 089D 1A 1677 LD A,(DE) + 089E 77 1678 LD (HL),A + 089F 1B 1679 DEC DE ; DON'T DISTURB THESE REGISTERS. + 08A0 2B 1680 DEC HL + 08A1 C9 1681 RET + 1682 ; + 1683 ; GET HERE TO CLOSE A FILE SPECIFIED BY (FCB). + 1684 ; + 08A2 AF 1685 CLOSEIT:XOR A ; CLEAR STATUS AND FILE POSITION BYTES. + 08A3 32r45s03 1686 LD (STATUS),A + 08A6 32rEAs0D 1687 LD (FILEPOS),A + 08A9 32rEBs0D 1688 LD (FILEPOS+1),A + 08AC CDr1Es05 1689 CALL GETWPRT ; GET WRITE PROTECT BIT FOR THIS DRIVE. + 08AF C0 1690 RET NZ ; JUST RETURN IF IT IS SET. + 08B0 CDr69s05 1691 CALL GETS2 ; ELSE GET THE 'S2' BYTE. + 08B3 E6 80 1692 AND #0x80 ; AND LOOK AT BIT 7 (FILE UNMODIFIED?). + 08B5 C0 1693 RET NZ ; JUST RETURN IF SET. + 08B6 0E 0F 1694 LD C,#15 ; ELSE LOOK UP THIS FILE IN DIRECTORY. + 08B8 CDr18s07 1695 CALL FINDFST + 08BB CDrF5s05 1696 CALL CKFILPOS ; WAS IT FOUND? + 08BE C8 1697 RET Z ; JUST RETURN IF NOT. + 08BF 01 10 00 1698 LD BC,#16 ; SET (HL) POINTING TO RECORDS USED SECTION. + 08C2 CDr5Es05 1699 CALL FCB2HL + 08C5 09 1700 ADD HL,BC + 08C6 EB 1701 EX DE,HL + 08C7 2Ar43s03 1702 LD HL,(PARAMS) ; DO THE SAME FOR USERS SPECIFIED FCB. + 08CA 09 1703 ADD HL,BC + 08CB 0E 10 1704 LD C,#16 ; THIS MANY BYTES ARE PRESENT IN THIS EXTENT. + 08CD 1705 CLOSEIT1: + 08CD 3ArDDs0D 1706 LD A,(BIGDISK) ; 8 OR 16 BIT RECORD NUMBERS? + 08D0 B7 1707 OR A + 08D1 CArE8s08 1708 JP Z,CLOSEIT4 + 08D4 7E 1709 LD A,(HL) ; JUST 8 BIT. GET ONE FROM USERS FCB. + 08D5 B7 1710 OR A + 08D6 1A 1711 LD A,(DE) ; NOW GET ONE FROM DIRECTORY FCB. + 08D7 C2rDBs08 1712 JP NZ,CLOSEIT2 + 08DA 77 1713 LD (HL),A ; USERS BYTE WAS ZERO. UPDATE FROM DIRECTORY. + 08DB 1714 CLOSEIT2: + 08DB B7 1715 OR A + 08DC C2rE1s08 1716 JP NZ,CLOSEIT3 + 08DF 7E 1717 LD A,(HL) ; DIRECTORIES BYTE WAS ZERO, UPDATE FROM USERS FCB. + 08E0 12 1718 LD (DE),A + 08E1 1719 CLOSEIT3: + 08E1 BE 1720 CP (HL) ; IF NEITHER ONE OF THESE BYTES WERE ZERO, + 08E2 C2r1Fs09 1721 JP NZ,CLOSEIT7 ; THEN CLOSE ERROR IF THEY ARE NOT THE SAME. + 08E5 C3rFDs08 1722 JP CLOSEIT5 ; OK SO FAR, GET TO NEXT BYTE IN FCBS. + 08E8 1723 CLOSEIT4: + 08E8 CDr94s08 1724 CALL MOVEWORD ; UPDATE USERS FCB IF IT IS ZERO. + 08EB EB 1725 EX DE,HL + 08EC CDr94s08 1726 CALL MOVEWORD ; UPDATE DIRECTORIES FCB IF IT IS ZERO. + 08EF EB 1727 EX DE,HL + 08F0 1A 1728 LD A,(DE) ; IF THESE TWO VALUES ARE NO DIFFERENT, + 08F1 BE 1729 CP (HL) ; THEN A CLOSE ERROR OCCURED. + 08F2 C2r1Fs09 1730 JP NZ,CLOSEIT7 + 08F5 13 1731 INC DE ; CHECK SECOND BYTE. + 08F6 23 1732 INC HL + 08F7 1A 1733 LD A,(DE) + 08F8 BE 1734 CP (HL) + 08F9 C2r1Fs09 1735 JP NZ,CLOSEIT7 + 08FC 0D 1736 DEC C ; REMEMBER 16 BIT VALUES. + 08FD 1737 CLOSEIT5: + 08FD 13 1738 INC DE ; BUMP TO NEXT ITEM IN TABLE. + 08FE 23 1739 INC HL + 08FF 0D 1740 DEC C ; THERE ARE 16 ENTRIES ONLY. + 0900 C2rCDs08 1741 JP NZ,CLOSEIT1 ; CONTINUE IF MORE TO DO. + 0903 01 EC FF 1742 LD BC,#0x0FFEC ; BACKUP 20 PLACES (EXTENT BYTE). + 0906 09 1743 ADD HL,BC + 0907 EB 1744 EX DE,HL + 0908 09 1745 ADD HL,BC + 0909 1A 1746 LD A,(DE) + 090A BE 1747 CP (HL) ; DIRECTORY'S EXTENT ALREADY GREATER THAN THE + 090B DAr17s09 1748 JP C,CLOSEIT6 ; USERS EXTENT? + 090E 77 1749 LD (HL),A ; NO, UPDATE DIRECTORY EXTENT. + 090F 01 03 00 1750 LD BC,#3 ; AND UPDATE THE RECORD COUNT BYTE IN + 0912 09 1751 ADD HL,BC ; DIRECTORIES FCB. + 0913 EB 1752 EX DE,HL + 0914 09 1753 ADD HL,BC + 0915 7E 1754 LD A,(HL) ; GET FROM USER. + 0916 12 1755 LD (DE),A ; AND PUT IN DIRECTORY. + 0917 1756 CLOSEIT6: + 0917 3E FF 1757 LD A,#0x0FF ; SET 'WAS OPEN AND IS NOW CLOSED' BYTE. + 0919 32rD2s0D 1758 LD (CLOSEFLG),A + 091C C3r10s08 1759 JP UPDATE1 ; UPDATE THE DIRECTORY NOW. + 091F 1760 CLOSEIT7: + 091F 21r45s03 1761 LD HL,#STATUS ; SET RETURN STATUS AND THEN RETURN. + 0922 35 1762 DEC (HL) + 0923 C9 1763 RET + 1764 ; + 1765 ; ROUTINE TO GET THE NEXT EMPTY SPACE IN THE DIRECTORY. IT + 1766 ; WILL THEN BE CLEARED FOR USE. + 1767 ; + 0924 1768 GETEMPTY: + 0924 CDr54s05 1769 CALL CHKWPRT ; MAKE SURE DISK IS NOT WRITE PROTECTED. + 0927 2Ar43s03 1770 LD HL,(PARAMS) ; SAVE CURRENT PARAMETERS (FCB). + 092A E5 1771 PUSH HL + 092B 21rACs0D 1772 LD HL,#EMPTYFCB ; USE SPECIAL ONE FOR EMPTY SPACE. + 092E 22r43s03 1773 LD (PARAMS),HL + 0931 0E 01 1774 LD C,#1 ; SEARCH FOR FIRST EMPTY SPOT IN DIRECTORY. + 0933 CDr18s07 1775 CALL FINDFST ; (* ONLY CHECK FIRST BYTE *) + 0936 CDrF5s05 1776 CALL CKFILPOS ; NONE? + 0939 E1 1777 POP HL + 093A 22r43s03 1778 LD (PARAMS),HL ; RESTORE ORIGINAL FCB ADDRESS. + 093D C8 1779 RET Z ; RETURN IF NO MORE SPACE. + 093E EB 1780 EX DE,HL + 093F 21 0F 00 1781 LD HL,#15 ; POINT TO NUMBER OF RECORDS FOR THIS FILE. + 0942 19 1782 ADD HL,DE + 0943 0E 11 1783 LD C,#17 ; AND CLEAR ALL OF THIS SPACE. + 0945 AF 1784 XOR A + 0946 77 1785 GETMT1: LD (HL),A + 0947 23 1786 INC HL + 0948 0D 1787 DEC C + 0949 C2r46s09 1788 JP NZ,GETMT1 + 094C 21 0D 00 1789 LD HL,#13 ; CLEAR THE 'S1' BYTE ALSO. + 094F 19 1790 ADD HL,DE + 0950 77 1791 LD (HL),A + 0951 CDr8Cs05 1792 CALL CHKNMBR ; KEEP (SCRATCH1) WITHIN BOUNDS. + 0954 CDrFDs07 1793 CALL FCBSET ; WRITE OUT THIS FCB ENTRY TO DIRECTORY. + 0957 C3r78s05 1794 JP SETS2B7 ; SET 'S2' BYTE BIT 7 (UNMODIFIED AT PRESENT). + 1795 ; + 1796 ; ROUTINE TO CLOSE THE CURRENT EXTENT AND OPEN THE NEXT ONE + 1797 ; FOR READING. + 1798 ; + 095A AF 1799 GETNEXT:XOR A + 095B 32rD2s0D 1800 LD (CLOSEFLG),A ; CLEAR CLOSE FLAG. + 095E CDrA2s08 1801 CALL CLOSEIT ; CLOSE THIS EXTENT. + 0961 CDrF5s05 1802 CALL CKFILPOS + 0964 C8 1803 RET Z ; NOT THERE??? + 0965 2Ar43s03 1804 LD HL,(PARAMS) ; GET EXTENT BYTE. + 0968 01 0C 00 1805 LD BC,#12 + 096B 09 1806 ADD HL,BC + 096C 7E 1807 LD A,(HL) ; AND INCREMENT IT. + 096D 3C 1808 INC A + 096E E6 1F 1809 AND #0x1F ; KEEP WITHIN RANGE 0-31. + 0970 77 1810 LD (HL),A + 0971 CAr83s09 1811 JP Z,GTNEXT1 ; OVERFLOW? + 0974 47 1812 LD B,A ; MASK EXTENT BYTE. + 0975 3ArC5s0D 1813 LD A,(EXTMASK) + 0978 A0 1814 AND B + 0979 21rD2s0D 1815 LD HL,#CLOSEFLG ; CHECK CLOSE FLAG (0FFH IS OK). + 097C A6 1816 AND (HL) + 097D CAr8Es09 1817 JP Z,GTNEXT2 ; IF ZERO, WE MUST READ IN NEXT EXTENT. + 0980 C3rACs09 1818 JP GTNEXT3 ; ELSE, IT IS ALREADY IN MEMORY. + 0983 01 02 00 1819 GTNEXT1:LD BC,#2 ; POINT TO THE 'S2' BYTE. + 0986 09 1820 ADD HL,BC + 0987 34 1821 INC (HL) ; AND BUMP IT. + 0988 7E 1822 LD A,(HL) ; TOO MANY EXTENTS? + 0989 E6 0F 1823 AND #0x0F + 098B CArB6s09 1824 JP Z,GTNEXT5 ; YES, SET ERROR CODE. + 1825 ; + 1826 ; GET HERE TO OPEN THE NEXT EXTENT. + 1827 ; + 098E 0E 0F 1828 GTNEXT2:LD C,#15 ; SET TO CHECK FIRST 15 BYTES OF FCB. + 0990 CDr18s07 1829 CALL FINDFST ; FIND THE FIRST ONE. + 0993 CDrF5s05 1830 CALL CKFILPOS ; NONE AVAILABLE? + 0996 C2rACs09 1831 JP NZ,GTNEXT3 + 0999 3ArD3s0D 1832 LD A,(R.DWRTFLG) ; NO EXTENT PRESENT. CAN WE OPEN AN EMPTY ONE? + 099C 3C 1833 INC A ; 0FFH MEANS READING (SO NOT POSSIBLE). + 099D CArB6s09 1834 JP Z,GTNEXT5 ; OR AN ERROR. + 09A0 CDr24s09 1835 CALL GETEMPTY ; WE ARE WRITING, GET AN EMPTY ENTRY. + 09A3 CDrF5s05 1836 CALL CKFILPOS ; NONE? + 09A6 CArB6s09 1837 JP Z,GTNEXT5 ; ERROR IF TRUE. + 09A9 C3rAFs09 1838 JP GTNEXT4 ; ELSE WE ARE ALMOST DONE. + 09AC CDr5As08 1839 GTNEXT3:CALL OPENIT1 ; OPEN THIS EXTENT. + 09AF CDrBBs04 1840 GTNEXT4:CALL STRDATA ; MOVE IN UPDATED DATA (REC #, EXTENT #, ETC.) + 09B2 AF 1841 XOR A ; CLEAR STATUS AND RETURN. + 09B3 C3r01s03 1842 JP SETSTAT + 1843 ; + 1844 ; ERROR IN EXTENDING THE FILE. TOO MANY EXTENTS WERE NEEDED + 1845 ; OR NOT ENOUGH SPACE ON THE DISK. + 1846 ; + 09B6 CDr05s03 1847 GTNEXT5:CALL IOERR1 ; SET ERROR CODE, CLEAR BIT 7 OF 'S2' + 09B9 C3r78s05 1848 JP SETS2B7 ; SO THIS IS NOT WRITTEN ON A CLOSE. + 1849 ; + 1850 ; READ A S.EQUENTIAL FILE. + 1851 ; + 09BC 3E 01 1852 RDSEQ: LD A,#1 ; SET S.EQUENTIAL ACCESS MODE. + 09BE 32rD5s0D 1853 LD (MODE),A + 09C1 3E FF 1854 RDSEQ1: LD A,#0x0FF ; DON'T ALLOW READING UNWRITTEN SPACE. + 09C3 32rD3s0D 1855 LD (R.DWRTFLG),A + 09C6 CDrBBs04 1856 CALL STRDATA ; PUT REC# AND EXT# INTO FCB. + 09C9 3ArE3s0D 1857 LD A,(SAVNREC) ; GET NEXT RECORD TO READ. + 09CC 21rE1s0D 1858 LD HL,#SAVNXT ; GET NUMBER OF RECORDS IN EXTENT. + 09CF BE 1859 CP (HL) ; WITHIN THIS EXTENT? + 09D0 DArE6s09 1860 JP C,RDSEQ2 + 09D3 FE 80 1861 CP #128 ; NO. IS THIS EXTENT FULLY USED? + 09D5 C2rFBs09 1862 JP NZ,RDSEQ3 ; NO. END-OF-FILE. + 09D8 CDr5As09 1863 CALL GETNEXT ; YES, OPEN THE NEXT ONE. + 09DB AF 1864 XOR A ; RESET NEXT RECORD TO READ. + 09DC 32rE3s0D 1865 LD (SAVNREC),A + 09DF 3Ar45s03 1866 LD A,(STATUS) ; CHECK ON OPEN, SUCCESSFUL? + 09E2 B7 1867 OR A + 09E3 C2rFBs09 1868 JP NZ,RDSEQ3 ; NO, ERROR. + 09E6 CDr77s04 1869 RDSEQ2: CALL COMBLK ; OK. COMPUTE BLOCK NUMBER TO READ. + 09E9 CDr84s04 1870 CALL CHKBLK ; CHECK IT. WITHIN BOUNDS? + 09EC CArFBs09 1871 JP Z,RDSEQ3 ; NO, ERROR. + 09EF CDr8As04 1872 CALL LOGICAL ; CONVERT (BLKNMBR) TO LOGICAL SECTOR (128 BYTE). + 09F2 CDrD1s03 1873 CALL TRKSEC1 ; SET THE TRACK AND SECTOR FOR THIS BLOCK #. + 09F5 CDrB2s03 1874 CALL DOREAD ; AND READ IT. + 09F8 C3rD2s04 1875 JP SETNREC ; AND SET THE NEXT RECORD TO BE ACCESSED. + 1876 ; + 1877 ; READ ERROR OCCURED. SET STATUS AND RETURN. + 1878 ; + 09FB C3r05s03 1879 RDSEQ3: JP IOERR1 + 1880 ; + 1881 ; WRITE THE NEXT S.EQUENTIAL RECORD. + 1882 ; + 09FE 3E 01 1883 WTSEQ: LD A,#1 ; SET S.EQUENTIAL ACCESS MODE. + 0A00 32rD5s0D 1884 LD (MODE),A + 0A03 3E 00 1885 WTSEQ1: LD A,#0 ; ALLOW AN ADDITION EMPTY EXTENT TO BE OPENED. + 0A05 32rD3s0D 1886 LD (R.DWRTFLG),A + 0A08 CDr54s05 1887 CALL CHKWPRT ; CHECK WRITE PROTECT STATUS. + 0A0B 2Ar43s03 1888 LD HL,(PARAMS) + 0A0E CDr47s05 1889 CALL CKROF1 ; CHECK FOR READ ONLY FILE, (HL) ALREADY SET TO FCB. + 0A11 CDrBBs04 1890 CALL STRDATA ; PUT UPDATED DATA INTO FCB. + 0A14 3ArE3s0D 1891 LD A,(SAVNREC) ; GET RECORD NUMBER TO WRITE. + 0A17 FE 80 1892 CP #128 ; WITHIN RANGE? + 0A19 D2r05s03 1893 JP NC,IOERR1 ; NO, ERROR(?). + 0A1C CDr77s04 1894 CALL COMBLK ; COMPUTE BLOCK NUMBER. + 0A1F CDr84s04 1895 CALL CHKBLK ; CHECK NUMBER. + 0A22 0E 00 1896 LD C,#0 ; IS THERE ONE TO WRITE TO? + 0A24 C2r6Es0A 1897 JP NZ,WTSEQ6 ; YES, GO DO IT. + 0A27 CDr3Es04 1898 CALL GETBLOCK ; GET NEXT BLOCK NUMBER WITHIN FCB TO USE. + 0A2A 32rD7s0D 1899 LD (RELBLOCK),A ; AND SAVE. + 0A2D 01 00 00 1900 LD BC,#0 ; START LOOKING FOR SPACE FROM THE START + 0A30 B7 1901 OR A ; IF NONE ALLOCATED AS YET. + 0A31 CAr3Bs0A 1902 JP Z,WTSEQ2 + 0A34 4F 1903 LD C,A ; EXTRACT PREVIOUS BLOCK NUMBER FROM FCB + 0A35 0B 1904 DEC BC ; SO WE CAN BE CLOSEST TO IT. + 0A36 CDr5Es04 1905 CALL EXTBLK + 0A39 44 1906 LD B,H + 0A3A 4D 1907 LD C,L + 0A3B CDrBEs07 1908 WTSEQ2: CALL FNDSPACE ; FIND THE NEXT EMPTY BLOCK NEAREST NUMBER (BC). + 0A3E 7D 1909 LD A,L ; CHECK FOR A ZERO NUMBER. + 0A3F B4 1910 OR H + 0A40 C2r48s0A 1911 JP NZ,WTSEQ3 + 0A43 3E 02 1912 LD A,#2 ; NO MORE SPACE? + 0A45 C3r01s03 1913 JP SETSTAT + 0A48 22rE5s0D 1914 WTSEQ3: LD (BLKNMBR),HL ; SAVE BLOCK NUMBER TO ACCESS. + 0A4B EB 1915 EX DE,HL ; PUT BLOCK NUMBER INTO (DE). + 0A4C 2Ar43s03 1916 LD HL,(PARAMS) ; NOW WE MUST UPDATE THE FCB FOR THIS + 0A4F 01 10 00 1917 LD BC,#16 ; NEWLY ALLOCATED BLOCK. + 0A52 09 1918 ADD HL,BC + 0A53 3ArDDs0D 1919 LD A,(BIGDISK) ; 8 OR 16 BIT BLOCK NUMBERS? + 0A56 B7 1920 OR A + 0A57 3ArD7s0D 1921 LD A,(RELBLOCK) ; (* UPDATE THIS ENTRY *) + 0A5A CAr64s0A 1922 JP Z,WTSEQ4 ; ZERO MEANS 16 BIT ONES. + 0A5D CDr64s05 1923 CALL ADDA2HL ; (HL)=(HL)+(A) + 0A60 73 1924 LD (HL),E ; STORE NEW BLOCK NUMBER. + 0A61 C3r6Cs0A 1925 JP WTSEQ5 + 0A64 4F 1926 WTSEQ4: LD C,A ; COMPUTE SPOT IN THIS 16 BIT TABLE. + 0A65 06 00 1927 LD B,#0 + 0A67 09 1928 ADD HL,BC + 0A68 09 1929 ADD HL,BC + 0A69 73 1930 LD (HL),E ; STUFF BLOCK NUMBER (DE) THERE. + 0A6A 23 1931 INC HL + 0A6B 72 1932 LD (HL),D + 0A6C 0E 02 1933 WTSEQ5: LD C,#2 ; SET (C) TO INDICATE WRITING TO UN-USED DISK SPACE. + 0A6E 3Ar45s03 1934 WTSEQ6: LD A,(STATUS) ; ARE WE OK SO FAR? + 0A71 B7 1935 OR A + 0A72 C0 1936 RET NZ + 0A73 C5 1937 PUSH BC ; YES, SAVE WRITE FLAG FOR BIOS (REGISTER C). + 0A74 CDr8As04 1938 CALL LOGICAL ; CONVERT (BLKNMBR) OVER TO LOICAL SECTORS. + 0A77 3ArD5s0D 1939 LD A,(MODE) ; GET ACCESS MODE FLAG (1=S.EQUENTIAL, + 0A7A 3D 1940 DEC A ; 0=RANDOM, 2=SPECIAL?). + 0A7B 3D 1941 DEC A + 0A7C C2rBBs0A 1942 JP NZ,WTSEQ9 + 1943 ; + 1944 ; SPECIAL RANDOM I/O FROM FUNCTION #40. MAYBE FOR M/PM, BUT THE + 1945 ; CURRENT BLOCK, IF IT HAS NOT BEEN WRITTEN TO, WILL BE ZEROED + 1946 ; OUT AND THEN WRITTEN (REASON?). + 1947 ; + 0A7F C1 1948 POP BC + 0A80 C5 1949 PUSH BC + 0A81 79 1950 LD A,C ; GET WRITE STATUS FLAG (2=WRITING UNUSED SPACE). + 0A82 3D 1951 DEC A + 0A83 3D 1952 DEC A + 0A84 C2rBBs0A 1953 JP NZ,WTSEQ9 + 0A87 E5 1954 PUSH HL + 0A88 2ArB9s0D 1955 LD HL,(DIRBUF) ; ZERO OUT THE DIRECTORY BUFFER. + 0A8B 57 1956 LD D,A ; NOTE THAT (A) IS ZERO HERE. + 0A8C 77 1957 WTSEQ7: LD (HL),A + 0A8D 23 1958 INC HL + 0A8E 14 1959 INC D ; DO 128 BYTES. + 0A8F F2r8Cs0A 1960 JP P,WTSEQ7 + 0A92 CDrE0s05 1961 CALL DIRDMA ; TELL THE BIOS THE DMA ADDRESS FOR DIRECTORY ACCESS. + 0A95 2ArE7s0D 1962 LD HL,(LOGSECT) ; GET SECTOR THAT STARTS CURRENT BLOCK. + 0A98 0E 02 1963 LD C,#2 ; SET 'WRITING TO UNUSED SPACE' FLAG. + 0A9A 22rE5s0D 1964 WTSEQ8: LD (BLKNMBR),HL ; SAVE SECTOR TO WRITE. + 0A9D C5 1965 PUSH BC + 0A9E CDrD1s03 1966 CALL TRKSEC1 ; DETERMINE ITS TRACK AND SECTOR NUMBERS. + 0AA1 C1 1967 POP BC + 0AA2 CDrB8s03 1968 CALL DOWRITE ; NOW WRITE OUT 128 BYTES OF ZEROS. + 0AA5 2ArE5s0D 1969 LD HL,(BLKNMBR) ; GET SECTOR NUMBER. + 0AA8 0E 00 1970 LD C,#0 ; SET NORMAL WRITE FLAG. + 0AAA 3ArC4s0D 1971 LD A,(BLKMASK) ; DETERMINE IF WE HAVE WRITTEN THE ENTIRE + 0AAD 47 1972 LD B,A ; PHYSICAL BLOCK. + 0AAE A5 1973 AND L + 0AAF B8 1974 CP B + 0AB0 23 1975 INC HL ; PREPARE FOR THE NEXT ONE. + 0AB1 C2r9As0A 1976 JP NZ,WTSEQ8 ; CONTINUE UNTIL (BLKMASK+1) SECTORS WRITTEN. + 0AB4 E1 1977 POP HL ; RESET NEXT SECTOR NUMBER. + 0AB5 22rE5s0D 1978 LD (BLKNMBR),HL + 0AB8 CDrDAs05 1979 CALL DEFDMA ; AND RESET DMA ADDRESS. + 1980 ; + 1981 ; NORMAL DISK WRITE. SET THE DESIRED TRACK AND SECTOR THEN + 1982 ; DO THE ACTUAL WRITE. + 1983 ; + 0ABB CDrD1s03 1984 WTSEQ9: CALL TRKSEC1 ; DETERMINE TRACK AND SECTOR FOR THIS WRITE. + 0ABE C1 1985 POP BC ; GET WRITE STATUS FLAG. + 0ABF C5 1986 PUSH BC + 0AC0 CDrB8s03 1987 CALL DOWRITE ; AND WRITE THIS OUT. + 0AC3 C1 1988 POP BC + 0AC4 3ArE3s0D 1989 LD A,(SAVNREC) ; GET NUMBER OF RECORDS IN FILE. + 0AC7 21rE1s0D 1990 LD HL,#SAVNXT ; GET LAST RECORD WRITTEN. + 0ACA BE 1991 CP (HL) + 0ACB DArD2s0A 1992 JP C,WTSEQ10 + 0ACE 77 1993 LD (HL),A ; WE HAVE TO UPDATE RECORD COUNT. + 0ACF 34 1994 INC (HL) + 0AD0 0E 02 1995 LD C,#2 + 1996 ; + 1997 ;* THIS AREA HAS BEEN PATCHED TO CORRECT DISK UPDATE PROBLEM + 1998 ;* WHEN USING BLOCKING AND DE-BLOCKING IN THE BIOS. + 1999 ; + 0AD2 00 2000 WTSEQ10:NOP ; WAS 'DCR C' + 0AD3 00 2001 NOP ; WAS 'DCR C' + 0AD4 21 00 00 2002 LD HL,#0 ; WAS 'JNZ WTSEQ99' + 2003 ; + 2004 ; * END OF PATCH. + 2005 ; + 0AD7 F5 2006 PUSH AF + 0AD8 CDr69s05 2007 CALL GETS2 ; SET 'EXTENT WRITTEN TO' FLAG. + 0ADB E6 7F 2008 AND #0x7F ; (* CLEAR BIT 7 *) + 0ADD 77 2009 LD (HL),A + 0ADE F1 2010 POP AF ; GET RECORD COUNT FOR THIS EXTENT. + 0ADF FE 7F 2011 WTSEQ99:CP #127 ; IS IT FULL? + 0AE1 C2r00s0B 2012 JP NZ,WTSEQ12 + 0AE4 3ArD5s0D 2013 LD A,(MODE) ; YES, ARE WE IN S.EQUENTIAL MODE? + 0AE7 FE 01 2014 CP #1 + 0AE9 C2r00s0B 2015 JP NZ,WTSEQ12 + 0AEC CDrD2s04 2016 CALL SETNREC ; YES, SET NEXT RECORD NUMBER. + 0AEF CDr5As09 2017 CALL GETNEXT ; AND GET NEXT EMPTY SPACE IN DIRECTORY. + 0AF2 21r45s03 2018 LD HL,#STATUS ; OK? + 0AF5 7E 2019 LD A,(HL) + 0AF6 B7 2020 OR A + 0AF7 C2rFEs0A 2021 JP NZ,WTSEQ11 + 0AFA 3D 2022 DEC A ; YES, SET RECORD COUNT TO -1. + 0AFB 32rE3s0D 2023 LD (SAVNREC),A + 0AFE 36 00 2024 WTSEQ11:LD (HL),#0 ; CLEAR STATUS. + 0B00 C3rD2s04 2025 WTSEQ12:JP SETNREC ; SET NEXT RECORD TO ACCESS. + 2026 ; + 2027 ; FOR RANDOM I/O, SET THE FCB FOR THE DESIRED RECORD NUMBER + 2028 ; BASED ON THE 'R0,R1,R2' BYTES. THESE BYTES IN THE FCB ARE + 2029 ; USED AS FOLLOWS: + 2030 ; + 2031 ; FCB+35 FCB+34 FCB+33 + 2032 ; | 'R-2' | 'R-1' | 'R-0' | + 2033 ; |7 0 | 7 0 | 7 0| + 2034 ; |0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0| + 2035 ; | OVERFLOW | | EXTRA | EXTENT | RECORD # | + 2036 ; | ______________| |_EXTENT|__NUMBER___|_____________| + 2037 ; ALSO 'S2' + 2038 ; + 2039 ; ON ENTRY, REGISTER (C) CONTAINS 0FFH IF THIS IS A READ + 2040 ; AND THUS WE CAN NOT ACCESS UNWRITTEN DISK SPACE. OTHERWISE, + 2041 ; ANOTHER EXTENT WILL BE OPENED (FOR WRITING) IF R.EQUIRED. + 2042 ; + 0B03 2043 POSITION: + 0B03 AF 2044 XOR A ; SET RANDOM I/O FLAG. + 0B04 32rD5s0D 2045 LD (MODE),A + 2046 ; + 2047 ; SPECIAL ENTRY (FUNCTION #40). M/PM ? + 2048 ; + 0B07 C5 2049 POSITN1:PUSH BC ; SAVE READ/WRITE FLAG. + 0B08 2Ar43s03 2050 LD HL,(PARAMS) ; GET ADDRESS OF FCB. + 0B0B EB 2051 EX DE,HL + 0B0C 21 21 00 2052 LD HL,#33 ; NOW GET BYTE 'R0'. + 0B0F 19 2053 ADD HL,DE + 0B10 7E 2054 LD A,(HL) + 0B11 E6 7F 2055 AND #0x7F ; KEEP BITS 0-6 FOR THE RECORD NUMBER TO ACCESS. + 0B13 F5 2056 PUSH AF + 0B14 7E 2057 LD A,(HL) ; NOW GET BIT 7 OF 'R0' AND BITS 0-3 OF 'R1'. + 0B15 17 2058 RLA + 0B16 23 2059 INC HL + 0B17 7E 2060 LD A,(HL) + 0B18 17 2061 RLA + 0B19 E6 1F 2062 AND #0x1F ; AND SAVE THIS IN BITS 0-4 OF (C). + 0B1B 4F 2063 LD C,A ; THIS IS THE EXTENT BYTE. + 0B1C 7E 2064 LD A,(HL) ; NOW GET THE EXTRA EXTENT BYTE. + 0B1D 1F 2065 RRA + 0B1E 1F 2066 RRA + 0B1F 1F 2067 RRA + 0B20 1F 2068 RRA + 0B21 E6 0F 2069 AND #0x0F + 0B23 47 2070 LD B,A ; AND SAVE IT IN (B). + 0B24 F1 2071 POP AF ; GET RECORD NUMBER BACK TO (A). + 0B25 23 2072 INC HL ; CHECK OVERFLOW BYTE 'R2'. + 0B26 6E 2073 LD L,(HL) + 0B27 2C 2074 INC L + 0B28 2D 2075 DEC L + 0B29 2E 06 2076 LD L,#6 ; PREPARE FOR ERROR. + 0B2B C2r8Bs0B 2077 JP NZ,POSITN5 ; OUT OF DISK SPACE ERROR. + 0B2E 21 20 00 2078 LD HL,#32 ; STORE RECORD NUMBER INTO FCB. + 0B31 19 2079 ADD HL,DE + 0B32 77 2080 LD (HL),A + 0B33 21 0C 00 2081 LD HL,#12 ; AND NOW CHECK THE EXTENT BYTE. + 0B36 19 2082 ADD HL,DE + 0B37 79 2083 LD A,C + 0B38 96 2084 SUB (HL) ; SAME EXTENT AS BEFORE? + 0B39 C2r47s0B 2085 JP NZ,POSITN2 + 0B3C 21 0E 00 2086 LD HL,#14 ; YES, CHECK EXTRA EXTENT BYTE 'S2' ALSO. + 0B3F 19 2087 ADD HL,DE + 0B40 78 2088 LD A,B + 0B41 96 2089 SUB (HL) + 0B42 E6 7F 2090 AND #0x7F + 0B44 CAr7Fs0B 2091 JP Z,POSITN3 ; SAME, WE ARE ALMOST DONE THEN. + 2092 ; + 2093 ; GET HERE WHEN ANOTHER EXTENT IS R.EQUIRED. + 2094 ; + 0B47 C5 2095 POSITN2:PUSH BC + 0B48 D5 2096 PUSH DE + 0B49 CDrA2s08 2097 CALL CLOSEIT ; CLOSE CURRENT EXTENT. + 0B4C D1 2098 POP DE + 0B4D C1 2099 POP BC + 0B4E 2E 03 2100 LD L,#3 ; PREPARE FOR ERROR. + 0B50 3Ar45s03 2101 LD A,(STATUS) + 0B53 3C 2102 INC A + 0B54 CAr84s0B 2103 JP Z,POSITN4 ; CLOSE ERROR. + 0B57 21 0C 00 2104 LD HL,#12 ; PUT DESIRED EXTENT INTO FCB NOW. + 0B5A 19 2105 ADD HL,DE + 0B5B 71 2106 LD (HL),C + 0B5C 21 0E 00 2107 LD HL,#14 ; AND STORE EXTRA EXTENT BYTE 'S2'. + 0B5F 19 2108 ADD HL,DE + 0B60 70 2109 LD (HL),B + 0B61 CDr51s08 2110 CALL OPENIT ; TRY AND GET THIS EXTENT. + 0B64 3Ar45s03 2111 LD A,(STATUS) ; WAS IT THERE? + 0B67 3C 2112 INC A + 0B68 C2r7Fs0B 2113 JP NZ,POSITN3 + 0B6B C1 2114 POP BC ; NO. CAN WE CREATE A NEW ONE (WRITING?). + 0B6C C5 2115 PUSH BC + 0B6D 2E 04 2116 LD L,#4 ; PREPARE FOR ERROR. + 0B6F 0C 2117 INC C + 0B70 CAr84s0B 2118 JP Z,POSITN4 ; NOPE, READING UNWRITTEN SPACE ERROR. + 0B73 CDr24s09 2119 CALL GETEMPTY ; YES WE CAN, TRY TO FIND SPACE. + 0B76 2E 05 2120 LD L,#5 ; PREPARE FOR ERROR. + 0B78 3Ar45s03 2121 LD A,(STATUS) + 0B7B 3C 2122 INC A + 0B7C CAr84s0B 2123 JP Z,POSITN4 ; OUT OF SPACE? + 2124 ; + 2125 ; NORMAL RETURN LOCATION. CLEAR ERROR CODE AND RETURN. + 2126 ; + 0B7F C1 2127 POSITN3:POP BC ; RESTORE STACK. + 0B80 AF 2128 XOR A ; AND CLEAR ERROR CODE BYTE. + 0B81 C3r01s03 2129 JP SETSTAT + 2130 ; + 2131 ; ERROR. SET THE 'S2' BYTE TO INDICATE THIS (WHY?). + 2132 ; + 0B84 E5 2133 POSITN4:PUSH HL + 0B85 CDr69s05 2134 CALL GETS2 + 0B88 36 C0 2135 LD (HL),#0x0C0 + 0B8A E1 2136 POP HL + 2137 ; + 2138 ; RETURN WITH ERROR CODE (PRESENTLY IN L). + 2139 ; + 0B8B C1 2140 POSITN5:POP BC + 0B8C 7D 2141 LD A,L ; GET ERROR CODE. + 0B8D 32r45s03 2142 LD (STATUS),A + 0B90 C3r78s05 2143 JP SETS2B7 + 2144 ; + 2145 ; READ A RANDOM RECORD. + 2146 ; + 0B93 0E FF 2147 READRAN:LD C,#0x0FF ; SET 'READ' STATUS. + 0B95 CDr03s0B 2148 CALL POSITION ; POSITION THE FILE TO PROPER RECORD. + 0B98 CCrC1s09 2149 CALL Z,RDSEQ1 ; AND READ IT AS USUAL (IF NO ERRORS). + 0B9B C9 2150 RET + 2151 ; + 2152 ; WRITE TO A RANDOM RECORD. + 2153 ; + 0B9C 2154 WRITERAN: + 0B9C 0E 00 2155 LD C,#0 ; SET 'WRITING' FLAG. + 0B9E CDr03s0B 2156 CALL POSITION ; POSITION THE FILE TO PROPER RECORD. + 0BA1 CCr03s0A 2157 CALL Z,WTSEQ1 ; AND WRITE AS USUAL (IF NO ERRORS). + 0BA4 C9 2158 RET + 2159 ; + 2160 ; COMPUTE THE RANDOM RECORD NUMBER. ENTER WITH (HL) POINTING + 2161 ; TO A FCB AN (DE) CONTAINS A RELATIVE LOCATION OF A RECORD + 2162 ; NUMBER. ON EXIT, (C) CONTAINS THE 'R0' BYTE, (B) THE 'R1' + 2163 ; BYTE, AND (A) THE 'R2' BYTE. + 2164 ; + 2165 ; ON RETURN, THE ZERO FLAG IS SET IF THE RECORD IS WITHIN + 2166 ; BOUNDS. OTHERWISE, AN OVERFLOW OCCURED. + 2167 ; + 0BA5 2168 COMPRAND: + 0BA5 EB 2169 EX DE,HL ; SAVE FCB POINTER IN (DE). + 0BA6 19 2170 ADD HL,DE ; COMPUTE RELATIVE POSITION OF RECORD #. + 0BA7 4E 2171 LD C,(HL) ; GET RECORD NUMBER INTO (BC). + 0BA8 06 00 2172 LD B,#0 + 0BAA 21 0C 00 2173 LD HL,#12 ; NOW GET EXTENT. + 0BAD 19 2174 ADD HL,DE + 0BAE 7E 2175 LD A,(HL) ; COMPUTE (BC)=(RECORD #)+(EXTENT)*128. + 0BAF 0F 2176 RRCA ; MOVE LOWER BIT INTO BIT 7. + 0BB0 E6 80 2177 AND #0x80 ; AND IGNORE ALL OTHER BITS. + 0BB2 81 2178 ADD A,C ; ADD TO OUR RECORD NUMBER. + 0BB3 4F 2179 LD C,A + 0BB4 3E 00 2180 LD A,#0 ; TAKE CARE OF ANY CARRY. + 0BB6 88 2181 ADC A,B + 0BB7 47 2182 LD B,A + 0BB8 7E 2183 LD A,(HL) ; NOW GET THE UPPER BITS OF EXTENT INTO + 0BB9 0F 2184 RRCA ; BIT POSITIONS 0-3. + 0BBA E6 0F 2185 AND #0x0F ; AND IGNORE ALL OTHERS. + 0BBC 80 2186 ADD A,B ; ADD THIS IN TO 'R1' BYTE. + 0BBD 47 2187 LD B,A + 0BBE 21 0E 00 2188 LD HL,#14 ; GET THE 'S2' BYTE (EXTRA EXTENT). + 0BC1 19 2189 ADD HL,DE + 0BC2 7E 2190 LD A,(HL) + 0BC3 87 2191 ADD A,A ; AND SHIFT IT LEFT 4 BITS (BITS 4-7). + 0BC4 87 2192 ADD A,A + 0BC5 87 2193 ADD A,A + 0BC6 87 2194 ADD A,A + 0BC7 F5 2195 PUSH AF ; SAVE CARRY FLAG (BIT 0 OF FLAG BYTE). + 0BC8 80 2196 ADD A,B ; NOW ADD EXTRA EXTENT INTO 'R1'. + 0BC9 47 2197 LD B,A + 0BCA F5 2198 PUSH AF ; AND SAVE CARRY (OVERFLOW BYTE 'R2'). + 0BCB E1 2199 POP HL ; BIT 0 OF (L) IS THE OVERFLOW INDICATOR. + 0BCC 7D 2200 LD A,L + 0BCD E1 2201 POP HL ; AND SAME FOR FIRST CARRY FLAG. + 0BCE B5 2202 OR L ; EITHER ONE OF THESE SET? + 0BCF E6 01 2203 AND #1 ; ONLY CHECK THE CARRY FLAGS. + 0BD1 C9 2204 RET + 2205 ; + 2206 ; ROUTINE TO SETUP THE FCB (BYTES 'R0', 'R1', 'R2') TO + 2207 ; REFLECT THE LAST RECORD USED FOR A RANDOM (OR OTHER) FILE. + 2208 ; THIS READS THE DIRECTORY AND LOOKS AT ALL EXTENTS COMPUTING + 2209 ; THE LARGERST RECORD NUMBER FOR EACH AND KEEPING THE MAXIMUM + 2210 ; VALUE ONLY. THEN 'R0', 'R1', AND 'R2' WILL REFLECT THIS + 2211 ; MAXIMUM RECORD NUMBER. THIS IS USED TO COMPUTE THE SPACE USED + 2212 ; BY A RANDOM FILE. + 2213 ; + 0BD2 0E 0C 2214 RANSIZE:LD C,#12 ; LOOK THRU DIRECTORY FOR FIRST ENTRY WITH + 0BD4 CDr18s07 2215 CALL FINDFST ; THIS NAME. + 0BD7 2Ar43s03 2216 LD HL,(PARAMS) ; ZERO OUT THE 'R0, R1, R2' BYTES. + 0BDA 11 21 00 2217 LD DE,#33 + 0BDD 19 2218 ADD HL,DE + 0BDE E5 2219 PUSH HL + 0BDF 72 2220 LD (HL),D ; NOTE THAT (D)=0. + 0BE0 23 2221 INC HL + 0BE1 72 2222 LD (HL),D + 0BE2 23 2223 INC HL + 0BE3 72 2224 LD (HL),D + 0BE4 CDrF5s05 2225 RANSIZ1:CALL CKFILPOS ; IS THERE AN EXTENT TO PROCESS? + 0BE7 CAr0Cs0C 2226 JP Z,RANSIZ3 ; NO, WE ARE DONE. + 0BEA CDr5Es05 2227 CALL FCB2HL ; SET (HL) POINTING TO PROPER FCB IN DIR. + 0BED 11 0F 00 2228 LD DE,#15 ; POINT TO LAST RECORD IN EXTENT. + 0BF0 CDrA5s0B 2229 CALL COMPRAND ; AND COMPUTE RANDOM PARAMETERS. + 0BF3 E1 2230 POP HL + 0BF4 E5 2231 PUSH HL ; NOW CHECK THESE VALUES AGAINST THOSE + 0BF5 5F 2232 LD E,A ; ALREADY IN FCB. + 0BF6 79 2233 LD A,C ; THE CARRY FLAG WILL BE SET IF THOSE + 0BF7 96 2234 SUB (HL) ; IN THE FCB REPRESENT A LARGER SIZE THAN + 0BF8 23 2235 INC HL ; THIS EXTENT DOES. + 0BF9 78 2236 LD A,B + 0BFA 9E 2237 SBC A,(HL) + 0BFB 23 2238 INC HL + 0BFC 7B 2239 LD A,E + 0BFD 9E 2240 SBC A,(HL) + 0BFE DAr06s0C 2241 JP C,RANSIZ2 + 0C01 73 2242 LD (HL),E ; WE FOUND A LARGER (IN SIZE) EXTENT. + 0C02 2B 2243 DEC HL ; STUFF THESE VALUES INTO FCB. + 0C03 70 2244 LD (HL),B + 0C04 2B 2245 DEC HL + 0C05 71 2246 LD (HL),C + 0C06 CDr2Ds07 2247 RANSIZ2:CALL FINDNXT ; NOW GET THE NEXT EXTENT. + 0C09 C3rE4s0B 2248 JP RANSIZ1 ; CONTINUE TIL ALL DONE. + 0C0C E1 2249 RANSIZ3:POP HL ; WE ARE DONE, RESTORE THE STACK AND + 0C0D C9 2250 RET ; RETURN. + 2251 ; + 2252 ; FUNCTION TO RETURN THE RANDOM RECORD POSITION OF A GIVEN + 2253 ; FILE WHICH HAS BEEN READ IN S.EQUENTIAL MODE UP TO NOW. + 2254 ; + 0C0E 2Ar43s03 2255 SETRAN: LD HL,(PARAMS) ; POINT TO FCB. + 0C11 11 20 00 2256 LD DE,#32 ; AND TO LAST USED RECORD. + 0C14 CDrA5s0B 2257 CALL COMPRAND ; COMPUTE RANDOM POSITION. + 0C17 21 21 00 2258 LD HL,#33 ; NOW STUFF THESE VALUES INTO FCB. + 0C1A 19 2259 ADD HL,DE + 0C1B 71 2260 LD (HL),C ; MOVE 'R0'. + 0C1C 23 2261 INC HL + 0C1D 70 2262 LD (HL),B ; AND 'R1'. + 0C1E 23 2263 INC HL + 0C1F 77 2264 LD (HL),A ; AND LASTLY 'R2'. + 0C20 C9 2265 RET + 2266 ; + 2267 ; THIS ROUTINE SELECT THE DRIVE SPECIFIED IN (ACTIVE) AND + 2268 ; UPDATE THE LOGIN VECTOR AND BITMAP TABLE IF THIS DRIVE WAS + 2269 ; NOT ALREADY ACTIVE. + 2270 ; + 0C21 2271 LOGINDRV: + 0C21 2ArAFs0D 2272 LD HL,(LOGIN) ; GET THE LOGIN VECTOR. + 0C24 3Ar42s03 2273 LD A,(ACTIVE) ; GET THE DEFAULT DRIVE. + 0C27 4F 2274 LD C,A + 0C28 CDrEAs04 2275 CALL SHIFTR ; POSITION ACTIVE BIT FOR THIS DRIVE + 0C2B E5 2276 PUSH HL ; INTO BIT 0. + 0C2C EB 2277 EX DE,HL + 0C2D CDr59s03 2278 CALL SELECT ; SELECT THIS DRIVE. + 0C30 E1 2279 POP HL + 0C31 CCr47s03 2280 CALL Z,SLCTERR ; VALID DRIVE? + 0C34 7D 2281 LD A,L ; IS THIS A NEWLY ACTIVATED DRIVE? + 0C35 1F 2282 RRA + 0C36 D8 2283 RET C + 0C37 2ArAFs0D 2284 LD HL,(LOGIN) ; YES, UPDATE THE LOGIN VECTOR. + 0C3A 4D 2285 LD C,L + 0C3B 44 2286 LD B,H + 0C3C CDr0Bs05 2287 CALL SETBIT + 0C3F 22rAFs0D 2288 LD (LOGIN),HL ; AND SAVE. + 0C42 C3rA3s06 2289 JP BITMAP ; NOW UPDATE THE BITMAP. + 2290 ; + 2291 ; FUNCTION TO SET THE ACTIVE DISK NUMBER. + 2292 ; + 0C45 3ArD6s0D 2293 SETDSK: LD A,(EPARAM) ; GET PARAMETER PASSED AND SEE IF THIS + 0C48 21r42s03 2294 LD HL,#ACTIVE ; REPRESENTS A CHANGE IN DRIVES. + 0C4B BE 2295 CP (HL) + 0C4C C8 2296 RET Z + 0C4D 77 2297 LD (HL),A ; YES IT DOES, LOG IT IN. + 0C4E C3r21s0C 2298 JP LOGINDRV + 2299 ; + 2300 ; THIS IS THE 'AUTO DISK SELECT' ROUTINE. THE FIRSST BYTE + 2301 ; OF THE FCB IS EXAMINED FOR A DRIVE SPECIFICATION. IF NON + 2302 ; ZERO THEN THE DRIVE WILL BE SELECTED AND LOGED IN. + 2303 ; + 0C51 3E FF 2304 AUTOSEL:LD A,#0x0FF ; SAY 'AUTO-SELECT ACTIVATED'. + 0C53 32rDEs0D 2305 LD (AUTO),A + 0C56 2Ar43s03 2306 LD HL,(PARAMS) ; GET DRIVE SPECIFIED. + 0C59 7E 2307 LD A,(HL) + 0C5A E6 1F 2308 AND #0x1F ; LOOK AT LOWER 5 BITS. + 0C5C 3D 2309 DEC A ; ADJUST FOR (1=A, 2=B) ETC. + 0C5D 32rD6s0D 2310 LD (EPARAM),A ; AND SAVE FOR THE SELECT ROUTINE. + 0C60 FE 1E 2311 CP #0x1E ; CHECK FOR 'NO CHANGE' CONDITION. + 0C62 D2r75s0C 2312 JP NC,AUTOSL1 ; YES, DON'T CHANGE. + 0C65 3Ar42s03 2313 LD A,(ACTIVE) ; WE MUST CHANGE, SAVE CURRENTLY ACTIVE + 0C68 32rDFs0D 2314 LD (OLDDRV),A ; DRIVE. + 0C6B 7E 2315 LD A,(HL) ; AND SAVE FIRST BYTE OF FCB ALSO. + 0C6C 32rE0s0D 2316 LD (AUTOFLAG),A ; THIS MUST BE NON-ZERO. + 0C6F E6 E0 2317 AND #0x0E0 ; WHATS THIS FOR (BITS 6,7 ARE USED FOR + 0C71 77 2318 LD (HL),A ; SOMETHING)? + 0C72 CDr45s0C 2319 CALL SETDSK ; SELECT AND LOG IN THIS DRIVE. + 0C75 3Ar41s03 2320 AUTOSL1:LD A,(USERNO) ; MOVE USER NUMBER INTO FCB. + 0C78 2Ar43s03 2321 LD HL,(PARAMS) ; (* UPPER HALF OF FIRST BYTE *) + 0C7B B6 2322 OR (HL) + 0C7C 77 2323 LD (HL),A + 0C7D C9 2324 RET ; AND RETURN (ALL DONE). + 2325 ; + 2326 ; FUNCTION TO RETURN THE CURRENT CP/M VERSION NUMBER. + 2327 ; + 0C7E 3E 22 2328 GETVER: LD A,#0x022 ; VERSION 2.2 + 0C80 C3r01s03 2329 JP SETSTAT + 2330 ; + 2331 ; FUNCTION TO RESET THE DISK SYSTEM. + 2332 ; + 0C83 21 00 00 2333 RSTDSK: LD HL,#0 ; CLEAR WRITE PROTECT STATUS AND LOG + 0C86 22rADs0D 2334 LD (WRTPRT),HL ; IN VECTOR. + 0C89 22rAFs0D 2335 LD (LOGIN),HL + 0C8C AF 2336 XOR A ; SELECT DRIVE 'A'. + 0C8D 32r42s03 2337 LD (ACTIVE),A + 0C90 21 80 00 2338 LD HL,#TBUFF ; SETUP DEFAULT DMA ADDRESS. + 0C93 22rB1s0D 2339 LD (USERDMA),HL + 0C96 CDrDAs05 2340 CALL DEFDMA + 0C99 C3r21s0C 2341 JP LOGINDRV ; NOW LOG IN DRIVE 'A'. + 2342 ; + 2343 ; FUNCTION TO OPEN A SPECIFIED FILE. + 2344 ; + 0C9C CDr72s05 2345 OPENFIL:CALL CLEARS2 ; CLEAR 'S2' BYTE. + 0C9F CDr51s0C 2346 CALL AUTOSEL ; SELECT PROPER DISK. + 0CA2 C3r51s08 2347 JP OPENIT ; AND OPEN THE FILE. + 2348 ; + 2349 ; FUNCTION TO CLOSE A SPECIFIED FILE. + 2350 ; + 0CA5 2351 CLOSEFIL: + 0CA5 CDr51s0C 2352 CALL AUTOSEL ; SELECT PROPER DISK. + 0CA8 C3rA2s08 2353 JP CLOSEIT ; AND CLOSE THE FILE. + 2354 ; + 2355 ; FUNCTION TO RETURN THE FIRST OCCURENCE OF A SPECIFIED FILE + 2356 ; NAME. IF THE FIRST BYTE OF THE FCB IS '?' THEN THE NAME WILL + 2357 ; NOT BE CHECKED (GET THE FIRST ENTRY NO MATTER WHAT). + 2358 ; + 0CAB 0E 00 2359 GETFST: LD C,#0 ; PREPARE FOR SPECIAL SEARCH. + 0CAD EB 2360 EX DE,HL + 0CAE 7E 2361 LD A,(HL) ; IS FIRST BYTE A '?'? + 0CAF FE 3F 2362 CP #QUESTION + 0CB1 CArC2s0C 2363 JP Z,GETFST1 ; YES, JUST GET VERY FIRST ENTRY (ZERO LENGTH MATCH). + 0CB4 CDrA6s04 2364 CALL SETEXT ; GET THE EXTENSION BYTE FROM FCB. + 0CB7 7E 2365 LD A,(HL) ; IS IT '?'? IF YES, THEN WE WANT + 0CB8 FE 3F 2366 CP #QUESTION ; AN ENTRY WITH A SPECIFIC 'S2' BYTE. + 0CBA C4r72s05 2367 CALL NZ,CLEARS2 ; OTHERWISE, LOOK FOR A ZERO 'S2' BYTE. + 0CBD CDr51s0C 2368 CALL AUTOSEL ; SELECT PROPER DRIVE. + 0CC0 0E 0F 2369 LD C,#15 ; COMPARE BYTES 0-14 IN FCB (12&13 EXCLUDED). + 0CC2 CDr18s07 2370 GETFST1:CALL FINDFST ; FIND AN ENTRY AND THEN MOVE IT INTO + 0CC5 C3rE9s05 2371 JP MOVEDIR ; THE USERS DMA SPACE. + 2372 ; + 2373 ; FUNCTION TO RETURN THE NEXT OCCURENCE OF A FILE NAME. + 2374 ; + 0CC8 2ArD9s0D 2375 GETNXT: LD HL,(SAVEFCB) ; RESTORE POINTERS. NOTE THAT NO + 0CCB 22r43s03 2376 LD (PARAMS),HL ; OTHER .DBOS CALLS ARE ALLOWED. + 0CCE CDr51s0C 2377 CALL AUTOSEL ; NO ERROR WILL BE RETURNED, BUT THE + 0CD1 CDr2Ds07 2378 CALL FINDNXT ; RESULTS WILL BE WRONG. + 0CD4 C3rE9s05 2379 JP MOVEDIR + 2380 ; + 2381 ; FUNCTION TO DELETE A FILE BY NAME. + 2382 ; + 0CD7 CDr51s0C 2383 DELFILE:CALL AUTOSEL ; SELECT PROPER DRIVE. + 0CDA CDr9Cs07 2384 CALL ERAFILE ; ERASE THE FILE. + 0CDD C3r01s07 2385 JP STSTATUS ; SET STATUS AND RETURN. + 2386 ; + 2387 ; FUNCTION TO EXECUTE A S.EQUENTIAL READ OF THE SPECIFIED + 2388 ; RECORD NUMBER. + 2389 ; + 0CE0 CDr51s0C 2390 READSEQ:CALL AUTOSEL ; SELECT PROPER DRIVE THEN READ. + 0CE3 C3rBCs09 2391 JP RDSEQ + 2392 ; + 2393 ; FUNCTION TO WRITE THE NET S.EQUENTIAL RECORD. + 2394 ; + 0CE6 CDr51s0C 2395 WRTSEQ: CALL AUTOSEL ; SELECT PROPER DRIVE THEN WRITE. + 0CE9 C3rFEs09 2396 JP WTSEQ + 2397 ; + 2398 ; CREATE A FILE FUNCTION. + 2399 ; + 0CEC CDr72s05 2400 FCREATE:CALL CLEARS2 ; CLEAR THE 'S2' BYTE ON ALL CREATES. + 0CEF CDr51s0C 2401 CALL AUTOSEL ; SELECT PROPER DRIVE AND GET THE NEXT + 0CF2 C3r24s09 2402 JP GETEMPTY ; EMPTY DIRECTORY SPACE. + 2403 ; + 2404 ; FUNCTION TO RENAME A FILE. + 2405 ; + 0CF5 CDr51s0C 2406 RENFILE:CALL AUTOSEL ; SELECT PROPER DRIVE AND THEN SWITCH + 0CF8 CDr16s08 2407 CALL CHGNAMES ; FILE NAMES. + 0CFB C3r01s07 2408 JP STSTATUS + 2409 ; + 2410 ; FUNCTION TO RETURN THE LOGIN VECTOR. + 2411 ; + 0CFE 2ArAFs0D 2412 GETLOG: LD HL,(LOGIN) + 0D01 C3r29s0D 2413 JP GETPRM1 + 2414 ; + 2415 ; FUNCTION TO RETURN THE CURRENT DISK ASSIGNMENT. + 2416 ; + 0D04 3Ar42s03 2417 GETCRNT:LD A,(ACTIVE) + 0D07 C3r01s03 2418 JP SETSTAT + 2419 ; + 2420 ; FUNCTION TO SET THE DMA ADDRESS. + 2421 ; + 0D0A EB 2422 PUTDMA: EX DE,HL + 0D0B 22rB1s0D 2423 LD (USERDMA),HL ; SAVE IN OUR SPACE AND THEN GET TO + 0D0E C3rDAs05 2424 JP DEFDMA ; THE BIOS WITH THIS ALSO. + 2425 ; + 2426 ; FUNCTION TO RETURN THE ALLOCATION VECTOR. + 2427 ; + 0D11 2ArBFs0D 2428 GETALOC:LD HL,(ALOCVECT) + 0D14 C3r29s0D 2429 JP GETPRM1 + 2430 ; + 2431 ; FUNCTION TO RETURN THE READ-ONLY STATUS VECTOR. + 2432 ; + 0D17 2ArADs0D 2433 GETROV: LD HL,(WRTPRT) + 0D1A C3r29s0D 2434 JP GETPRM1 + 2435 ; + 2436 ; FUNCTION TO SET THE FILE ATTRIBUTES (READ-ONLY, SYSTEM). + 2437 ; + 0D1D CDr51s0C 2438 SETATTR:CALL AUTOSEL ; SELECT PROPER DRIVE THEN SAVE ATTRIBUTES. + 0D20 CDr3Bs08 2439 CALL SAVEATTR + 0D23 C3r01s07 2440 JP STSTATUS + 2441 ; + 2442 ; FUNCTION TO RETURN THE ADDRESS OF THE DISK PARAMETER BLOCK + 2443 ; FOR THE CURRENT DRIVE. + 2444 ; + 0D26 2ArBBs0D 2445 GETPARM:LD HL,(DISKPB) + 0D29 22r45s03 2446 GETPRM1:LD (STATUS),HL + 0D2C C9 2447 RET + 2448 ; + 2449 ; FUNCTION TO GET OR SET THE USER NUMBER. IF (E) WAS (FF) + 2450 ; THEN THIS IS A R.EQUEST TO RETURN THE CURRENT USER NUMBER. + 2451 ; ELSE SET THE USER NUMBER FROM (E). + 2452 ; + 0D2D 3ArD6s0D 2453 GETUSER:LD A,(EPARAM) ; GET PARAMETER. + 0D30 FE FF 2454 CP #0x0FF ; GET USER NUMBER? + 0D32 C2r3Bs0D 2455 JP NZ,SETUSER + 0D35 3Ar41s03 2456 LD A,(USERNO) ; YES, JUST DO IT. + 0D38 C3r01s03 2457 JP SETSTAT + 0D3B E6 1F 2458 SETUSER:AND #0x1F ; NO, WE SHOULD SET IT INSTEAD. KEEP LOW + 0D3D 32r41s03 2459 LD (USERNO),A ; BITS (0-4) ONLY. + 0D40 C9 2460 RET + 2461 ; + 2462 ; FUNCTION TO READ A RANDOM RECORD FROM A FILE. + 2463 ; + 0D41 2464 RDRANDOM: + 0D41 CDr51s0C 2465 CALL AUTOSEL ; SELECT PROPER DRIVE AND READ. + 0D44 C3r93s0B 2466 JP READRAN + 2467 ; + 2468 ; FUNCTION TO COMPUTE THE FILE SIZE FOR RANDOM FILES. + 2469 ; + 0D47 2470 WTRANDOM: + 0D47 CDr51s0C 2471 CALL AUTOSEL ; SELECT PROPER DRIVE AND WRITE. + 0D4A C3r9Cs0B 2472 JP WRITERAN + 2473 ; + 2474 ; FUNCTION TO COMPUTE THE SIZE OF A RANDOM FILE. + 2475 ; + 0D4D 2476 FILESIZE: + 0D4D CDr51s0C 2477 CALL AUTOSEL ; SELECT PROPER DRIVE AND CHECK FILE LENGTH + 0D50 C3rD2s0B 2478 JP RANSIZE + 2479 ; + 2480 ; FUNCTION #37. THIS ALLOWS A PROGRAM TO LOG OFF ANY DRIVES. + 2481 ; ON ENTRY, SET (DE) TO CONTAIN A WORD WITH BITS SET FOR THOSE + 2482 ; DRIVES THAT ARE TO BE LOGGED OFF. THE LOG-IN VECTOR AND THE + 2483 ; WRITE PROTECT VECTOR WILL BE UPDATED. THIS MUST BE A M/PM + 2484 ; SPECIAL FUNCTION. + 2485 ; + 0D53 2Ar43s03 2486 LOGOFF: LD HL,(PARAMS) ; GET DRIVES TO LOG OFF. + 0D56 7D 2487 LD A,L ; FOR EACH BIT THAT IS SET, WE WANT + 0D57 2F 2488 CPL ; TO CLEAR THAT BIT IN (LOGIN) + 0D58 5F 2489 LD E,A ; AND (WRTPRT). + 0D59 7C 2490 LD A,H + 0D5A 2F 2491 CPL + 0D5B 2ArAFs0D 2492 LD HL,(LOGIN) ; RESET THE LOGIN VECTOR. + 0D5E A4 2493 AND H + 0D5F 57 2494 LD D,A + 0D60 7D 2495 LD A,L + 0D61 A3 2496 AND E + 0D62 5F 2497 LD E,A + 0D63 2ArADs0D 2498 LD HL,(WRTPRT) + 0D66 EB 2499 EX DE,HL + 0D67 22rAFs0D 2500 LD (LOGIN),HL ; AND SAVE. + 0D6A 7D 2501 LD A,L ; NOW DO THE WRITE PROTECT VECTOR. + 0D6B A3 2502 AND E + 0D6C 6F 2503 LD L,A + 0D6D 7C 2504 LD A,H + 0D6E A2 2505 AND D + 0D6F 67 2506 LD H,A + 0D70 22rADs0D 2507 LD (WRTPRT),HL ; AND SAVE. ALL DONE. + 0D73 C9 2508 RET + 2509 ; + 2510 ; GET HERE TO RETURN TO THE USER. + 2511 ; + 0D74 3ArDEs0D 2512 GOBACK: LD A,(AUTO) ; WAS AUTO SELECT ACTIVATED? + 0D77 B7 2513 OR A + 0D78 CAr91s0D 2514 JP Z,GOBACK1 + 0D7B 2Ar43s03 2515 LD HL,(PARAMS) ; YES, BUT WAS A CHANGE MADE? + 0D7E 36 00 2516 LD (HL),#0 ; (* RESET FIRST BYTE OF FCB *) + 0D80 3ArE0s0D 2517 LD A,(AUTOFLAG) + 0D83 B7 2518 OR A + 0D84 CAr91s0D 2519 JP Z,GOBACK1 + 0D87 77 2520 LD (HL),A ; YES, RESET FIRST BYTE PROPERLY. + 0D88 3ArDFs0D 2521 LD A,(OLDDRV) ; AND GET THE OLD DRIVE AND SELECT IT. + 0D8B 32rD6s0D 2522 LD (EPARAM),A + 0D8E CDr45s0C 2523 CALL SETDSK + 0D91 2Ar0Fs03 2524 GOBACK1:LD HL,(USRSTACK) ; RESET THE USERS STACK POINTER. + 0D94 F9 2525 LD SP,HL + 0D95 2Ar45s03 2526 LD HL,(STATUS) ; GET RETURN STATUS. + 0D98 7D 2527 LD A,L ; FORCE VERSION 1.4 COMPATABILITY. + 0D99 44 2528 LD B,H + 0D9A C9 2529 RET ; AND GO BACK TO USER. + 2530 ; + 2531 ; FUNCTION #40. THIS IS A SPECIAL ENTRY TO DO RANDOM I/O. + 2532 ; FOR THE CASE WHERE WE ARE WRITING TO UNUSED DISK SPACE, THIS + 2533 ; SPACE WILL BE ZEROED OUT FIRST. THIS MUST BE A M/PM SPECIAL + 2534 ; PURPOSE FUNCTION, BECAUSE WHY WOULD ANY NORMAL PROGRAM EVEN + 2535 ; CARE ABOUT THE PREVIOUS CONTENTS OF A SECTOR ABOUT TO BE + 2536 ; WRITTEN OVER. + 2537 ; + 0D9B CDr51s0C 2538 WTSPECL:CALL AUTOSEL ; SELECT PROPER DRIVE. + 0D9E 3E 02 2539 LD A,#2 ; USE SPECIAL WRITE MODE. + 0DA0 32rD5s0D 2540 LD (MODE),A + 0DA3 0E 00 2541 LD C,#0 ; SET WRITE INDICATOR. + 0DA5 CDr07s0B 2542 CALL POSITN1 ; POSITION THE FILE. + 0DA8 CCr03s0A 2543 CALL Z,WTSEQ1 ; AND WRITE (IF NO ERRORS). + 0DAB C9 2544 RET + 2545 ; + 2546 ;************************************************************** + 2547 ;* + 2548 ;* BDOS DATA STORAGE POOL. + 2549 ;* + 2550 ;************************************************************** + 2551 ; + 0DAC 2552 EMPTYFCB: + 0DAC E5 2553 .DB 0x0E5 ; EMPTY DIRECTORY SEGMENT INDICATOR. + 0DAD 00 00 2554 WRTPRT: .DW 0 ; WRITE PROTECT STATUS FOR ALL 16 DRIVES. + 0DAF 00 00 2555 LOGIN: .DW 0 ; DRIVE ACTIVE WORD (1 BIT PER DRIVE). + 0DB1 80 00 2556 USERDMA:.DW 0x80 ; USER'S DMA ADDRESS (DEFAULTS TO 80H). + 2557 ; + 2558 ; SCRATCH AREAS FROM PARAMETER BLOCK. + 2559 ; + 0DB3 2560 SCRATCH1: + 0DB3 00 00 2561 .DW 0 ; RELATIVE POSITION WITHIN DIR SEGMENT FOR FILE (0-3). + 0DB5 2562 SCRATCH2: + 0DB5 00 00 2563 .DW 0 ; LAST SELECTED TRACK NUMBER. + 0DB7 2564 SCRATCH3: + 0DB7 00 00 2565 .DW 0 ; LAST SELECTED SECTOR NUMBER. + 2566 ; + 2567 ; DISK STORAGE AREAS FROM PARAMETER BLOCK. + 2568 ; + 0DB9 00 00 2569 DIRBUF: .DW 0 ; ADDRESS OF DIRECTORY BUFFER TO USE. + 0DBB 00 00 2570 DISKPB: .DW 0 ; CONTAINS ADDRESS OF DISK PARAMETER BLOCK. + 0DBD 00 00 2571 CHKVECT:.DW 0 ; ADDRESS OF CHECK VECTOR. + 0DBF 2572 ALOCVECT: + 0DBF 00 00 2573 .DW 0 ; ADDRESS OF ALLOCATION VECTOR (BIT MAP). + 2574 ; + 2575 ; PARAMETER BLOCK RETURNED FROM THE BIOS. + 2576 ; + 0DC1 00 00 2577 SECTORS:.DW 0 ; SECTORS PER TRACK FROM BIOS. + 0DC3 00 2578 BLKSHFT:.DB 0 ; BLOCK SHIFT. + 0DC4 00 2579 BLKMASK:.DB 0 ; BLOCK MASK. + 0DC5 00 2580 EXTMASK:.DB 0 ; EXTENT MASK. + 0DC6 00 00 2581 DSKSIZE:.DW 0 ; DISK SIZE FROM BIOS (NUMBER OF BLOCKS-1). + 0DC8 00 00 2582 DIRSIZE:.DW 0 ; DIRECTORY SIZE. + 0DCA 00 00 2583 ALLOC0: .DW 0 ; STORAGE FOR FIRST BYTES OF BIT MAP (DIR SPACE USED). + 0DCC 00 00 2584 ALLOC1: .DW 0 + 0DCE 00 00 2585 OFFSET: .DW 0 ; FIRST USABLE TRACK NUMBER. + 0DD0 00 00 2586 XLATE: .DW 0 ; SECTOR TRANSLATION TABLE ADDRESS. + 2587 ; + 2588 ; + 0DD2 2589 CLOSEFLG: + 0DD2 00 2590 .DB 0 ; CLOSE FLAG (=0FFH IS EXTENT WRITTEN OK). + 0DD3 2591 R.DWRTFLG: + 0DD3 00 2592 .DB 0 ; READ/WRITE FLAG (0FFH=READ, 0=WRITE). + 0DD4 00 2593 FNDSTAT:.DB 0 ; FILENAME FOUND STATUS (0=FOUND FIRST ENTRY). + 0DD5 00 2594 MODE: .DB 0 ; I/O MODE SELECT (0=RANDOM, 1=S.EQUENTIAL, 2=SPECIAL RANDOM). + 0DD6 00 2595 EPARAM: .DB 0 ; STORAGE FOR REGISTER (E) ON ENTRY TO BDOS. + 0DD7 2596 RELBLOCK: + 0DD7 00 2597 .DB 0 ; RELATIVE POSITION WITHIN FCB OF BLOCK NUMBER WRITTEN. + 0DD8 00 2598 COUNTER:.DB 0 ; BYTE COUNTER FOR DIRECTORY NAME SEARCHES. + 0DD9 00 00 00 00 2599 SAVEFCB:.DW 0,0 ; SAVE SPACE FOR ADDRESS OF FCB (FOR DIRECTORY SEARCHES). + 0DDD 00 2600 BIGDISK:.DB 0 ; IF =0 THEN DISK IS > 256 BLOCKS LONG. + 0DDE 00 2601 AUTO: .DB 0 ; IF NON-ZERO, THEN AUTO SELECT ACTIVATED. + 0DDF 00 2602 OLDDRV: .DB 0 ; ON AUTO SELECT, STORAGE FOR PREVIOUS DRIVE. + 0DE0 2603 AUTOFLAG: + 0DE0 00 2604 .DB 0 ; IF NON-ZERO, THEN AUTO SELECT CHANGED DRIVES. + 0DE1 00 2605 SAVNXT: .DB 0 ; STORAGE FOR NEXT RECORD NUMBER TO ACCESS. + 0DE2 00 2606 SAVEXT: .DB 0 ; STORAGE FOR EXTENT NUMBER OF FILE. + 0DE3 00 00 2607 SAVNREC:.DW 0 ; STORAGE FOR NUMBER OF RECORDS IN FILE. + 0DE5 00 00 2608 BLKNMBR:.DW 0 ; BLOCK NUMBER (PHYSICAL SECTOR) USED WITHIN A FILE OR LOGICAL SEC + 0DE7 00 00 2609 LOGSECT:.DW 0 ; STARTING LOGICAL (128 BYTE) SECTOR OF BLOCK (PHYSICAL SECTOR). + 0DE9 00 2610 FCBPOS: .DB 0 ; RELATIVE POSITION WITHIN BUFFER FOR FCB OF FILE OF INTEREST. + 0DEA 00 00 2611 FILEPOS:.DW 0 ; FILES POSITION WITHIN DIRECTORY (0 TO MAX ENTRIES -1). + 2612 ; + 2613 ; DISK DIRECTORY BUFFER CHECKSUM BYTES. ONE FOR EACH OF THE + 2614 ; 16 POSSIBLE DRIVES. + 2615 ; + 0DEC 2616 CKSUMTBL: + 0DEC 00 00 00 00 00 00 2617 .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + 00 00 00 00 00 00 + 00 00 00 00 + 2618 ; + 2619 ;************************************************************** + 2620 ;* + 2621 ;* B I O S J U M P T A B L E + 2622 ;* + 2623 ;************************************************************** + 2624 ; + 2625 + E600 2626 BIOS = BIOSO ;BIOS ORIGIN + 2627 ; + E600 2628 BOOT = BIOS ;(BOOT) Cold boot entry + E603 2629 WBOOT = BIOS+3 ;Warm boot entry + E606 2630 CONST = BIOS+6 ;Console status + E609 2631 CONIN = BIOS+9 ;Console char in + E60C 2632 CONOUT = BIOS+12 ;Console char out + E60F 2633 LIST = BIOS+15 ;List char out + E612 2634 PUNCH = BIOS+18 ;Punch char out + E615 2635 READER = BIOS+21 ;Reader char in + E618 2636 HOME = BIOS+24 ;Home disk + E61B 2637 SELDSK = BIOS+27 ;Select disk + E61E 2638 SETTRK = BIOS+30 ;Set disk track addr + E621 2639 SETSEC = BIOS+33 ;Set disk sector addr + E624 2640 SETDMA = BIOS+36 ;Set DMA buffer addr + E627 2641 READ = BIOS+39 ;Read sector + E62A 2642 WRITE = BIOS+42 ;Write sector + E630 2643 SECTRN = BIOS+48 ;Sector translation routine + 2644 ; + 2645 ;dwg; .IF ENDFIL + 2646 ;dwg; .ORG BDOSO+0DFFH + 2647 ;dwg; .DB 55H + 2648 ;dwg; .ENDIF + 2649 + 2650 ;dwg; .END + 2651 + 0DFC 2652 _bdos_end:: + 2653 .area _CODE + 2654 .area _CABS diff --git a/doug/src/bdosb01.rel b/doug/src/bdosb01.rel new file mode 100755 index 00000000..9c37b3e5 --- /dev/null +++ b/doug/src/bdosb01.rel @@ -0,0 +1,714 @@ +XL +H 8 areas 4 global symbols +M bdosb01 +O -mz80 +S .__.ABS. Def0000 +A _CODE size 0 flags 0 addr 0 +S _bdos Def0000 +S _bdos_start Def0000 +A _DATA size 0 flags 0 addr 0 +A _OVERLAY size 0 flags 0 addr 0 +A _HOME size 0 flags 0 addr 0 +A _GSINIT size 0 flags 0 addr 0 +A _GSFINAL size 0 flags 0 addr 0 +A _BDOSB01 size DFC flags 0 addr 0 +S _bdos_end Def0DFC +A _CABS size 0 flags 0 addr 0 +T 00 00 +R 00 00 00 00 +T 00 00 +R 00 00 00 00 +T 00 00 00 00 00 00 00 00 C3 11 00 99 00 A5 00 +R 00 00 06 00 00 09 06 00 00 0B 06 00 00 0D 06 00 +T 0D 00 AB 00 B1 00 EB 22 43 03 EB 7B 32 +R 00 00 06 00 00 02 06 00 00 04 06 00 00 08 06 00 +T 18 00 D6 0D 21 00 00 22 45 03 39 22 0F 03 31 +R 00 00 06 00 00 02 06 00 00 08 06 00 00 0C 06 00 +T 25 00 41 03 AF 32 E0 0D 32 DE 0D 21 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T 2F 00 74 0D E5 79 FE 29 D0 4B 21 47 00 5F 16 00 +R 00 00 06 00 00 02 06 00 00 0B 06 00 +T 3D 00 19 19 5E 23 56 2A 43 03 EB E9 03 E6 C8 02 +R 00 00 06 00 00 08 06 00 00 0E 06 00 +T 4B 00 90 01 CE 02 12 E6 0F E6 D4 02 +R 00 00 06 00 00 02 06 00 00 04 06 00 00 0A 06 00 +T 55 00 ED 02 F3 02 F8 02 +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 5B 00 E1 01 FE 02 7E 0C +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 61 00 83 0C 45 0C 9C 0C +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 67 00 A5 0C AB 0C C8 0C +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 6D 00 D7 0C E0 0C E6 0C +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 73 00 EC 0C F5 0C FE 0C +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 79 00 04 0D 0A 0D 11 0D +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 7F 00 2C 05 17 0D 1D 0D +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 85 00 26 0D 2D 0D 41 0D +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 8B 00 47 0D 4D 0D 0E 0C +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 91 00 53 0D 04 03 04 03 +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 97 00 9B 0D 21 CA 00 CD E5 00 FE 03 CA 00 00 C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T A5 00 21 D5 00 C3 B4 00 21 E1 00 C3 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T AF 00 B4 00 21 DC 00 CD E5 00 C3 00 00 42 44 4F +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T BD 00 53 20 45 52 52 20 4F 4E 20 20 3A 20 24 42 +R 00 00 06 00 +T CB 00 41 44 20 53 45 43 54 4F 52 24 53 45 4C 45 +R 00 00 06 00 +T D9 00 43 54 24 46 49 4C 45 20 52 2F 4F 24 E5 CD +R 00 00 06 00 +T E7 00 C9 01 3A 42 03 C6 41 32 C6 00 01 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T F2 00 BA 00 CD D3 01 C1 CD D3 01 21 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T FC 00 0E 03 7E 36 00 B7 C0 C3 09 E6 CD FB 00 CD +R 00 00 06 00 00 02 06 00 00 0D 06 00 +T 0A 01 14 01 D8 F5 4F CD 90 01 F1 C9 FE 0D C8 FE +R 00 00 06 00 00 02 06 00 00 08 06 00 +T 18 01 0A C8 FE 09 C8 FE 08 C8 FE 20 C9 +R 00 00 06 00 +T 23 01 +R 00 00 06 00 +T 23 01 3A 0E 03 B7 C2 45 01 CD 06 E6 E6 01 C8 CD +R 00 00 06 00 00 03 06 00 00 07 06 00 +T 31 01 09 E6 FE 13 C2 42 01 CD 09 E6 FE 03 CA +R 00 00 06 00 00 07 06 00 +T 3E 01 00 00 AF C9 32 0E 03 3E 01 C9 3A 0A 03 B7 +R 00 00 06 00 00 07 06 00 00 0D 06 00 +T 4C 01 C2 62 01 C5 CD 23 01 C1 C5 CD 0C E6 C1 C5 +R 00 00 06 00 00 03 06 00 00 07 06 00 +T 5A 01 3A 0D 03 B7 C4 0F E6 C1 79 21 0C 03 FE 7F +R 00 00 06 00 00 03 06 00 00 0C 06 00 +T 68 01 C8 34 FE 20 D0 35 7E B7 C8 79 FE 08 C2 +R 00 00 06 00 +T 75 01 79 01 35 C9 FE 0A C0 36 00 C9 79 CD 14 01 +R 00 00 06 00 00 02 06 00 00 0E 06 00 +T 83 01 D2 90 01 F5 0E 5E CD 48 01 F1 F6 40 4F 79 +R 00 00 06 00 00 03 06 00 00 09 06 00 +T 91 01 FE 09 C2 48 01 0E 20 CD 48 01 3A 0C 03 E6 +R 00 00 06 00 00 05 06 00 00 0A 06 00 00 0D 06 00 +T 9F 01 07 C2 96 01 C9 CD AC 01 0E 20 CD 0C E6 0E +R 00 00 06 00 00 04 06 00 00 08 06 00 +T AD 01 08 C3 0C E6 0E 23 CD 48 01 CD C9 01 3A +R 00 00 06 00 00 09 06 00 00 0C 06 00 +T BA 01 0C 03 21 0B 03 BE D0 0E 20 CD 48 01 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0C 06 00 +T C7 01 B9 01 0E 0D CD 48 01 0E 0A C3 48 01 0A FE +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0C 06 00 +T D5 01 24 C8 03 C5 4F CD 90 01 C1 C3 D3 01 3A +R 00 00 06 00 00 08 06 00 00 0C 06 00 +T E2 01 0C 03 32 0B 03 2A 43 03 4E 23 E5 06 00 C5 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T F0 01 E5 CD FB 00 E6 7F E1 C1 FE 0D CA C1 02 FE +R 00 00 06 00 00 04 06 00 00 0D 06 00 +T FE 01 0A CA C1 02 FE 08 C2 16 02 78 B7 CA EF 01 +R 00 00 06 00 00 04 06 00 00 09 06 00 00 0E 06 00 +T 0C 02 05 3A 0C 03 32 0A 03 C3 70 02 FE 7F C2 +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T 19 02 26 02 78 B7 CA EF 01 7E 05 2B C3 A9 02 FE +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0D 06 00 +T 27 02 05 C2 37 02 C5 E5 CD C9 01 AF 32 0B 03 C3 +R 00 00 06 00 00 04 06 00 00 09 06 00 00 0D 06 00 +T 35 02 F1 01 FE 10 C2 48 02 E5 21 0D 03 3E 01 96 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0B 06 00 +T 43 02 77 E1 C3 EF 01 FE 18 C2 5F 02 E1 3A 0B 03 +R 00 00 06 00 00 05 06 00 00 0A 06 00 00 0E 06 00 +T 51 02 21 0C 03 BE D2 E1 01 35 CD A4 01 C3 +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0B 06 00 +T 5D 02 4E 02 FE 15 C2 6B 02 CD B1 01 E1 C3 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T 69 02 E1 01 FE 12 C2 A6 02 C5 CD B1 01 C1 E1 E5 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0B 06 00 +T 77 02 C5 78 B7 CA 8A 02 23 4E 05 C5 E5 CD 7F 01 +R 00 00 06 00 00 06 06 00 00 0E 06 00 +T 85 02 E1 C1 C3 78 02 E5 3A 0A 03 B7 CA F1 01 21 +R 00 00 06 00 00 05 06 00 00 09 06 00 00 0D 06 00 +T 93 02 0C 03 96 32 0A 03 CD A4 01 21 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T 9D 02 0A 03 35 C2 99 02 C3 F1 01 23 77 04 C5 E5 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T AB 02 4F CD 7F 01 E1 C1 7E FE 03 78 C2 BD 02 FE +R 00 00 06 00 00 04 06 00 00 0D 06 00 +T B9 02 01 CA 00 00 B9 DA EF 01 E1 70 0E 0D C3 +R 00 00 06 00 00 08 06 00 +T C6 02 48 01 CD 06 01 C3 01 03 CD 15 E6 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T D2 02 01 03 79 3C CA E0 02 3C CA 06 E6 C3 0C E6 +R 00 00 06 00 00 02 06 00 00 07 06 00 +T E0 02 CD 06 E6 B7 CA 91 0D CD 09 E6 C3 01 03 3A +R 00 00 06 00 00 07 06 00 00 0D 06 00 +T EE 02 03 00 C3 01 03 21 03 00 71 C9 EB 4D 44 C3 +R 00 00 06 00 00 05 06 00 +T FC 02 D3 01 CD 23 01 32 45 03 C9 3E 01 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 08 03 01 03 00 +R 00 00 06 00 00 02 06 00 +T 0B 03 +R 00 00 06 00 +T 0B 03 02 00 00 00 +R 00 00 06 00 +T 0F 03 +R 00 00 06 00 +T 0F 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 1D 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 2B 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 39 03 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 41 03 +R 00 00 06 00 +T 41 03 00 00 00 00 00 00 21 0B 00 5E 23 56 EB E9 +R 00 00 06 00 00 09 06 00 +T 4F 03 0C 0D C8 1A 77 13 23 C3 50 03 3A 42 03 4F +R 00 00 06 00 00 0A 06 00 00 0D 06 00 +T 5D 03 CD 1B E6 7C B5 C8 5E 23 56 23 22 B3 0D 23 +R 00 00 06 00 00 0D 06 00 +T 6B 03 23 22 B5 0D 23 23 22 B7 0D 23 23 EB 22 +R 00 00 06 00 00 04 06 00 00 09 06 00 +T 78 03 D0 0D 21 B9 0D 0E 08 CD 4F 03 2A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T 83 03 BB 0D EB 21 C1 0D 0E 0F CD 4F 03 2A +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0B 06 00 +T 8F 03 C6 0D 7C 21 DD 0D 36 FF B7 CA 9D 03 36 00 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0C 06 00 +T 9D 03 3E FF B7 C9 CD 18 E6 AF 2A B5 0D 77 23 77 +R 00 00 06 00 00 0B 06 00 +T AB 03 2A B7 0D 77 23 77 C9 CD 27 E6 C3 BB 03 CD +R 00 00 06 00 00 03 06 00 00 0D 06 00 +T B9 03 2A E6 B7 C8 21 09 00 C3 4A 03 2A EA 0D 0E +R 00 00 06 00 00 07 06 00 00 0A 06 00 00 0D 06 00 +T C7 03 02 CD EA 04 22 E5 0D 22 EC 0D 21 +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T D2 03 E5 0D 4E 23 46 2A B7 0D 5E 23 56 2A B5 0D +R 00 00 06 00 00 02 06 00 00 08 06 00 00 0E 06 00 +T E0 03 7E 23 66 6F 79 93 78 9A D2 FA 03 E5 2A +R 00 00 06 00 00 0B 06 00 +T ED 03 C1 0D 7B 95 5F 7A 9C 57 E1 2B C3 E4 03 E5 +R 00 00 06 00 00 02 06 00 00 0D 06 00 +T FB 03 2A C1 0D 19 DA 0F 04 79 95 78 9C DA 0F 04 +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0E 06 00 +T 09 04 EB E1 23 C3 FA 03 E1 C5 D5 E5 EB 2A CE 0D +R 00 00 06 00 00 06 06 00 00 0E 06 00 +T 17 04 19 44 4D CD 1E E6 D1 2A B5 0D 73 23 72 D1 +R 00 00 06 00 00 0A 06 00 +T 25 04 2A B7 0D 73 23 72 C1 79 93 4F 78 9A 47 2A +R 00 00 06 00 00 03 06 00 +T 33 04 D0 0D EB CD 30 E6 4D 44 C3 21 E6 +R 00 00 06 00 00 02 06 00 +T 3E 04 +R 00 00 06 00 +T 3E 04 21 C3 0D 4E 3A E3 0D B7 1F 0D C2 45 04 47 +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0D 06 00 +T 4C 04 3E 08 96 4F 3A E2 0D 0D CA 5C 04 B7 17 C3 +R 00 00 06 00 00 07 06 00 00 0B 06 00 +T 5A 04 53 04 80 C9 2A 43 03 11 10 00 19 09 3A +R 00 00 06 00 00 02 06 00 00 07 06 00 +T 67 04 DD 0D B7 CA 71 04 6E 26 00 C9 09 5E 23 56 +R 00 00 06 00 00 02 06 00 00 06 06 00 +T 75 04 EB C9 CD 3E 04 4F 06 00 CD 5E 04 22 E5 0D +R 00 00 06 00 00 05 06 00 00 0B 06 00 00 0E 06 00 +T 83 04 C9 2A E5 0D 7D B4 C9 3A C3 0D 2A E5 0D 29 +R 00 00 06 00 00 04 06 00 00 0A 06 00 00 0D 06 00 +T 91 04 3D C2 90 04 22 E7 0D 3A C4 0D 4F 3A +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T 9D 04 E3 0D A1 B5 6F 22 E5 0D C9 2A 43 03 11 +R 00 00 06 00 00 02 06 00 00 08 06 00 00 0C 06 00 +T AA 04 0C 00 19 C9 2A 43 03 11 0F 00 19 EB 21 +R 00 00 06 00 00 07 06 00 +T B7 04 11 00 19 C9 CD AE 04 7E 32 E3 0D EB 7E 32 +R 00 00 06 00 00 07 06 00 00 0B 06 00 +T C5 04 E1 0D CD A6 04 3A C5 0D A6 32 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T CF 04 E2 0D C9 CD AE 04 3A D5 0D FE 02 C2 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T DB 04 DE 04 AF 4F 3A E3 0D 81 77 EB 3A E1 0D 77 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0D 06 00 +T E9 04 C9 0C 0D C8 7C B7 1F 67 7D 1F 6F C3 EB 04 +R 00 00 06 00 00 0E 06 00 +T F7 04 +R 00 00 06 00 +T F7 04 0E 80 2A B9 0D AF 86 23 0D C2 FD 04 C9 0C +R 00 00 06 00 00 05 06 00 00 0C 06 00 +T 05 05 0D C8 29 C3 05 05 C5 3A 42 03 4F 21 01 00 +R 00 00 06 00 00 06 06 00 00 0A 06 00 +T 13 05 CD 04 05 C1 79 B5 6F 78 B4 67 C9 2A AD 0D +R 00 00 06 00 00 03 06 00 00 0E 06 00 +T 21 05 3A 42 03 4F CD EA 04 7D E6 01 C9 21 AD 0D +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0E 06 00 +T 2F 05 4E 23 46 CD 0B 05 22 AD 0D 2A C8 0D 23 EB +R 00 00 06 00 00 06 06 00 00 09 06 00 00 0C 06 00 +T 3D 05 2A B3 0D 73 23 72 C9 CD 5E 05 11 09 00 19 +R 00 00 06 00 00 03 06 00 00 0A 06 00 +T 4B 05 7E 17 D0 21 0F 00 C3 4A 03 CD 1E 05 C8 21 +R 00 00 06 00 00 06 06 00 00 09 06 00 00 0C 06 00 +T 59 05 0D 00 C3 4A 03 2A B9 0D 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 62 05 E9 0D 85 6F D0 24 C9 2A 43 03 11 0E 00 19 +R 00 00 06 00 00 02 06 00 00 0A 06 00 +T 70 05 7E C9 CD 69 05 36 00 C9 CD 69 05 F6 80 77 +R 00 00 06 00 00 05 06 00 00 0B 06 00 +T 7E 05 C9 2A EA 0D EB 2A B3 0D 7B 96 23 7A 9E C9 +R 00 00 06 00 00 04 06 00 00 08 06 00 +T 8C 05 CD 7F 05 D8 13 72 2B 73 C9 7B 95 6F 7A 9C +R 00 00 06 00 00 03 06 00 +T 9A 05 67 C9 0E FF +R 00 00 06 00 +T 9E 05 +R 00 00 06 00 +T 9E 05 2A EC 0D EB 2A CC 0D CD 95 05 D0 C5 CD +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0A 06 00 +T AB 05 F7 04 2A BD 0D EB 2A EC 0D 19 C1 0C CA +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T B8 05 C4 05 BE C8 CD 7F 05 D0 CD 2C 05 C9 77 C9 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0B 06 00 +T C6 05 +R 00 00 06 00 +T C6 05 CD 9C 05 CD E0 05 0E 01 CD B8 03 C3 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0B 06 00 +T D2 05 DA 05 CD E0 05 CD B2 03 21 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T DB 05 B1 0D C3 E3 05 21 B9 0D 4E 23 46 C3 24 E6 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T E9 05 2A B9 0D EB 2A B1 0D 0E 80 C3 4F 03 +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0C 06 00 +T F5 05 +R 00 00 06 00 +T F5 05 21 EA 0D 7E 23 BE C0 3C C9 +R 00 00 06 00 00 03 06 00 +T FE 05 +R 00 00 06 00 +T FE 05 21 FF FF 22 EA 0D C9 2A C8 0D EB 2A EA 0D +R 00 00 06 00 00 06 06 00 00 0A 06 00 00 0E 06 00 +T 0C 06 23 22 EA 0D CD 95 05 D2 19 06 C3 +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T 17 06 FE 05 3A EA 0D E6 03 06 05 87 05 C2 20 06 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0E 06 00 +T 25 06 32 E9 0D B7 C0 C5 CD C3 03 CD D4 05 C1 C3 +R 00 00 06 00 00 03 06 00 00 09 06 00 00 0C 06 00 +T 33 06 9E 05 +R 00 00 06 00 00 02 06 00 +T 35 06 +R 00 00 06 00 +T 35 06 79 E6 07 3C 5F 57 79 0F 0F 0F E6 1F 4F 78 +R 00 00 06 00 +T 43 06 87 87 87 87 87 B1 4F 78 0F 0F 0F E6 1F 47 +R 00 00 06 00 +T 51 06 2A BF 0D 09 7E 07 1D C2 56 06 C9 +R 00 00 06 00 00 03 06 00 00 0A 06 00 +T 5C 06 +R 00 00 06 00 +T 5C 06 D5 CD 35 06 E6 FE C1 B1 0F 15 C2 64 06 77 +R 00 00 06 00 00 04 06 00 00 0D 06 00 +T 6A 06 C9 CD 5E 05 11 10 00 19 C5 0E 11 D1 0D C8 +R 00 00 06 00 00 04 06 00 +T 78 06 D5 3A DD 0D B7 CA 88 06 C5 E5 4E 06 00 C3 +R 00 00 06 00 00 04 06 00 00 08 06 00 +T 86 06 8E 06 0D C5 4E 23 46 E5 79 B0 CA 9D 06 2A +R 00 00 06 00 00 02 06 00 00 0D 06 00 +T 94 06 C6 0D 7D 91 7C 98 D4 5C 06 E1 23 C1 C3 +R 00 00 06 00 00 02 06 00 00 09 06 00 +T A1 06 75 06 2A C6 0D 0E 03 CD EA 04 23 44 4D 2A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T AF 06 BF 0D 36 00 23 0B 78 B1 C2 B1 06 2A CA 0D +R 00 00 06 00 00 02 06 00 00 0B 06 00 00 0E 06 00 +T BD 06 EB 2A BF 0D 73 23 72 CD A1 03 2A B3 0D 36 +R 00 00 06 00 00 04 06 00 00 0A 06 00 00 0D 06 00 +T CB 06 03 23 36 00 CD FE 05 0E FF CD 05 06 CD +R 00 00 06 00 00 07 06 00 00 0C 06 00 +T D8 06 F5 05 C8 CD 5E 05 3E E5 BE CA D2 06 3A +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0C 06 00 +T E5 06 41 03 BE C2 F6 06 23 7E D6 24 C2 F6 06 3D +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0D 06 00 +T F3 06 32 45 03 0E 01 CD 6B 06 CD 8C 05 C3 +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0B 06 00 +T FF 06 D2 06 +R 00 00 06 00 00 02 06 00 +T 01 07 +R 00 00 06 00 +T 01 07 3A D4 0D C3 01 03 C5 F5 3A C5 0D 2F 47 79 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0B 06 00 +T 0F 07 A0 4F F1 A0 91 E6 1F C1 C9 3E FF 32 D4 0D +R 00 00 06 00 00 0E 06 00 +T 1D 07 21 D8 0D 71 2A 43 03 22 D9 0D CD +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0A 06 00 +T 28 07 FE 05 CD A1 03 0E 00 CD 05 06 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T 33 07 F5 05 CA 94 07 2A D9 0D EB 1A FE E5 CA +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 40 07 4A 07 D5 CD 7F 05 D1 D2 94 07 CD +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0A 06 00 +T 4B 07 5E 05 3A D8 0D 4F 06 00 79 B7 CA 83 07 1A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0D 06 00 +T 59 07 FE 3F CA 7C 07 78 FE 0D CA 7C 07 FE 0C 1A +R 00 00 06 00 00 05 06 00 00 0B 06 00 +T 67 07 CA 73 07 96 E6 7F C2 2D 07 C3 7C 07 C5 4E +R 00 00 06 00 00 03 06 00 00 09 06 00 00 0C 06 00 +T 75 07 CD 07 07 C1 C2 2D 07 13 23 04 0D C3 53 07 +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0E 06 00 +T 83 07 3A EA 0D E6 03 32 45 03 21 D4 0D 7E 17 D0 +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0B 06 00 +T 91 07 AF 77 C9 CD FE 05 3E FF C3 01 03 CD 54 05 +R 00 00 06 00 00 06 06 00 00 0B 06 00 00 0E 06 00 +T 9F 07 0E 0C CD 18 07 CD F5 05 C8 CD 44 05 CD +R 00 00 06 00 00 05 06 00 00 08 06 00 00 0C 06 00 +T AC 07 5E 05 36 E5 0E 00 CD 6B 06 CD C6 05 CD +R 00 00 06 00 00 02 06 00 00 09 06 00 00 0C 06 00 +T B9 07 2D 07 C3 A4 07 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T BE 07 +R 00 00 06 00 +T BE 07 50 59 79 B0 CA D1 07 0B D5 C5 CD 35 06 1F +R 00 00 06 00 00 07 06 00 00 0D 06 00 +T CC 07 D2 EC 07 C1 D1 2A C6 0D 7B 95 7A 9C D2 +R 00 00 06 00 00 03 06 00 00 08 06 00 +T D9 07 F4 07 13 C5 D5 42 4B CD 35 06 1F D2 EC 07 +R 00 00 06 00 00 02 06 00 00 0A 06 00 00 0E 06 00 +T E7 07 D1 C1 C3 C0 07 17 3C CD 64 06 E1 D1 C9 79 +R 00 00 06 00 00 05 06 00 00 0A 06 00 +T F5 07 B0 C2 C0 07 21 00 00 C9 0E 00 1E 20 D5 06 +R 00 00 06 00 00 04 06 00 +T 03 08 00 2A 43 03 09 EB CD 5E 05 C1 CD 4F 03 CD +R 00 00 06 00 00 04 06 00 00 09 06 00 00 0D 06 00 +T 11 08 C3 03 C3 C6 05 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 16 08 +R 00 00 06 00 +T 16 08 CD 54 05 0E 0C CD 18 07 2A 43 03 7E 11 +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0B 06 00 +T 23 08 10 00 19 77 CD F5 05 C8 CD 44 05 0E 10 1E +R 00 00 06 00 00 07 06 00 00 0B 06 00 +T 31 08 0C CD 01 08 CD 2D 07 C3 27 08 +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T 3B 08 +R 00 00 06 00 +T 3B 08 0E 0C CD 18 07 CD F5 05 C8 0E 00 1E 0C CD +R 00 00 06 00 00 05 06 00 00 08 06 00 +T 49 08 01 08 CD 2D 07 C3 40 08 0E 0F CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 54 08 18 07 CD F5 05 C8 CD A6 04 7E F5 E5 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T 61 08 5E 05 EB 2A 43 03 0E 20 D5 CD 4F 03 CD +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0C 06 00 +T 6E 08 78 05 D1 21 0C 00 19 4E 21 0F 00 19 46 E1 +R 00 00 06 00 00 02 06 00 +T 7C 08 F1 77 79 BE 78 CA 8B 08 3E 00 DA 8B 08 3E +R 00 00 06 00 00 08 06 00 00 0D 06 00 +T 8A 08 80 2A 43 03 11 0F 00 19 77 C9 +R 00 00 06 00 00 04 06 00 +T 94 08 +R 00 00 06 00 +T 94 08 7E 23 B6 2B C0 1A 77 13 23 1A 77 1B 2B C9 +R 00 00 06 00 +T A2 08 AF 32 45 03 32 EA 0D 32 EB 0D CD +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T AD 08 1E 05 C0 CD 69 05 E6 80 C0 0E 0F CD 18 07 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0E 06 00 +T BB 08 CD F5 05 C8 01 10 00 CD 5E 05 09 EB 2A +R 00 00 06 00 00 03 06 00 00 0A 06 00 +T C8 08 43 03 09 0E 10 +R 00 00 06 00 00 02 06 00 +T CD 08 +R 00 00 06 00 +T CD 08 3A DD 0D B7 CA E8 08 7E B7 1A C2 DB 08 77 +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0D 06 00 +T DB 08 +R 00 00 06 00 +T DB 08 B7 C2 E1 08 7E 12 +R 00 00 06 00 00 04 06 00 +T E1 08 +R 00 00 06 00 +T E1 08 BE C2 1F 09 C3 FD 08 +R 00 00 06 00 00 04 06 00 00 07 06 00 +T E8 08 +R 00 00 06 00 +T E8 08 CD 94 08 EB CD 94 08 EB 1A BE C2 1F 09 13 +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0D 06 00 +T F6 08 23 1A BE C2 1F 09 0D +R 00 00 06 00 00 06 06 00 +T FD 08 +R 00 00 06 00 +T FD 08 13 23 0D C2 CD 08 01 EC FF 09 EB 09 1A BE +R 00 00 06 00 00 06 06 00 +T 0B 09 DA 17 09 77 01 03 00 09 EB 09 7E 12 +R 00 00 06 00 00 03 06 00 +T 17 09 +R 00 00 06 00 +T 17 09 3E FF 32 D2 0D C3 10 08 +R 00 00 06 00 00 05 06 00 00 08 06 00 +T 1F 09 +R 00 00 06 00 +T 1F 09 21 45 03 35 C9 +R 00 00 06 00 00 03 06 00 +T 24 09 +R 00 00 06 00 +T 24 09 CD 54 05 2A 43 03 E5 21 AC 0D 22 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0A 06 00 +T 2F 09 43 03 0E 01 CD 18 07 CD F5 05 E1 22 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T 3B 09 43 03 C8 EB 21 0F 00 19 0E 11 AF 77 23 0D +R 00 00 06 00 00 02 06 00 +T 49 09 C2 46 09 21 0D 00 19 77 CD 8C 05 CD FD 07 +R 00 00 06 00 00 03 06 00 00 0B 06 00 00 0E 06 00 +T 57 09 C3 78 05 AF 32 D2 0D CD A2 08 CD +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0A 06 00 +T 62 09 F5 05 C8 2A 43 03 01 0C 00 09 7E 3C E6 1F +R 00 00 06 00 00 02 06 00 00 06 06 00 +T 70 09 77 CA 83 09 47 3A C5 0D A0 21 D2 0D A6 CA +R 00 00 06 00 00 04 06 00 00 08 06 00 00 0C 06 00 +T 7E 09 8E 09 C3 AC 09 01 02 00 09 34 7E E6 0F CA +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 8C 09 B6 09 0E 0F CD 18 07 CD F5 05 C2 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T 97 09 AC 09 3A D3 0D 3C CA B6 09 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T A1 09 24 09 CD F5 05 CA B6 09 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T AA 09 AF 09 CD 5A 08 CD BB 04 AF C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T B4 09 01 03 CD 05 03 C3 78 05 3E 01 32 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T BF 09 D5 0D 3E FF 32 D3 0D CD BB 04 3A +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T CA 09 E3 0D 21 E1 0D BE DA E6 09 FE 80 C2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T D6 09 FB 09 CD 5A 09 AF 32 E3 0D 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T E0 09 45 03 B7 C2 FB 09 CD 77 04 CD +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T EA 09 84 04 CA FB 09 CD 8A 04 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T F3 09 D1 03 CD B2 03 C3 D2 04 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T FC 09 05 03 3E 01 32 D5 0D 3E 00 32 D3 0D CD +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0C 06 00 +T 09 0A 54 05 2A 43 03 CD 47 05 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 12 0A BB 04 3A E3 0D FE 80 D2 05 03 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T 1D 0A 77 04 CD 84 04 0E 00 C2 6E 0A CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T 28 0A 3E 04 32 D7 0D 01 00 00 B7 CA 3B 0A 4F 0B +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0C 06 00 +T 36 0A CD 5E 04 44 4D CD BE 07 7D B4 C2 48 0A 3E +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0D 06 00 +T 44 0A 02 C3 01 03 22 E5 0D EB 2A 43 03 01 10 00 +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0B 06 00 +T 52 0A 09 3A DD 0D B7 3A D7 0D CA 64 0A CD +R 00 00 06 00 00 04 06 00 00 08 06 00 00 0B 06 00 +T 5E 0A 64 05 73 C3 6C 0A 4F 06 00 09 09 73 23 72 +R 00 00 06 00 00 02 06 00 00 06 06 00 +T 6C 0A 0E 02 3A 45 03 B7 C0 C5 CD 8A 04 3A D5 0D +R 00 00 06 00 00 05 06 00 00 0B 06 00 00 0E 06 00 +T 7A 0A 3D 3D C2 BB 0A C1 C5 79 3D 3D C2 BB 0A E5 +R 00 00 06 00 00 05 06 00 00 0D 06 00 +T 88 0A 2A B9 0D 57 77 23 14 F2 8C 0A CD E0 05 2A +R 00 00 06 00 00 03 06 00 00 0A 06 00 00 0D 06 00 +T 96 0A E7 0D 0E 02 22 E5 0D C5 CD D1 03 C1 CD +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0B 06 00 +T A3 0A B8 03 2A E5 0D 0E 00 3A C4 0D 47 A5 B8 23 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T B1 0A C2 9A 0A E1 22 E5 0D CD DA 05 CD +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0A 06 00 +T BC 0A D1 03 C1 C5 CD B8 03 C1 3A E3 0D 21 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0B 06 00 +T C8 0A E1 0D BE DA D2 0A 77 34 0E 02 00 00 21 +R 00 00 06 00 00 02 06 00 00 06 06 00 +T D5 0A 00 00 F5 CD 69 05 E6 7F 77 F1 FE 7F C2 +R 00 00 06 00 00 06 06 00 +T E2 0A 00 0B 3A D5 0D FE 01 C2 00 0B CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T ED 0A D2 04 CD 5A 09 21 45 03 7E B7 C2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T F8 0A FE 0A 3D 32 E3 0D 36 00 C3 D2 04 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0B 06 00 +T 03 0B +R 00 00 06 00 +T 03 0B AF 32 D5 0D C5 2A 43 03 EB 21 21 00 19 7E +R 00 00 06 00 00 04 06 00 00 08 06 00 +T 11 0B E6 7F F5 7E 17 23 7E 17 E6 1F 4F 7E 1F 1F +R 00 00 06 00 +T 1F 0B 1F 1F E6 0F 47 F1 23 6E 2C 2D 2E 06 C2 +R 00 00 06 00 +T 2C 0B 8B 0B 21 20 00 19 77 21 0C 00 19 79 96 C2 +R 00 00 06 00 00 02 06 00 +T 3A 0B 47 0B 21 0E 00 19 78 96 E6 7F CA 7F 0B C5 +R 00 00 06 00 00 02 06 00 00 0D 06 00 +T 48 0B D5 CD A2 08 D1 C1 2E 03 3A 45 03 3C CA +R 00 00 06 00 00 04 06 00 00 0B 06 00 +T 55 0B 84 0B 21 0C 00 19 71 21 0E 00 19 70 CD +R 00 00 06 00 00 02 06 00 +T 62 0B 51 08 3A 45 03 3C C2 7F 0B C1 C5 2E 04 0C +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T 70 0B CA 84 0B CD 24 09 2E 05 3A 45 03 3C CA +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0B 06 00 +T 7D 0B 84 0B C1 AF C3 01 03 E5 CD 69 05 36 C0 E1 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0B 06 00 +T 8B 0B C1 7D 32 45 03 C3 78 05 0E FF CD 03 0B CC +R 00 00 06 00 00 05 06 00 00 08 06 00 00 0D 06 00 +T 99 0B C1 09 C9 +R 00 00 06 00 00 02 06 00 +T 9C 0B +R 00 00 06 00 +T 9C 0B 0E 00 CD 03 0B CC 03 0A C9 +R 00 00 06 00 00 05 06 00 00 08 06 00 +T A5 0B +R 00 00 06 00 +T A5 0B EB 19 4E 06 00 21 0C 00 19 7E 0F E6 80 81 +R 00 00 06 00 +T B3 0B 4F 3E 00 88 47 7E 0F E6 0F 80 47 21 0E 00 +R 00 00 06 00 +T C1 0B 19 7E 87 87 87 87 F5 80 47 F5 E1 7D E1 B5 +R 00 00 06 00 +T CF 0B E6 01 C9 0E 0C CD 18 07 2A 43 03 11 21 00 +R 00 00 06 00 00 08 06 00 00 0B 06 00 +T DD 0B 19 E5 72 23 72 23 72 CD F5 05 CA 0C 0C CD +R 00 00 06 00 00 0A 06 00 00 0D 06 00 +T EB 0B 5E 05 11 0F 00 CD A5 0B E1 E5 5F 79 96 23 +R 00 00 06 00 00 02 06 00 00 08 06 00 +T F9 0B 78 9E 23 7B 9E DA 06 0C 73 2B 70 2B 71 CD +R 00 00 06 00 00 08 06 00 +T 07 0C 2D 07 C3 E4 0B E1 C9 2A 43 03 11 20 00 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T 15 0C A5 0B 21 21 00 19 71 23 70 23 77 C9 +R 00 00 06 00 00 02 06 00 +T 21 0C +R 00 00 06 00 +T 21 0C 2A AF 0D 3A 42 03 4F CD EA 04 E5 EB CD +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0A 06 00 +T 2E 0C 59 03 E1 CC 47 03 7D 1F D8 2A AF 0D 4D 44 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0C 06 00 +T 3C 0C CD 0B 05 22 AF 0D C3 A3 06 3A +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 46 0C D6 0D 21 42 03 BE C8 77 C3 21 0C 3E FF 32 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0B 06 00 +T 54 0C DE 0D 2A 43 03 7E E6 1F 3D 32 D6 0D FE 1E +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0C 06 00 +T 62 0C D2 75 0C 3A 42 03 32 DF 0D 7E 32 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 6D 0C E0 0D E6 E0 77 CD 45 0C 3A 41 03 2A +R 00 00 06 00 00 02 06 00 00 08 06 00 00 0B 06 00 +T 79 0C 43 03 B6 77 C9 3E 22 C3 01 03 21 00 00 22 +R 00 00 06 00 00 02 06 00 00 0A 06 00 +T 87 0C AD 0D 22 AF 0D AF 32 42 03 21 80 00 22 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T 94 0C B1 0D CD DA 05 C3 21 0C CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 9D 0C 72 05 CD 51 0C C3 51 08 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T A5 0C +R 00 00 06 00 +T A5 0C CD 51 0C C3 A2 08 0E 00 EB 7E FE 3F CA +R 00 00 06 00 00 03 06 00 00 06 06 00 +T B2 0C C2 0C CD A6 04 7E FE 3F C4 72 05 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0B 06 00 +T BE 0C 51 0C 0E 0F CD 18 07 C3 E9 05 2A +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T C9 0C D9 0D 22 43 03 CD 51 0C CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T D2 0C 2D 07 C3 E9 05 CD 51 0C CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T DB 0C 9C 07 C3 01 07 CD 51 0C C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T E4 0C BC 09 CD 51 0C C3 FE 09 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T ED 0C 72 05 CD 51 0C C3 24 09 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T F6 0C 51 0C CD 16 08 C3 01 07 2A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T FF 0C AF 0D C3 29 0D 3A 42 03 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 08 0D 01 03 EB 22 B1 0D C3 DA 05 2A +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T 12 0D BF 0D C3 29 0D 2A AD 0D C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 1B 0D 29 0D CD 51 0C CD 3B 08 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 24 0D 01 07 2A BB 0D 22 45 03 C9 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 2E 0D D6 0D FE FF C2 3B 0D 3A 41 03 C3 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T 39 0D 01 03 E6 1F 32 41 03 C9 +R 00 00 06 00 00 02 06 00 00 07 06 00 +T 41 0D +R 00 00 06 00 +T 41 0D CD 51 0C C3 93 0B +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 47 0D +R 00 00 06 00 +T 47 0D CD 51 0C C3 9C 0B +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 4D 0D +R 00 00 06 00 +T 4D 0D CD 51 0C C3 D2 0B 2A 43 03 7D 2F 5F 7C 2F +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 5B 0D 2A AF 0D A4 57 7D A3 5F 2A AD 0D EB 22 +R 00 00 06 00 00 03 06 00 00 0B 06 00 +T 68 0D AF 0D 7D A3 6F 7C A2 67 22 AD 0D C9 3A +R 00 00 06 00 00 02 06 00 00 0B 06 00 +T 75 0D DE 0D B7 CA 91 0D 2A 43 03 36 00 3A +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T 81 0D E0 0D B7 CA 91 0D 77 3A DF 0D 32 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0A 06 00 +T 8C 0D D6 0D CD 45 0C 2A 0F 03 F9 2A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 96 0D 45 03 7D 44 C9 CD 51 0C 3E 02 32 D5 0D 0E +R 00 00 06 00 00 02 06 00 00 08 06 00 00 0D 06 00 +T A4 0D 00 CD 07 0B CC 03 0A C9 +R 00 00 06 00 00 04 06 00 00 07 06 00 +T AC 0D +R 00 00 06 00 +T AC 0D E5 00 00 00 00 80 00 +R 00 00 06 00 +T B3 0D +R 00 00 06 00 +T B3 0D 00 00 +R 00 00 06 00 +T B5 0D +R 00 00 06 00 +T B5 0D 00 00 +R 00 00 06 00 +T B7 0D +R 00 00 06 00 +T B7 0D 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T BF 0D +R 00 00 06 00 +T BF 0D 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T CC 0D 00 00 00 00 00 00 +R 00 00 06 00 +T D2 0D +R 00 00 06 00 +T D2 0D 00 +R 00 00 06 00 +T D3 0D +R 00 00 06 00 +T D3 0D 00 00 00 00 +R 00 00 06 00 +T D7 0D +R 00 00 06 00 +T D7 0D 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T E0 0D +R 00 00 06 00 +T E0 0D 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T EC 0D +R 00 00 06 00 +T EC 0D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T FA 0D 00 00 +R 00 00 06 00 +T FC 0D +R 00 00 06 00 diff --git a/doug/src/bdosb01.s b/doug/src/bdosb01.s new file mode 100755 index 00000000..70328e01 --- /dev/null +++ b/doug/src/bdosb01.s @@ -0,0 +1,2654 @@ + .title bdosb01.s derived from bdosb01.asm + .sbttl by Douglas Goodall for N8VEM use '11 + + .module bdosb01 + .optsdcc -mz80 + +;-------------------------------------------------------- +; Public variables in this module +;-------------------------------------------------------- + .globl _bdos +;-------------------------------------------------------- +; special function registers +;-------------------------------------------------------- +;-------------------------------------------------------- +; ram data +;-------------------------------------------------------- + .area _DATA +;-------------------------------------------------------- +; overlayable items in ram +;-------------------------------------------------------- + .area _OVERLAY +;-------------------------------------------------------- +; external initialized ram data +;-------------------------------------------------------- +;-------------------------------------------------------- +; global & static initialisations +;-------------------------------------------------------- + .area _HOME + .area _GSINIT + .area _GSFINAL + .area _GSINIT +;-------------------------------------------------------- +; Home +;-------------------------------------------------------- + .area _HOME + .area _HOME +;-------------------------------------------------------- +; code +;-------------------------------------------------------- + .area _CODE +;bdos.c:1: void bdos(void) +; --------------------------------- +; Function bdos +; --------------------------------- +_bdos_start:: +_bdos: + +;dwg-start; + .area _DATA +;dwg-end; + +ENDFIL = 1 ;FILL FULL BDOS LENGTH +; +IOBYTE = 3 ; I/O DEFINITION BYTE. +TDRIVE = 4 ; CURRENT DRIVE NAME AND USER NUMBER. +ENTRY = 5 ; ENTRY POINT FOR THE CP/M BDOS. +TFCB = 0x5C ; DEFAULT FILE CONTROL BLOCK. +TBUFF = 0x80 ; I/O BUFFER AND COMMAND LINE STORAGE. +TBASE = 0x100 ; TRANSIANT PROGRAM STORAGE AREA. +; +; SET CONTROL CHARACTER .EQUATES. +; +ASCIIA = 0x41 +AT = 0x40 +CNTRLC = 3 ; CONTROL-C +CNTRLE = 05 ; CONTROL-E +BS = 08 ; BACKSPACE +TAB = 09 ; TAB +LF = 0x0A ; LINE FEED +FF = 0x0C ; FORM FEED +CR = 0x0D ; CARRIAGE RETURN +CNTRLP = 0x10 ; CONTROL-P +CNTRLR = 0x12 ; CONTROL-R +CNTRLS = 0x13 ; CONTROL-S +CNTRLU = 0x15 ; CONTROL-U +CNTRLX = 0x18 ; CONTROL-X +CNTRLZ = 0x1A ; CONTROL-Z (END-OF-FILE MARK) +SPACE = 0x20 +POUND = 0x23 +DOLLAR = 0x24 +QUESTION = 0x3f +UP = 0x5E +DEL = 0x7F ; RUBOUT + +; CPM ORIGIN CALCULATE + +NK = 59 ;SYSTEM SIZE +BASE = (NK*1024)-0x5000 +CCPO = BASE+0x3400 ;CCP ORIGIN +BDOSO = BASE+0x3C00 ;BDOS ORIGIN +BIOSO = BASE+0x4A00 ;BIOS ORIGIN + +;dwg-begin; + +; .area _CODE + .area _BDOSB01 + +;dwg-end; + +;dwg; .ORG BDOSO + .DB 0,0,0,0,0,0 ;OLD SERIAL NUMBER +; +;************************************************************** +;* +;* B D O S E N T R Y +;* +;************************************************************** +; +FBASE: JP FBASE1 +; +; BDOS ERROR TABLE. +; +BADSCTR:.DW ERROR1 ; BAD SECTOR ON READ OR WRITE. +BADSLCT:.DW ERROR2 ; BAD DISK SELECT. +RODISK: .DW ERROR3 ; DISK IS READ ONLY. +ROFILE: .DW ERROR4 ; FILE IS READ ONLY. +; +; ENTRY INTO BDOS. (DE) OR (E) ARE THE PARAMETERS PASSED. THE +; FUNCTION NUMBER DESIRED IS IN REGISTER (C). +; E contains drive number if passing this +FBASE1: EX DE,HL ; SAVE THE (DE) PARAMETERS. + LD (PARAMS),HL + EX DE,HL + LD A,E ; AND SAVE REGISTER (E) IN PARTICULAR. + LD (EPARAM),A + LD HL,#0 + LD (STATUS),HL ; CLEAR RETURN STATUS. + ADD HL,SP + LD (USRSTACK),HL ; SAVE USERS STACK POINTER. + LD SP,#STKAREA ; AND SET OUR OWN. + XOR A ; CLEAR AUTO SELECT STORAGE SPACE. + LD (AUTOFLAG),A + LD (AUTO),A + LD HL,#GOBACK ; SET RETURN ADDRESS. + PUSH HL + LD A,C ; GET FUNCTION NUMBER. + CP #NFUNCTS ; VALID FUNCTION NUMBER? + RET NC + LD C,E ; KEEP SINGLE REGISTER FUNCTION HERE. + LD HL,#FUNCTNS ; NOW LOOK THRU THE FUNCTION TABLE. + LD E,A + LD D,#0 ; (DE)=FUNCTION NUMBER. + ADD HL,DE + ADD HL,DE ; (HL)=(START OF TABLE)+2*(FUNCTION NUMBER). + LD E,(HL) + INC HL + LD D,(HL) ; NOW (DE)=ADDRESS FOR THIS FUNCTION. + LD HL,(PARAMS) ; RETRIEVE PARAMETERS. + EX DE,HL ; NOW (DE) HAS THE ORIGINAL PARAMETERS. + JP (HL) ; EXECUTE DESIRED FUNCTION. +; +; BDOS FUNCTION JUMP TABLE. +; +NFUNCTS = 41 ; NUMBER OF FUNCTIONS IN FOLLOWIN TABLE. +; +FUNCTNS:.DW WBOOT,GETCON,OUTCON,GETRDR,PUNCH,LIST,DIRCIO,GETIOB + .DW SETIOB,PRTSTR,R.DBUFF,GETCSTS,GETVER,RSTDSK,SETDSK,OPENFIL + .DW CLOSEFIL,GETFST,GETNXT,DELFILE,READSEQ,WRTSEQ,FCREATE + .DW RENFILE,GETLOG,GETCRNT,PUTDMA,GETALOC,WRTPRTD,GETROV,SETATTR + .DW GETPARM,GETUSER,RDRANDOM,WTRANDOM,FILESIZE,SETRAN,LOGOFF,RTN + .DW RTN,WTSPECL +; +; BDOS ERROR MESSAGE SECTION. +; +ERROR1: LD HL,#BADSEC ; BAD SECTOR MESSAGE. + CALL PRTERR ; PRINT IT AND GET A 1 CHAR RESPONCE. + CP #CNTRLC ; RE-BOOT R.EQUEST (CONTROL-C)? + JP Z,0 ; YES. + RET ; NO, RETURN TO RETRY I/O FUNCTION. +; +ERROR2: LD HL,#BADSEL ; BAD DRIVE SELECTED. + JP ERROR5 +; +ERROR3: LD HL,#DISKRO ; DISK IS READ ONLY. + JP ERROR5 +; +ERROR4: LD HL,#FILERO ; FILE IS READ ONLY. +; +ERROR5: CALL PRTERR + JP 0 ; ALWAYS REBOOT ON THESE ERRORS. +; +BDOSERR: .ascii "BDOS ERR ON " +BDOSDRV: .ascii " : $" +BADSEC: .ascii "BAD SECTOR$" +BADSEL: .ascii "SELECT$" +FILERO: .ascii "FILE " +DISKRO: .ascii "R/O$" +; +; PRINT BDOS ERROR MESSAGE. +; +PRTERR: PUSH HL ; SAVE SECOND MESSAGE POINTER. + CALL OUTCRLF ; SEND (CR)(LF). + LD A,(ACTIVE) ; GET ACTIVE DRIVE. + ADD A,#ASCIIA ; MAKE ASCII. + LD (BDOSDRV),A ; AND PUT IN MESSAGE. + LD BC,#BDOSERR ; AND PRINT IT. + CALL PRTMESG + POP BC ; PRINT SECOND MESSAGE LINE NOW. + CALL PRTMESG +; +; GET AN INPUT CHARACTER. WE WILL CHECK OUR 1 CHARACTER +; BUFFER FIRST. THIS MAY BE SET BY THE CONSOLE STATUS ROUTINE. +; +GETCHAR:LD HL,#CHARBUF ; CHECK CHARACTER BUFFER. + LD A,(HL) ; ANYTHING PRESENT ALREADY? + LD (HL),#0 ; ...EITHER CASE CLEAR IT. + OR A + RET NZ ; YES, USE IT. + JP CONIN ; NOPE, GO GET A CHARACTER RESPONCE. +; +; INPUT AND ECHO A CHARACTER. +; +GETECHO:CALL GETCHAR ; INPUT A CHARACTER. + CALL CHKCHAR ; CARRIAGE CONTROL? + RET C ; NO, A REGULAR CONTROL CHAR SO DON'T ECHO. + PUSH AF ; OK, SAVE CHARACTER NOW. + LD C,A + CALL OUTCON ; AND ECHO IT. + POP AF ; GET CHARACTER AND RETURN. + RET +; +; CHECK CHARACTER IN (A). SET THE ZERO FLAG ON A CARRIAGE +; CONTROL CHARACTER AND THE CARRY FLAG ON ANY OTHER CONTROL +; CHARACTER. +; +CHKCHAR:CP #CR ; CHECK FOR CARRIAGE RETURN, LINE FEED, BACKSPACE, + RET Z ; OR A TAB. + CP #LF + RET Z + CP #TAB + RET Z + CP #BS + RET Z + CP #SPACE ; OTHER CONTROL CHAR? SET CARRY FLAG. + RET +; +; CHECK THE CONSOLE DURING OUTPUT. HALT ON A CONTROL-S, THEN +; REBOOT ON A CONTROL-C. IF ANYTHING ELSE IS READY, CLEAR THE +; ZERO FLAG AND RETURN (THE CALLING ROUTINE MAY WANT TO DO +; SOMETHING). +; +CKCONSOL: + LD A,(CHARBUF) ; CHECK BUFFER. + OR A ; IF ANYTHING, JUST RETURN WITHOUT CHECKING. + JP NZ,CKCON2 + CALL CONST ; NOTHING IN BUFFER. CHECK CONSOLE. + AND #0x01 ; LOOK AT BIT 0. + RET Z ; RETURN IF NOTHING. + CALL CONIN ; OK, GET IT. + CP #CNTRLS ; IF NOT CONTROL-S, RETURN WITH ZERO CLEARED. + JP NZ,CKCON1 + CALL CONIN ; HALT PROCESSING UNTIL ANOTHER CHAR + CP #CNTRLC ; IS TYPED. CONTROL-C? + JP Z,0 ; YES, REBOOT NOW. + XOR A ; NO, JUST PRETEND NOTHING WAS EVER READY. + RET +CKCON1: LD (CHARBUF),A ; SAVE CHARACTER IN BUFFER FOR LATER PROCESSING. +CKCON2: LD A,#1 ; SET (A) TO NON ZERO TO MEAN SOMETHING IS READY. + RET +; +; OUTPUT (C) TO THE SCREEN. IF THE PRINTER FLIP-FLOP FLAG +; IS SET, WE WILL SEND CHARACTER TO PRINTER ALSO. THE CONSOLE +; WILL BE CHECKED IN THE PROCESS. +; +OUTCHAR:LD A,(OUTFLAG) ; CHECK OUTPUT FLAG. + OR A ; ANYTHING AND WE WON'T GENERATE OUTPUT. + JP NZ,OUTCHR1 + PUSH BC + CALL CKCONSOL ; CHECK CONSOLE (WE DON'T CARE WHATS THERE). + POP BC + PUSH BC + CALL CONOUT ; OUTPUT (C) TO THE SCREEN. + POP BC + PUSH BC + LD A,(PRTFLAG) ; CHECK PRINTER FLIP-FLOP FLAG. + OR A + CALL NZ,LIST ; PRINT IT ALSO IF NON-ZERO. + POP BC +OUTCHR1:LD A,C ; UPDATE CURSORS POSITION. + LD HL,#CURPOS + CP #DEL ; RUBOUTS DON'T DO ANYTHING HERE. + RET Z + INC (HL) ; BUMP LINE POINTER. + CP #SPACE ; AND RETURN IF A NORMAL CHARACTER. + RET NC + DEC (HL) ; RESTORE AND CHECK FOR THE START OF THE LINE. + LD A,(HL) + OR A + RET Z ; INGNORE CONTROL CHARACTERS AT THE START OF THE LINE. + LD A,C + CP #BS ; IS IT A BACKSPACE? + JP NZ,OUTCHR2 + DEC (HL) ; YES, BACKUP POINTER. + RET +OUTCHR2:CP #LF ; IS IT A LINE FEED? + RET NZ ; IGNORE ANYTHING ELSE. + LD (HL),#0 ; RESET POINTER TO START OF LINE. + RET +; +; OUTPUT (A) TO THE SCREEN. IF IT IS A CONTROL CHARACTER +; (OTHER THAN CARRIAGE CONTROL), USE ^X FORMAT. +; +SHOWIT: LD A,C + CALL CHKCHAR ; CHECK CHARACTER. + JP NC,OUTCON ; NOT A CONTROL, USE NORMAL OUTPUT. + PUSH AF + LD C,#UP ; FOR A CONTROL CHARACTER, PRECEED IT WITH '^'. + CALL OUTCHAR + POP AF + OR #AT ; AND THEN USE THE LETTER .EQUIVELANT. + LD C,A +; +; FUNCTION TO OUTPUT (C) TO THE CONSOLE DEVICE AND EXPAND TABS +; IF NECESSARY. +; +OUTCON: LD A,C + CP #TAB ; IS IT A TAB? + JP NZ,OUTCHAR ; USE REGULAR OUTPUT. +OUTCON1:LD C,#SPACE ; YES IT IS, USE SPACES INSTEAD. + CALL OUTCHAR + LD A,(CURPOS) ; GO UNTIL THE CURSOR IS AT A MULTIPLE OF 8 + + AND #7 ; POSITION. + JP NZ,OUTCON1 + RET +; +; ECHO A BACKSPACE CHARACTER. ERASE THE PREVOIUS CHARACTER +; ON THE SCREEN. +; +BACKUP: CALL BACKUP1 ; BACKUP THE SCREEN 1 PLACE. + LD C,#SPACE ; THEN BLANK THAT CHARACTER. + CALL CONOUT +BACKUP1:LD C,#BS ; THEN BACK SPACE ONCE MORE. + JP CONOUT +; +; SIGNAL A DELETED LINE. PRINT A '#' AT THE END AND START +; OVER. +; +NEWLINE:LD C,#POUND + CALL OUTCHAR ; PRINT THIS. + CALL OUTCRLF ; START NEW LINE. +NEWLN1: LD A,(CURPOS) ; MOVE THE CURSOR TO THE STARTING POSITION. + LD HL,#STARTING + CP (HL) + RET NC ; THERE YET? + LD C,#SPACE + CALL OUTCHAR ; NOPE, KEEP GOING. + JP NEWLN1 +; +; OUTPUT A (CR) (LF) TO THE CONSOLE DEVICE (SCREEN). +; +OUTCRLF:LD C,#CR + CALL OUTCHAR + LD C,#LF + JP OUTCHAR +; +; PRINT MESSAGE POINTED TO BY (BC). IT WILL END WITH A '$'. +; +PRTMESG:LD A,(BC) ; CHECK FOR TERMINATING CHARACTER. + CP #DOLLAR + RET Z + INC BC + PUSH BC ; OTHERWISE, BUMP POINTER AND PRINT IT. + LD C,A + CALL OUTCON + POP BC + JP PRTMESG +; +; FUNCTION TO EXECUTE A BUFFERED READ. +; +R.DBUFF: LD A,(CURPOS) ; USE PRESENT LOCATION AS STARTING ONE. + LD (STARTING),A + LD HL,(PARAMS) ; GET THE MAXIMUM BUFFER SPACE. + LD C,(HL) + INC HL ; POINT TO FIRST AVAILABLE SPACE. + PUSH HL ; AND SAVE. + LD B,#0 ; KEEP A CHARACTER COUNT. +R.DBUF1: PUSH BC + PUSH HL +R.DBUF2: CALL GETCHAR ; GET THE NEXT INPUT CHARACTER. + AND #0x7F ; STRIP BIT 7. + POP HL ; RESET REGISTERS. + POP BC + CP #CR ; EN OF THE LINE? + JP Z,R.DBUF17 + CP #LF + JP Z,R.DBUF17 + CP #BS ; HOW ABOUT A BACKSPACE? + JP NZ,R.DBUF3 + LD A,B ; YES, BUT IGNORE AT THE BEGINNING OF THE LINE. + OR A + JP Z,R.DBUF1 + DEC B ; OK, UPDATE COUNTER. + LD A,(CURPOS) ; IF WE BACKSPACE TO THE START OF THE LINE, + LD (OUTFLAG),A ; TREAT AS A CANCEL (CONTROL-X). + JP R.DBUF10 +R.DBUF3: CP #DEL ; USER TYPED A RUBOUT? + JP NZ,R.DBUF4 + LD A,B ; IGNORE AT THE START OF THE LINE. + OR A + JP Z,R.DBUF1 + LD A,(HL) ; OK, ECHO THE PREVOIUS CHARACTER. + DEC B ; AND RESET POINTERS (COUNTERS). + DEC HL + JP R.DBUF15 +R.DBUF4: CP #CNTRLE ; PHYSICAL END OF LINE? + JP NZ,R.DBUF5 + PUSH BC ; YES, DO IT. + PUSH HL + CALL OUTCRLF + XOR A ; AND UPDATE STARTING POSITION. + LD (STARTING),A + JP R.DBUF2 +R.DBUF5: CP #CNTRLP ; CONTROL-P? + JP NZ,R.DBUF6 + PUSH HL ; YES, FLIP THE PRINT FLAG FILP-FLOP BYTE. + LD HL,#PRTFLAG + LD A,#1 ; PRTFLAG=1-PRTFLAG + SUB (HL) + LD (HL),A + POP HL + JP R.DBUF1 +R.DBUF6: CP #CNTRLX ; CONTROL-X (CANCEL)? + JP NZ,R.DBUF8 + POP HL +R.DBUF7: LD A,(STARTING) ; YES, BACKUP THE CURSOR TO HERE. + LD HL,#CURPOS + CP (HL) + JP NC,R.DBUFF ; DONE YET? + DEC (HL) ; NO, DECREMENT POINTER AND OUTPUT BACK UP ONE SPACE. + CALL BACKUP + JP R.DBUF7 +R.DBUF8: CP #CNTRLU ; CNTROL-U (CANCEL LINE)? + JP NZ,R.DBUF9 + CALL NEWLINE ; START A NEW LINE. + POP HL + JP R.DBUFF +R.DBUF9: CP #CNTRLR ; CONTROL-R? + JP NZ,R.DBUF14 +R.DBUF10:PUSH BC ; YES, START A NEW LINE AND RETYPE THE OLD ONE. + CALL NEWLINE + POP BC + POP HL + PUSH HL + PUSH BC +R.DBUF11:LD A,B ; DONE WHOLE LINE YET? + OR A + JP Z,R.DBUF12 + INC HL ; NOPE, GET NEXT CHARACTER. + LD C,(HL) + DEC B ; COUNT IT. + PUSH BC + PUSH HL + CALL SHOWIT ; AND DISPLAY IT. + POP HL + POP BC + JP R.DBUF11 +R.DBUF12:PUSH HL ; DONE WITH LINE. IF WE WERE DISPLAYING + LD A,(OUTFLAG) ; THEN UPDATE CURSOR POSITION. + OR A + JP Z,R.DBUF2 + LD HL,#CURPOS ; BECAUSE THIS LINE IS SHORTER, WE MUST + SUB (HL) ; BACK UP THE CURSOR (NOT THE SCREEN HOWEVER) + LD (OUTFLAG),A ; SOME NUMBER OF POSITIONS. +R.DBUF13:CALL BACKUP ; NOTE THAT AS LONG AS (OUTFLAG) IS NON + LD HL,#OUTFLAG ; ZERO, THE SCREEN WILL NOT BE CHANGED. + DEC (HL) + JP NZ,R.DBUF13 + JP R.DBUF2 ; NOW JUST GET THE NEXT CHARACTER. +; +; JUST A NORMAL CHARACTER, PUT THIS IN OUR BUFFER AND ECHO. +; +R.DBUF14:INC HL + LD (HL),A ; STORE CHARACTER. + INC B ; AND COUNT IT. +R.DBUF15:PUSH BC + PUSH HL + LD C,A ; ECHO IT NOW. + CALL SHOWIT + POP HL + POP BC + LD A,(HL) ; WAS IT AN ABORT R.EQUEST? + CP #CNTRLC ; CONTROL-C ABORT? + LD A,B + JP NZ,R.DBUF16 + CP #1 ; ONLY IF AT START OF LINE. + JP Z,0 +R.DBUF16:CP C ; NOPE, HAVE WE FILLED THE BUFFER? + JP C,R.DBUF1 +R.DBUF17:POP HL ; YES END THE LINE AND RETURN. + LD (HL),B + LD C,#CR + JP OUTCHAR ; OUTPUT (CR) AND RETURN. +; +; FUNCTION TO GET A CHARACTER FROM THE CONSOLE DEVICE. +; +GETCON: CALL GETECHO ; GET AND ECHO. + JP SETSTAT ; SAVE STATUS AND RETURN. +; +; FUNCTION TO GET A CHARACTER FROM THE TAPE READER DEVICE. +; +GETRDR: CALL READER ; GET A CHARACTER FROM READER, SET STATUS AND RETURN. + JP SETSTAT +; +; FUNCTION TO PERFORM DIRECT CONSOLE I/O. IF (C) CONTAINS (FF) +; THEN THIS IS AN INPUT R.EQUEST. IF (C) CONTAINS (FE) THEN +; THIS IS A STATUS R.EQUEST. OTHERWISE WE ARE TO OUTPUT (C). +; +DIRCIO: LD A,C ; TEST FOR (FF). + INC A + JP Z,DIRC1 + INC A ; TEST FOR (FE). + JP Z,CONST + JP CONOUT ; JUST OUTPUT (C). +DIRC1: CALL CONST ; THIS IS AN INPUT R.EQUEST. + OR A + JP Z,GOBACK1 ; NOT READY? JUST RETURN (DIRECTLY). + CALL CONIN ; YES, GET CHARACTER. + JP SETSTAT ; SET STATUS AND RETURN. +; +; FUNCTION TO RETURN THE I/O BYTE. +; +GETIOB: LD A,(IOBYTE) + JP SETSTAT +; +; FUNCTION TO SET THE I/O BYTE. +; +SETIOB: LD HL,#IOBYTE + LD (HL),C + RET +; +; FUNCTION TO PRINT THE CHARACTER STRING POINTED TO BY (DE) +; ON THE CONSOLE DEVICE. THE STRING ENDS WITH A '$'. +; +PRTSTR: EX DE,HL + LD C,L + LD B,H ; NOW (BC) POINTS TO IT. + JP PRTMESG +; +; FUNCTION TO INTERIGATE THE CONSOLE DEVICE. +; +GETCSTS:CALL CKCONSOL +; +; GET HERE TO SET THE STATUS AND RETURN TO THE CLEANUP +; SECTION. THEN BACK TO THE USER. +; +SETSTAT:LD (STATUS),A +RTN: RET +; +; SET THE STATUS TO 1 (READ OR WRITE ERROR CODE). +; +IOERR1: LD A,#1 + JP SETSTAT +; +OUTFLAG:.DB 0 ; OUTPUT FLAG (NON ZERO MEANS NO OUTPUT). +STARTING: + .DB 2 ; STARTING POSITION FOR CURSOR. +CURPOS: .DB 0 ; CURSOR POSITION (0=START OF LINE). +PRTFLAG:.DB 0 ; PRINTER FLAG (CONTROL-P TOGGLE). LIST IF NON ZERO. +CHARBUF:.DB 0 ; SINGLE INPUT CHARACTER BUFFER. +; +; STACK AREA FOR BDOS CALLS. +; +USRSTACK: + .DW 0 ; SAVE USERS STACK POINTER HERE. +; + .DB 0,0,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,0,0 +STKAREA: ; END OF STACK AREA. +; +USERNO: .DB 0 ; CURRENT USER NUMBER. +ACTIVE: .DB 0 ; CURRENTLY ACTIVE DRIVE. +PARAMS: .DW 0 ; SAVE (DE) PARAMETERS HERE ON ENTRY. +STATUS: .DW 0 ; STATUS RETURNED FROM BDOS FUNCTION. +; +; SELECT ERROR OCCURED, JUMP TO ERROR ROUTINE. +; +SLCTERR:LD HL,#BADSLCT +; +; JUMP TO (HL) INDIRECTLY. +; +JUMPHL: LD E,(HL) + INC HL + LD D,(HL) ; NOW (DE) CONTAIN THE DESIRED ADDRESS. + EX DE,HL + JP (HL) +; +; BLOCK MOVE. (DE) TO (HL), (C) BYTES TOTAL. +; +DE2HL: INC C ; IS COUNT DOWN TO ZERO? +DE2HL1: DEC C + RET Z ; YES, WE ARE DONE. + LD A,(DE) ; NO, MOVE ONE MORE BYTE. + LD (HL),A + INC DE + INC HL + JP DE2HL1 ; AND REPEAT. +; +; SELECT THE DESIRED DRIVE. +; +SELECT: LD A,(ACTIVE) ; GET ACTIVE DISK. + LD C,A + CALL SELDSK ; SELECT IT. + LD A,H ; VALID DRIVE? + OR L ; VALID DRIVE? + RET Z ; RETURN IF NOT. +; +; HERE, THE BIOS RETURNED THE ADDRESS OF THE PARAMETER BLOCK +; IN (HL). WE WILL EXTRACT THE NECESSARY POINTERS AND SAVE THEM. +; + LD E,(HL) ; YES, GET ADDRESS OF TRANSLATION TABLE INTO (DE). + INC HL + LD D,(HL) + INC HL + LD (SCRATCH1),HL ; SAVE POINTERS TO SCRATCH AREAS. + INC HL + INC HL + LD (SCRATCH2),HL ; DITTO. + INC HL + INC HL + LD (SCRATCH3),HL ; DITTO. + INC HL + INC HL + EX DE,HL ; NOW SAVE THE TRANSLATION TABLE ADDRESS. + LD (XLATE),HL + LD HL,#DIRBUF ; PUT THE NEXT 8 BYTES HERE. + LD C,#8 ; THEY CONSIST OF THE DIRECTORY BUFFER + CALL DE2HL ; POINTER, PARAMETER BLOCK POINTER, + LD HL,(DISKPB) ; CHECK AND ALLOCATION VECTORS. + EX DE,HL + LD HL,#SECTORS ; MOVE PARAMETER BLOCK INTO OUR RAM. + LD C,#15 ; IT IS 15 BYTES LONG. + CALL DE2HL + LD HL,(DSKSIZE) ; CHECK DISK SIZE. + LD A,H ; MORE THAN 256 BLOCKS ON THIS? + LD HL,#BIGDISK + LD (HL),#0x0FF ; SET TO SAMLL. + OR A + JP Z,SELECT1 + LD (HL),#0 ; WRONG, SET TO LARGE. +SELECT1:LD A,#0x0FF ; CLEAR THE ZERO FLAG. + OR A + RET +; +; ROUTINE TO HOME THE DISK TRACK HEAD AND CLEAR POINTERS. +; +HOMEDRV:CALL HOME ; HOME THE HEAD. + XOR A + LD HL,(SCRATCH2) ; SET OUR TRACK POINTER ALSO. + LD (HL),A + INC HL + LD (HL),A + LD HL,(SCRATCH3) ; AND OUR SECTOR POINTER. + LD (HL),A + INC HL + LD (HL),A + RET +; +; DO THE ACTUAL DISK READ AND CHECK THE ERROR RETURN STATUS. +; +DOREAD: CALL READ + JP IORET +; +; DO THE ACTUAL DISK WRITE AND HANDLE ANY BIOS ERROR. +; +DOWRITE:CALL WRITE +IORET: OR A + RET Z ; RETURN UNLESS AN ERROR OCCURED. + LD HL,#BADSCTR ; BAD READ/WRITE ON THIS SECTOR. + JP JUMPHL +; +; ROUTINE TO SELECT THE TRACK AND SECTOR THAT THE DESIRED +; BLOCK NUMBER FALLS IN. +; +TRKSEC: LD HL,(FILEPOS) ; GET POSITION OF LAST ACCESSED FILE + LD C,#2 ; IN DIRECTORY AND COMPUTE SECTOR #. + CALL SHIFTR ; SECTOR #=FILE-POSITION/4. + LD (BLKNMBR),HL ; SAVE THIS AS THE BLOCK NUMBER OF INTEREST. + LD (CKSUMTBL),HL ; WHAT'S IT DOING HERE TOO? +; +; IF THE SECTOR NUMBER HAS ALREADY BEEN SET (BLKNMBR), ENTER +; AT THIS POINT. +; +TRKSEC1:LD HL,#BLKNMBR + LD C,(HL) ; MOVE SECTOR NUMBER INTO (BC). + INC HL + LD B,(HL) + LD HL,(SCRATCH3) ; GET CURRENT SECTOR NUMBER AND + LD E,(HL) ; MOVE THIS INTO (DE). + INC HL + LD D,(HL) + LD HL,(SCRATCH2) ; GET CURRENT TRACK NUMBER. + LD A,(HL) ; AND THIS INTO (HL). + INC HL + LD H,(HL) + LD L,A +TRKSEC2:LD A,C ; IS DESIRED SECTOR BEFORE CURRENT ONE? + SUB E + LD A,B + SBC A,D + JP NC,TRKSEC3 + PUSH HL ; YES, DECREMENT SECTORS BY ONE TRACK. + LD HL,(SECTORS) ; GET SECTORS PER TRACK. + LD A,E + SUB L + LD E,A + LD A,D + SBC A,H + LD D,A ; NOW WE HAVE BACKED UP ONE FULL TRACK. + POP HL + DEC HL ; ADJUST TRACK COUNTER. + JP TRKSEC2 +TRKSEC3:PUSH HL ; DESIRED SECTOR IS AFTER CURRENT ONE. + LD HL,(SECTORS) ; GET SECTORS PER TRACK. + ADD HL,DE ; BUMP SECTOR POINTER TO NEXT TRACK. + JP C,TRKSEC4 + LD A,C ; IS DESIRED SECTOR NOW BEFORE CURRENT ONE? + SUB L + LD A,B + SBC A,H + JP C,TRKSEC4 + EX DE,HL ; NOT YES, INCREMENT TRACK COUNTER + POP HL ; AND CONTINUE UNTIL IT IS. + INC HL + JP TRKSEC3 +; +; HERE WE HAVE DETERMINED THE TRACK NUMBER THAT CONTAINS THE +; DESIRED SECTOR. +; +TRKSEC4:POP HL ; GET TRACK NUMBER (HL). + PUSH BC + PUSH DE + PUSH HL + EX DE,HL + LD HL,(OFFSET) ; ADJUST FOR FIRST TRACK OFFSET. + ADD HL,DE + LD B,H + LD C,L + CALL SETTRK ; SELECT THIS TRACK. + POP DE ; RESET CURRENT TRACK POINTER. + LD HL,(SCRATCH2) + LD (HL),E + INC HL + LD (HL),D + POP DE + LD HL,(SCRATCH3) ; RESET THE FIRST SECTOR ON THIS TRACK. + LD (HL),E + INC HL + LD (HL),D + POP BC + LD A,C ; NOW SUBTRACT THE DESIRED ONE. + SUB E ; TO MAKE IT RELATIVE (1-# SECTORS/TRACK). + LD C,A + LD A,B + SBC A,D + LD B,A + LD HL,(XLATE) ; TRANSLATE THIS SECTOR ACCORDING TO THIS TABLE. + EX DE,HL + CALL SECTRN ; LET THE BIOS TRANSLATE IT. + LD C,L + LD B,H + JP SETSEC ; AND SELECT IT. +; +; COMPUTE BLOCK NUMBER FROM RECORD NUMBER (SAVNREC) AND +; EXTENT NUMBER (SAVEXT). +; +GETBLOCK: + LD HL,#BLKSHFT ; GET LOGICAL TO PHYSICAL CONVERSION. + LD C,(HL) ; NOTE THAT THIS IS BASE 2 LOG OF RATIO. + LD A,(SAVNREC) ; GET RECORD NUMBER. +GETBLK1:OR A ; COMPUTE (A)=(A)/2^BLKSHFT. + RRA + DEC C + JP NZ,GETBLK1 + LD B,A ; SAVE RESULT IN (B). + LD A,#8 + SUB (HL) + LD C,A ; COMPUTE (C)=8-BLKSHFT. + LD A,(SAVEXT) +GETBLK2:DEC C ; COMPUTE (A)=SAVEXT*2^(8-BLKSHFT). + JP Z,GETBLK3 + OR A + RLA + JP GETBLK2 +GETBLK3:ADD A,B + RET +; +; ROUTINE TO EXTRACT THE (BC) BLOCK BYTE FROM THE FCB POINTED +; TO BY (PARAMS). IF THIS IS A BIG-DISK, THEN THESE ARE 16 BIT +; BLOCK NUMBERS, ELSE THEY ARE 8 BIT NUMBERS. +; NUMBER IS RETURNED IN (HL). +; +EXTBLK: LD HL,(PARAMS) ; GET FCB ADDRESS. + LD DE,#16 ; BLOCK NUMBERS START 16 BYTES INTO FCB. + ADD HL,DE + ADD HL,BC + LD A,(BIGDISK) ; ARE WE USING A BIG-DISK? + OR A + JP Z,EXTBLK1 + LD L,(HL) ; NO, EXTRACT AN 8 BIT NUMBER FROM THE FCB. + LD H,#0 + RET +EXTBLK1:ADD HL,BC ; YES, EXTRACT A 16 BIT NUMBER. + LD E,(HL) + INC HL + LD D,(HL) + EX DE,HL ; RETURN IN (HL). + RET +; +; COMPUTE BLOCK NUMBER. +; +COMBLK: CALL GETBLOCK + LD C,A + LD B,#0 + CALL EXTBLK + LD (BLKNMBR),HL + RET +; +; CHECK FOR A ZERO BLOCK NUMBER (UNUSED). +; +CHKBLK: LD HL,(BLKNMBR) + LD A,L ; IS IT ZERO? + OR H + RET +; +; ADJUST PHYSICAL BLOCK (BLKNMBR) AND CONVERT TO LOGICAL +; SECTOR (LOGSECT). THIS IS THE STARTING SECTOR OF THIS BLOCK. +; THE ACTUAL SECTOR OF INTEREST IS THEN ADDED TO THIS AND THE +; RESULTING SECTOR NUMBER IS STORED BACK IN (BLKNMBR). THIS +; WILL STILL HAVE TO BE ADJUSTED FOR THE TRACK NUMBER. +; +LOGICAL:LD A,(BLKSHFT) ; GET LOG2(PHYSICAL/LOGICAL SECTORS). + LD HL,(BLKNMBR) ; GET PHYSICAL SECTOR DESIRED. +LOGICL1:ADD HL,HL ; COMPUTE LOGICAL SECTOR NUMBER. + DEC A ; NOTE LOGICAL SECTORS ARE 128 BYTES LONG. + JP NZ,LOGICL1 + LD (LOGSECT),HL ; SAVE LOGICAL SECTOR. + LD A,(BLKMASK) ; GET BLOCK MASK. + LD C,A + LD A,(SAVNREC) ; GET NEXT SECTOR TO ACCESS. + AND C ; EXTRACT THE RELATIVE POSITION WITHIN PHYSICAL BLOCK. + OR L ; AND ADD IT TOO LOGICAL SECTOR. + LD L,A + LD (BLKNMBR),HL ; AND STORE. + RET +; +; SET (HL) TO POINT TO EXTENT BYTE IN FCB. +; +SETEXT: LD HL,(PARAMS) + LD DE,#12 ; IT IS THE TWELTH BYTE. + ADD HL,DE + RET +; +; SET (HL) TO POINT TO RECORD COUNT BYTE IN FCB AND (DE) TO +; NEXT RECORD NUMBER BYTE. +; +SETHLDE:LD HL,(PARAMS) + LD DE,#15 ; RECORD COUNT BYTE (#15). + ADD HL,DE + EX DE,HL + LD HL,#17 ; NEXT RECORD NUMBER (#32). + ADD HL,DE + RET +; +; SAVE CURRENT FILE DATA FROM FCB. +; +STRDATA:CALL SETHLDE + LD A,(HL) ; GET AND STORE RECORD COUNT BYTE. + LD (SAVNREC),A + EX DE,HL + LD A,(HL) ; GET AND STORE NEXT RECORD NUMBER BYTE. + LD (SAVNXT),A + CALL SETEXT ; POINT TO EXTENT BYTE. + LD A,(EXTMASK) ; GET EXTENT MASK. + AND (HL) + LD (SAVEXT),A ; AND SAVE EXTENT HERE. + RET +; +; SET THE NEXT RECORD TO ACCESS. IF (MODE) IS SET TO 2, THEN +; THE LAST RECORD BYTE (SAVNREC) HAS THE CORRECT NUMBER TO ACCESS. +; FOR S.EQUENTIAL ACCESS, (MODE) WILL BE .EQUAL TO 1. +; +SETNREC:CALL SETHLDE + LD A,(MODE) ; GET S.EQUENTIAL FLAG (=1). + CP #2 ; A 2 INDICATES THAT NO ADDER IS NEEDED. + JP NZ,STNREC1 + XOR A ; CLEAR ADDER (RANDOM ACCESS?). +STNREC1:LD C,A + LD A,(SAVNREC) ; GET LAST RECORD NUMBER. + ADD A,C ; INCREMENT RECORD COUNT. + LD (HL),A ; AND SET FCB'S NEXT RECORD BYTE. + EX DE,HL + LD A,(SAVNXT) ; GET NEXT RECORD BYTE FROM STORAGE. + LD (HL),A ; AND PUT THIS INTO FCB AS NUMBER OF RECORDS USED. + RET +; +; SHIFT (HL) RIGHT (C) BITS. +; +SHIFTR: INC C +SHIFTR1:DEC C + RET Z + LD A,H + OR A + RRA + LD H,A + LD A,L + RRA + LD L,A + JP SHIFTR1 +; +; COMPUTE THE CHECK-SUM FOR THE DIRECTORY BUFFER. RETURN +; INTEGER SUM IN (A). +; +CHECKSUM: + LD C,#128 ; LENGTH OF BUFFER. + LD HL,(DIRBUF) ; GET ITS LOCATION. + XOR A ; CLEAR SUMMATION BYTE. +CHKSUM1:ADD A,(HL) ; AND COMPUTE SUM IGNORING CARRIES. + INC HL + DEC C + JP NZ,CHKSUM1 + RET +; +; SHIFT (HL) LEFT (C) BITS. +; +SHIFTL: INC C +SHIFTL1:DEC C + RET Z + ADD HL,HL ; SHIFT LEFT 1 BIT. + JP SHIFTL1 +; +; ROUTINE TO SET A BIT IN A 16 BIT VALUE CONTAINED IN (BC). +; THE BIT SET DEPENDS ON THE CURRENT DRIVE SELECTION. +; +SETBIT: PUSH BC ; SAVE 16 BIT WORD. + LD A,(ACTIVE) ; GET ACTIVE DRIVE. + LD C,A + LD HL,#1 + CALL SHIFTL ; SHIFT BIT 0 INTO PLACE. + POP BC ; NOW 'OR' THIS WITH THE ORIGINAL WORD. + LD A,C + OR L + LD L,A ; LOW BYTE DONE, DO HIGH BYTE. + LD A,B + OR H + LD H,A + RET +; +; EXTRACT THE WRITE PROTECT STATUS BIT FOR THE CURRENT DRIVE. +; THE RESULT IS RETURNED IN (A), BIT 0. +; +GETWPRT:LD HL,(WRTPRT) ; GET STATUS BYTES. + LD A,(ACTIVE) ; WHICH DRIVE IS CURRENT? + LD C,A + CALL SHIFTR ; SHIFT STATUS SUCH THAT BIT 0 IS THE + LD A,L ; ONE OF INTEREST FOR THIS DRIVE. + AND #1 ; AND ISOLATE IT. + RET +; +; FUNCTION TO WRITE PROTECT THE CURRENT DISK. +; +WRTPRTD:LD HL,#WRTPRT ; POINT TO STATUS WORD. + LD C,(HL) ; SET (BC) .EQUAL TO THE STATUS. + INC HL + LD B,(HL) + CALL SETBIT ; AND SET THIS BIT ACCORDING TO CURRENT DRIVE. + LD (WRTPRT),HL ; THEN SAVE. + LD HL,(DIRSIZE) ; NOW SAVE DIRECTORY SIZE LIMIT. + INC HL ; REMEMBER THE LAST ONE. + EX DE,HL + LD HL,(SCRATCH1) ; AND STORE IT HERE. + LD (HL),E ; PUT LOW BYTE. + INC HL + LD (HL),D ; THEN HIGH BYTE. + RET +; +; CHECK FOR A READ ONLY FILE. +; +CHKROFL:CALL FCB2HL ; SET (HL) TO FILE ENTRY IN DIRECTORY BUFFER. +CKROF1: LD DE,#9 ; LOOK AT BIT 7 OF THE NINTH BYTE. + ADD HL,DE + LD A,(HL) + RLA + RET NC ; RETURN IF OK. + LD HL,#ROFILE ; ELSE, PRINT ERROR MESSAGE AND TERMINATE. + JP JUMPHL +; +; CHECK THE WRITE PROTECT STATUS OF THE ACTIVE DISK. +; +CHKWPRT:CALL GETWPRT + RET Z ; RETURN IF OK. + LD HL,#RODISK ; ELSE PRINT MESSAGE AND TERMINATE. + JP JUMPHL +; +; ROUTINE TO SET (HL) POINTING TO THE PROPER ENTRY IN THE +; DIRECTORY BUFFER. +; +FCB2HL: LD HL,(DIRBUF) ; GET ADDRESS OF BUFFER. + LD A,(FCBPOS) ; RELATIVE POSITION OF FILE. +; +; ROUTINE TO ADD (A) TO (HL). +; +ADDA2HL:ADD A,L + LD L,A + RET NC + INC H ; TAKE CARE OF ANY CARRY. + RET +; +; ROUTINE TO GET THE 'S2' BYTE FROM THE FCB SUPPLIED IN +; THE INITIAL PARAMETER SPECIFICATION. +; +GETS2: LD HL,(PARAMS) ; GET ADDRESS OF FCB. + LD DE,#14 ; RELATIVE POSITION OF 'S2'. + ADD HL,DE + LD A,(HL) ; EXTRACT THIS BYTE. + RET +; +; CLEAR THE 'S2' BYTE IN THE FCB. +; +CLEARS2:CALL GETS2 ; THIS SETS (HL) POINTING TO IT. + LD (HL),#0 ; NOW CLEAR IT. + RET +; +; SET BIT 7 IN THE 'S2' BYTE OF THE FCB. +; +SETS2B7:CALL GETS2 ; GET THE BYTE. + OR #0x80 ; AND SET BIT 7. + LD (HL),A ; THEN STORE. + RET +; +; COMPARE (FILEPOS) WITH (SCRATCH1) AND SET FLAGS BASED ON +; THE DIFFERENCE. THIS CHECKS TO SEE IF THERE ARE MORE FILE +; NAMES IN THE DIRECTORY. WE ARE AT (FILEPOS) AND THERE ARE +; (SCRATCH1) OF THEM TO CHECK. +; +MOREFLS:LD HL,(FILEPOS) ; WE ARE HERE. + EX DE,HL + LD HL,(SCRATCH1) ; AND DON'T GO PAST HERE. + LD A,E ; COMPUTE DIFFERENCE BUT DON'T KEEP. + SUB (HL) + INC HL + LD A,D + SBC A,(HL) ; SET CARRY IF NO MORE NAMES. + RET +; +; CALL THIS ROUTINE TO PREVENT (SCRATCH1) FROM BEING GREATER +; THAN (FILEPOS). +; +CHKNMBR:CALL MOREFLS ; SCRATCH1 TOO BIG? + RET C + INC DE ; YES, RESET IT TO (FILEPOS). + LD (HL),D + DEC HL + LD (HL),E + RET +; +; COMPUTE (HL)=(DE)-(HL) +; +SUBHL: LD A,E ; COMPUTE DIFFERENCE. + SUB L + LD L,A ; STORE LOW BYTE. + LD A,D + SBC A,H + LD H,A ; AND THEN HIGH BYTE. + RET +; +; SET THE DIRECTORY CHECKSUM BYTE. +; +SETDIR: LD C,#0xFF +; +; ROUTINE TO SET OR COMPARE THE DIRECTORY CHECKSUM BYTE. IF +; (C)=0FFH, THEN THIS WILL SET THE CHECKSUM BYTE. ELSE THE BYTE +; WILL BE CHECKED. IF THE CHECK FAILS (THE DISK HAS BEEN CHANGED), +; THEN THIS DISK WILL BE WRITE PROTECTED. +; +CHECKDIR: + LD HL,(CKSUMTBL) + EX DE,HL + LD HL,(ALLOC1) + CALL SUBHL + RET NC ; OK IF (CKSUMTBL) > (ALLOC1), SO RETURN. + PUSH BC + CALL CHECKSUM ; ELSE COMPUTE CHECKSUM. + LD HL,(CHKVECT) ; GET ADDRESS OF CHECKSUM TABLE. + EX DE,HL + LD HL,(CKSUMTBL) + ADD HL,DE ; SET (HL) TO POINT TO BYTE FOR THIS DRIVE. + POP BC + INC C ; SET OR CHECK ? + JP Z,CHKDIR1 + CP (HL) ; CHECK THEM. + RET Z ; RETURN IF THEY ARE THE SAME. + CALL MOREFLS ; NOT THE SAME, DO WE CARE? + RET NC + CALL WRTPRTD ; YES, MARK THIS AS WRITE PROTECTED. + RET +CHKDIR1:LD (HL),A ; JUST SET THE BYTE. + RET +; +; DO A WRITE TO THE DIRECTORY OF THE CURRENT DISK. +; +DIRWRITE: + CALL SETDIR ; SET CHECKSUM BYTE. + CALL DIRDMA ; SET DIRECTORY DMA ADDRESS. + LD C,#1 ; TELL THE BIOS TO ACTUALLY WRITE. + CALL DOWRITE ; THEN DO THE WRITE. + JP DEFDMA +; +; READ FROM THE DIRECTORY. +; +DIRREAD:CALL DIRDMA ; SET THE DIRECTORY DMA ADDRESS. + CALL DOREAD ; AND READ IT. +; +; ROUTINE TO SET THE DMA ADDRESS TO THE USERS CHOICE. +; +DEFDMA: LD HL,#USERDMA ; RESET THE DEFAULT DMA ADDRESS AND RETURN. + JP DIRDMA1 +; +; ROUTINE TO SET THE DMA ADDRESS FOR DIRECTORY WORK. +; +DIRDMA: LD HL,#DIRBUF +; +; SET THE DMA ADDRESS. ON ENTRY, (HL) POINTS TO +; WORD CONTAINING THE DESIRED DMA ADDRESS. +; +DIRDMA1:LD C,(HL) + INC HL + LD B,(HL) ; SETUP (BC) AND GO TO THE BIOS TO SET IT. + JP SETDMA +; +; MOVE THE DIRECTORY BUFFER INTO USER'S DMA SPACE. +; +MOVEDIR:LD HL,(DIRBUF) ; BUFFER IS LOCATED HERE, AND + EX DE,HL + LD HL,(USERDMA) ; PUT IT HERE. + LD C,#128 ; THIS IS ITS LENGTH. + JP DE2HL ; MOVE IT NOW AND RETURN. +; +; CHECK (FILEPOS) AND SET THE ZERO FLAG IF IT .EQUALS 0FFFFH. +; +CKFILPOS: + LD HL,#FILEPOS + LD A,(HL) + INC HL + CP (HL) ; ARE BOTH BYTES THE SAME? + RET NZ + INC A ; YES, BUT ARE THEY EACH 0FFH? + RET +; +; SET LOCATION (FILEPOS) TO 0FFFFH. +; +STFILPOS: + LD HL,#0x0FFFF + LD (FILEPOS),HL + RET +; +; MOVE ON TO THE NEXT FILE POSITION WITHIN THE CURRENT +; DIRECTORY BUFFER. IF NO MORE EXIST, SET POINTER TO 0FFFFH +; AND THE CALLING ROUTINE WILL CHECK FOR THIS. ENTER WITH (C) +; .EQUAL TO 0FFH TO CAUSE THE CHECKSUM BYTE TO BE SET, ELSE WE +; WILL CHECK THIS DISK AND SET WRITE PROTECT IF CHECKSUMS ARE +; NOT THE SAME (APPLIES ONLY IF ANOTHER DIRECTORY SECTOR MUST +; BE READ). +; +NXENTRY:LD HL,(DIRSIZE) ; GET DIRECTORY ENTRY SIZE LIMIT. + EX DE,HL + LD HL,(FILEPOS) ; GET CURRENT COUNT. + INC HL ; GO ON TO THE NEXT ONE. + LD (FILEPOS),HL + CALL SUBHL ; (HL)=(DIRSIZE)-(FILEPOS) + JP NC,NXENT1 ; IS THERE MORE ROOM LEFT? + JP STFILPOS ; NO. SET THIS FLAG AND RETURN. +NXENT1: LD A,(FILEPOS) ; GET FILE POSITION WITHIN DIRECTORY. + AND #3 ; ONLY LOOK WITHIN THIS SECTOR (ONLY 4 ENTRIES FIT). + LD B,#5 ; CONVERT TO RELATIVE POSITION (32 BYTES EACH). +NXENT2: ADD A,A ; NOTE THAT THIS IS NOT EFFICIENT CODE. + DEC B ; 5 'ADD A'S WOULD BE BETTER. + JP NZ,NXENT2 + LD (FCBPOS),A ; SAVE IT AS POSITION OF FCB. + OR A + RET NZ ; RETURN IF WE ARE WITHIN BUFFER. + PUSH BC + CALL TRKSEC ; WE NEED THE NEXT DIRECTORY SECTOR. + CALL DIRREAD + POP BC + JP CHECKDIR +; +; ROUTINE TO TO GET A BIT FROM THE DISK SPACE ALLOCATION +; MAP. IT IS RETURNED IN (A), BIT POSITION 0. ON ENTRY TO HERE, +; SET (BC) TO THE BLOCK NUMBER ON THE DISK TO CHECK. +; ON RETURN, (D) WILL CONTAIN THE ORIGINAL BIT POSITION FOR +; THIS BLOCK NUMBER AND (HL) WILL POINT TO THE ADDRESS FOR IT. +; +CKBITMAP: + LD A,C ; DETERMINE BIT NUMBER OF INTEREST. + AND #7 ; COMPUTE (D)=(E)=(C AND 7)+1. + INC A + LD E,A ; SAVE PARTICULAR BIT NUMBER. + LD D,A +; +; COMPUTE (BC)=(BC)/8. +; + LD A,C + RRCA ; NOW SHIFT RIGHT 3 BITS. + RRCA + RRCA + AND #0x1F ; AND CLEAR BITS 7,6,5. + LD C,A + LD A,B + ADD A,A ; NOW SHIFT (B) INTO BITS 7,6,5. + ADD A,A + ADD A,A + ADD A,A + ADD A,A + OR C ; AND ADD IN (C). + LD C,A ; OK, (C) HA BEEN COMPLETED. + LD A,B ; IS THERE A BETTER WAY OF DOING THIS? + RRCA + RRCA + RRCA + AND #0x1F + LD B,A ; AND NOW (B) IS COMPLETED. +; +; USE THIS AS AN OFFSET INTO THE DISK SPACE ALLOCATION +; TABLE. +; + LD HL,(ALOCVECT) + ADD HL,BC + LD A,(HL) ; NOW GET CORRECT BYTE. +CKBMAP1:RLCA ; GET CORRECT BIT INTO POSITION 0. + DEC E + JP NZ,CKBMAP1 + RET +; +; SET OR CLEAR THE BIT MAP SUCH THAT BLOCK NUMBER (BC) WILL BE MARKED +; AS USED. ON ENTRY, IF (E)=0 THEN THIS BIT WILL BE CLEARED, IF IT .EQUALS +; 1 THEN IT WILL BE SET (DON'T USE ANYOTHER VALUES). +; +STBITMAP: + PUSH DE + CALL CKBITMAP ; GET THE BYTE OF INTEREST. + AND #0x0FE ; CLEAR THE AFFECTED BIT. + POP BC + OR C ; AND NOW SET IT ACORDING TO (C). +; +; ENTRY TO RESTORE THE ORIGINAL BIT POSITION AND THEN STORE +; IN TABLE. (A) CONTAINS THE VALUE, (D) CONTAINS THE BIT +; POSITION (1-8), AND (HL) POINTS TO THE ADDRESS WITHIN THE +; SPACE ALLOCATION TABLE FOR THIS BYTE. +; +STBMAP1:RRCA ; RESTORE ORIGINAL BIT POSITION. + DEC D + JP NZ,STBMAP1 + LD (HL),A ; AND STOR BYTE IN TABLE. + RET +; +; SET/CLEAR SPACE USED BITS IN ALLOCATION MAP FOR THIS FILE. +; ON ENTRY, (C)=1 TO SET THE MAP AND (C)=0 TO CLEAR IT. +; +SETFILE:CALL FCB2HL ; GET ADDRESS OF FCB + LD DE,#16 + ADD HL,DE ; GET TO BLOCK NUMBER BYTES. + PUSH BC + LD C,#17 ; CHECK ALL 17 BYTES (MAX) OF TABLE. +SETFL1: POP DE + DEC C ; DONE ALL BYTES YET? + RET Z + PUSH DE + LD A,(BIGDISK) ; CHECK DISK SIZE FOR 16 BIT BLOCK NUMBERS. + OR A + JP Z,SETFL2 + PUSH BC ; ONLY 8 BIT NUMBERS. SET (BC) TO THIS ONE. + PUSH HL + LD C,(HL) ; GET LOW BYTE FROM TABLE, ALWAYS + LD B,#0 ; SET HIGH BYTE TO ZERO. + JP SETFL3 +SETFL2: DEC C ; FOR 16 BIT BLOCK NUMBERS, ADJUST COUNTER. + PUSH BC + LD C,(HL) ; NOW GET BOTH THE LOW AND HIGH BYTES. + INC HL + LD B,(HL) + PUSH HL +SETFL3: LD A,C ; BLOCK USED? + OR B + JP Z,SETFL4 + LD HL,(DSKSIZE) ; IS THIS BLOCK NUMBER WITHIN THE + LD A,L ; SPACE ON THE DISK? + SUB C + LD A,H + SBC A,B + CALL NC,STBITMAP ; YES, SET THE PROPER BIT. +SETFL4: POP HL ; POINT TO NEXT BLOCK NUMBER IN FCB. + INC HL + POP BC + JP SETFL1 +; +; CONSTRUCT THE SPACE USED ALLOCATION BIT MAP FOR THE ACTIVE +; DRIVE. IF A FILE NAME STARTS WITH '$' AND IT IS UNDER THE +; CURRENT USER NUMBER, THEN (STATUS) IS SET TO MINUS 1. OTHERWISE +; IT IS NOT SET AT ALL. +; +BITMAP: LD HL,(DSKSIZE) ; COMPUTE SIZE OF ALLOCATION TABLE. + LD C,#3 + CALL SHIFTR ; (HL)=(HL)/8. + INC HL ; AT LEASE 1 BYTE. + LD B,H + LD C,L ; SET (BC) TO THE ALLOCATION TABLE LENGTH. +; +; INITIALIZE THE BITMAP FOR THIS DRIVE. RIGHT NOW, THE FIRST +; TWO BYTES ARE SPECIFIED BY THE DISK PARAMETER BLOCK. HOWEVER +; A PATCH COULD BE ENTERED HERE IF IT WERE NECESSARY TO SETUP +; THIS TABLE IN A SPECIAL MANNOR. FOR EXAMPLE, THE BIOS COULD +; DETERMINE LOCATIONS OF 'BAD BLOCKS' AND SET THEM AS ALREADY +; 'USED' IN THE MAP. +; + LD HL,(ALOCVECT) ; NOW ZERO OUT THE TABLE NOW. +BITMAP1:LD (HL),#0 + INC HL + DEC BC + LD A,B + OR C + JP NZ,BITMAP1 + LD HL,(ALLOC0) ; GET INITIAL SPACE USED BY DIRECTORY. + EX DE,HL + LD HL,(ALOCVECT) ; AND PUT THIS INTO MAP. + LD (HL),E + INC HL + LD (HL),D +; +; END OF INITIALIZATION PORTION. +; + CALL HOMEDRV ; NOW HOME THE DRIVE. + LD HL,(SCRATCH1) + LD (HL),#3 ; FORCE NEXT DIRECTORY R.EQUEST TO READ + INC HL ; IN A SECTOR. + LD (HL),#0 + CALL STFILPOS ; CLEAR INITIAL FILE POSITION ALSO. +BITMAP2:LD C,#0x0FF ; READ NEXT FILE NAME IN DIRECTORY + CALL NXENTRY ; AND SET CHECKSUM BYTE. + CALL CKFILPOS ; IS THERE ANOTHER FILE? + RET Z + CALL FCB2HL ; YES, GET ITS ADDRESS. + LD A,#0x0E5 + CP (HL) ; EMPTY FILE ENTRY? + JP Z,BITMAP2 + LD A,(USERNO) ; NO, CORRECT USER NUMBER? + CP (HL) + JP NZ,BITMAP3 + INC HL + LD A,(HL) ; YES, DOES NAME START WITH A '$'? + SUB #DOLLAR + JP NZ,BITMAP3 + DEC A ; YES, SET ATATUS TO MINUS ONE. + LD (STATUS),A +BITMAP3:LD C,#1 ; NOW SET THIS FILE'S SPACE AS USED IN BIT MAP. + CALL SETFILE + CALL CHKNMBR ; KEEP (SCRATCH1) IN BOUNDS. + JP BITMAP2 +; +; SET THE STATUS (STATUS) AND RETURN. +; +STSTATUS: + LD A,(FNDSTAT) + JP SETSTAT +; +; CHECK EXTENTS IN (A) AND (C). SET THE ZERO FLAG IF THEY +; ARE THE SAME. THE NUMBER OF 16K CHUNKS OF DISK SPACE THAT +; THE DIRECTORY EXTENT COVERS IS EXPRESSAD IS (EXTMASK+1). +; NO REGISTERS ARE MODIFIED. +; +SAMEXT: PUSH BC + PUSH AF + LD A,(EXTMASK) ; GET EXTENT MASK AND USE IT TO + CPL ; TO COMPARE BOTH EXTENT NUMBERS. + LD B,A ; SAVE RESULTING MASK HERE. + LD A,C ; MASK FIRST EXTENT AND SAVE IN (C). + AND B + LD C,A + POP AF ; NOW MASK SECOND EXTENT AND COMPARE + AND B ; WITH THE FIRST ONE. + SUB C + AND #0x1F ; (* ONLY CHECK BUTS 0-4 *) + POP BC ; THE ZERO FLAG IS SET IF THEY ARE THE SAME. + RET ; RESTORE (BC) AND RETURN. +; +; SEARCH FOR THE FIRST OCCURENCE OF A FILE NAME. ON ENTRY, +; REGISTER (C) SHOULD CONTAIN THE NUMBER OF BYTES OF THE FCB +; THAT MUST MATCH. +; +FINDFST:LD A,#0x0FF + LD (FNDSTAT),A + LD HL,#COUNTER ; SAVE CHARACTER COUNT. + LD (HL),C + LD HL,(PARAMS) ; GET FILENAME TO MATCH. + LD (SAVEFCB),HL ; AND SAVE. + CALL STFILPOS ; CLEAR INITIAL FILE POSITION (SET TO 0FFFFH). + CALL HOMEDRV ; HOME THE DRIVE. +; +; ENTRY TO LOCATE THE NEXT OCCURENCE OF A FILENAME WITHIN THE +; DIRECTORY. THE DISK IS NOT EXPECTED TO HAVE BEEN CHANGED. IF +; IT WAS, THEN IT WILL BE WRITE PROTECTED. +; +FINDNXT:LD C,#0 ; WRITE PROTECT THE DISK IF CHANGED. + CALL NXENTRY ; GET NEXT FILENAME ENTRY IN DIRECTORY. + CALL CKFILPOS ; IS FILE POSITION = 0FFFFH? + JP Z,FNDNXT6 ; YES, EXIT NOW THEN. + LD HL,(SAVEFCB) ; SET (DE) POINTING TO FILENAME TO MATCH. + EX DE,HL + LD A,(DE) + CP #0x0E5 ; EMPTY DIRECTORY ENTRY? + JP Z,FNDNXT1 ; (* ARE WE TRYING TO RESERECT ERASED ENTRIES? *) + PUSH DE + CALL MOREFLS ; MORE FILES IN DIRECTORY? + POP DE + JP NC,FNDNXT6 ; NO MORE. EXIT NOW. +FNDNXT1:CALL FCB2HL ; GET ADDRESS OF THIS FCB IN DIRECTORY. + LD A,(COUNTER) ; GET NUMBER OF BYTES (CHARACTERS) TO CHECK. + LD C,A + LD B,#0 ; INITIALIZE BYTE POSITION COUNTER. +FNDNXT2:LD A,C ; ARE WE DONE WITH THE COMPARE? + OR A + JP Z,FNDNXT5 + LD A,(DE) ; NO, CHECK NEXT BYTE. + CP #QUESTION ; DON'T CARE ABOUT THIS CHARACTER? + JP Z,FNDNXT4 + LD A,B ; GET BYTES POSITION IN FCB. + CP #13 ; DON'T CARE ABOUT THE THIRTEENTH BYTE EITHER. + JP Z,FNDNXT4 + CP #12 ; EXTENT BYTE? + LD A,(DE) + JP Z,FNDNXT3 + SUB (HL) ; OTHERWISE COMPARE CHARACTERS. + AND #0x7F + JP NZ,FINDNXT ; NOT THE SAME, CHECK NEXT ENTRY. + JP FNDNXT4 ; SO FAR SO GOOD, KEEP CHECKING. +FNDNXT3:PUSH BC ; CHECK THE EXTENT BYTE HERE. + LD C,(HL) + CALL SAMEXT + POP BC + JP NZ,FINDNXT ; NOT THE SAME, LOOK SOME MORE. +; +; SO FAR THE NAMES COMPARE. BUMP POINTERS TO THE NEXT BYTE +; AND CONTINUE UNTIL ALL (C) CHARACTERS HAVE BEEN CHECKED. +; +FNDNXT4:INC DE ; BUMP POINTERS. + INC HL + INC B + DEC C ; ADJUST CHARACTER COUNTER. + JP FNDNXT2 +FNDNXT5:LD A,(FILEPOS) ; RETURN THE POSITION OF THIS ENTRY. + AND #3 + LD (STATUS),A + LD HL,#FNDSTAT + LD A,(HL) + RLA + RET NC + XOR A + LD (HL),A + RET +; +; FILENAME WAS NOT FOUND. SET APPROPRIATE STATUS. +; +FNDNXT6:CALL STFILPOS ; SET (FILEPOS) TO 0FFFFH. + LD A,#0x0FF ; SAY NOT LOCATED. + JP SETSTAT +; +; ERASE FILES FROM THE DIRECTORY. ONLY THE FIRST BYTE OF THE +; FCB WILL BE AFFECTED. IT IS SET TO (E5). +; +ERAFILE:CALL CHKWPRT ; IS DISK WRITE PROTECTED? + LD C,#12 ; ONLY COMPARE FILE NAMES. + CALL FINDFST ; GET FIRST FILE NAME. +ERAFIL1:CALL CKFILPOS ; ANY FOUND? + RET Z ; NOPE, WE MUST BE DONE. + CALL CHKROFL ; IS FILE READ ONLY? + CALL FCB2HL ; NOPE, GET ADDRESS OF FCB AND + LD (HL),#0x0E5 ; SET FIRST BYTE TO 'EMPTY'. + LD C,#0 ; CLEAR THE SPACE FROM THE BIT MAP. + CALL SETFILE + CALL DIRWRITE ; NOW WRITE THE DIRECTORY SECTOR BACK OUT. + CALL FINDNXT ; FIND THE NEXT FILE NAME. + JP ERAFIL1 ; AND REPEAT PROCESS. +; +; LOOK THROUGH THE SPACE ALLOCATION MAP (BIT MAP) FOR THE +; NEXT AVAILABLE BLOCK. START SEARCHING AT BLOCK NUMBER (BC-1). +; THE SEARCH PROCEDURE IS TO LOOK FOR AN EMPTY BLOCK THAT IS +; BEFORE THE STARTING BLOCK. IF NOT EMPTY, LOOK AT A LATER +; BLOCK NUMBER. IN THIS WAY, WE RETURN THE CLOSEST EMPTY BLOCK +; ON EITHER SIDE OF THE 'TARGET' BLOCK NUMBER. THIS WILL SPEED +; ACCESS ON RANDOM DEVICES. FOR SERIAL DEVICES, THIS SHOULD BE +; CHANGED TO LOOK IN THE FORWARD DIRECTION FIRST AND THEN START +; AT THE FRONT AND SEARCH SOME MORE. +; +; ON RETURN, (DE)= BLOCK NUMBER THAT IS EMPTY AND (HL) =0 +; IF NO EMPRY BLOCK WAS FOUND. +; +FNDSPACE: + LD D,B ; SET (DE) AS THE BLOCK THAT IS CHECKED. + LD E,C +; +; LOOK BEFORE TARGET BLOCK. REGISTERS (BC) ARE USED AS THE LOWER +; POINTER AND (DE) AS THE UPPER POINTER. +; +FNDSPA1:LD A,C ; IS BLOCK 0 SPECIFIED? + OR B + JP Z,FNDSPA2 + DEC BC ; NOPE, CHECK PREVIOUS BLOCK. + PUSH DE + PUSH BC + CALL CKBITMAP + RRA ; IS THIS BLOCK EMPTY? + JP NC,FNDSPA3 ; YES. USE THIS. +; +; NOTE THAT THE ABOVE LOGIC GETS THE FIRST BLOCK THAT IT FINDS +; THAT IS EMPTY. THUS A FILE COULD BE WRITTEN 'BACKWARD' MAKING +; IT VERY SLOW TO ACCESS. THIS COULD BE CHANGED TO LOOK FOR THE +; FIRST EMPTY BLOCK AND THEN CONTINUE UNTIL THE START OF THIS +; EMPTY SPACE IS LOCATED AND THEN USED THAT STARTING BLOCK. +; THIS SHOULD HELP SPEED UP ACCESS TO SOME FILES ESPECIALLY ON +; A WELL USED DISK WITH LOTS OF FAIRLY SMALL 'HOLES'. +; + POP BC ; NOPE, CHECK SOME MORE. + POP DE +; +; NOW LOOK AFTER TARGET BLOCK. +; +FNDSPA2:LD HL,(DSKSIZE) ; IS BLOCK (DE) WITHIN DISK LIMITS? + LD A,E + SUB L + LD A,D + SBC A,H + JP NC,FNDSPA4 + INC DE ; YES, MOVE ON TO NEXT ONE. + PUSH BC + PUSH DE + LD B,D + LD C,E + CALL CKBITMAP ; CHECK IT. + RRA ; EMPTY? + JP NC,FNDSPA3 + POP DE ; NOPE, CONTINUE SEARCHING. + POP BC + JP FNDSPA1 +; +; EMPTY BLOCK FOUND. SET IT AS USED AND RETURN WITH (HL) +; POINTING TO IT (TRUE?). +; +FNDSPA3:RLA ; RESET BYTE. + INC A ; AND SET BIT 0. + CALL STBMAP1 ; UPDATE BIT MAP. + POP HL ; SET RETURN REGISTERS. + POP DE + RET +; +; FREE BLOCK WAS NOT FOUND. IF (BC) IS NOT ZERO, THEN WE HAVE +; NOT CHECKED ALL OF THE DISK SPACE. +; +FNDSPA4:LD A,C + OR B + JP NZ,FNDSPA1 + LD HL,#0 ; SET 'NOT FOUND' STATUS. + RET +; +; MOVE A COMPLETE FCB ENTRY INTO THE DIRECTORY AND WRITE IT. +; +FCBSET: LD C,#0 + LD E,#32 ; LENGTH OF EACH ENTRY. +; +; MOVE (E) BYTES FROM THE FCB POINTED TO BY (PARAMS) INTO +; FCB IN DIRECTORY STARTING AT RELATIVE BYTE (C). THIS UPDATED +; DIRECTORY BUFFER IS THEN WRITTEN TO THE DISK. +; +UPDATE: PUSH DE + LD B,#0 ; SET (BC) TO RELATIVE BYTE POSITION. + LD HL,(PARAMS) ; GET ADDRESS OF FCB. + ADD HL,BC ; COMPUTE STARTING BYTE. + EX DE,HL + CALL FCB2HL ; GET ADDRESS OF FCB TO UPDATE IN DIRECTORY. + POP BC ; SET (C) TO NUMBER OF BYTES TO CHANGE. + CALL DE2HL +UPDATE1:CALL TRKSEC ; DETERMINE THE TRACK AND SECTOR AFFECTED. + JP DIRWRITE ; THEN WRITE THIS SECTOR OUT. +; +; ROUTINE TO CHANGE THE NAME OF ALL FILES ON THE DISK WITH A +; SPECIFIED NAME. THE FCB CONTAINS THE CURRENT NAME AS THE +; FIRST 12 CHARACTERS AND THE NEW NAME 16 BYTES INTO THE FCB. +; +CHGNAMES: + CALL CHKWPRT ; CHECK FOR A WRITE PROTECTED DISK. + LD C,#12 ; MATCH FIRST 12 BYTES OF FCB ONLY. + CALL FINDFST ; GET FIRST NAME. + LD HL,(PARAMS) ; GET ADDRESS OF FCB. + LD A,(HL) ; GET USER NUMBER. + LD DE,#16 ; MOVE OVER TO DESIRED NAME. + ADD HL,DE + LD (HL),A ; KEEP SAME USER NUMBER. +CHGNAM1:CALL CKFILPOS ; ANY MATCHING FILE FOUND? + RET Z ; NO, WE MUST BE DONE. + CALL CHKROFL ; CHECK FOR READ ONLY FILE. + LD C,#16 ; START 16 BYTES INTO FCB. + LD E,#12 ; AND UPDATE THE FIRST 12 BYTES OF DIRECTORY. + CALL UPDATE + CALL FINDNXT ; GET TE NEXT FILE NAME. + JP CHGNAM1 ; AND CONTINUE. +; +; UPDATE A FILES ATTRIBUTES. THE PROCEDURE IS TO SEARCH FOR +; EVERY FILE WITH THE SAME NAME AS SHOWN IN FCB (IGNORING BIT 7) +; AND THEN TO UPDATE IT (WHICH INCLUDES BIT 7). NO OTHER CHANGES +; ARE MADE. +; +SAVEATTR: + LD C,#12 ; MATCH FIRST 12 BYTES. + CALL FINDFST ; LOOK FOR FIRST FILENAME. +SAVATR1:CALL CKFILPOS ; WAS ONE FOUND? + RET Z ; NOPE, WE MUST BE DONE. + LD C,#0 ; YES, UPDATE THE FIRST 12 BYTES NOW. + LD E,#12 + CALL UPDATE ; UPDATE FILENAME AND WRITE DIRECTORY. + CALL FINDNXT ; AND GET THE NEXT FILE. + JP SAVATR1 ; THEN CONTINUE UNTIL DONE. +; +; OPEN A FILE (NAME SPECIFIED IN FCB). +; +OPENIT: LD C,#15 ; COMPARE THE FIRST 15 BYTES. + CALL FINDFST ; GET THE FIRST ONE IN DIRECTORY. + CALL CKFILPOS ; ANY AT ALL? + RET Z +OPENIT1:CALL SETEXT ; POINT TO EXTENT BYTE WITHIN USERS FCB. + LD A,(HL) ; AND GET IT. + PUSH AF ; SAVE IT AND ADDRESS. + PUSH HL + CALL FCB2HL ; POINT TO FCB IN DIRECTORY. + EX DE,HL + LD HL,(PARAMS) ; THIS IS THE USERS COPY. + LD C,#32 ; MOVE IT INTO USERS SPACE. + PUSH DE + CALL DE2HL + CALL SETS2B7 ; SET BIT 7 IN 'S2' BYTE (UNMODIFIED). + POP DE ; NOW GET THE EXTENT BYTE FROM THIS FCB. + LD HL,#12 + ADD HL,DE + LD C,(HL) ; INTO (C). + LD HL,#15 ; NOW GET THE RECORD COUNT BYTE INTO (B). + ADD HL,DE + LD B,(HL) + POP HL ; KEEP THE SAME EXTENT AS THE USER HAD ORIGINALLY. + POP AF + LD (HL),A + LD A,C ; IS IT THE SAME AS IN THE DIRECTORY FCB? + CP (HL) + LD A,B ; IF YES, THEN USE THE SAME RECORD COUNT. + JP Z,OPENIT2 + LD A,#0 ; IF THE USER SPECIFIED AN EXTENT GREATER THAN + JP C,OPENIT2 ; THE ONE IN THE DIRECTORY, THEN SET RECORD COUNT TO 0. + LD A,#128 ; OTHERWISE SET TO MAXIMUM. +OPENIT2:LD HL,(PARAMS) ; SET RECORD COUNT IN USERS FCB TO (A). + LD DE,#15 + ADD HL,DE ; COMPUTE RELATIVE POSITION. + LD (HL),A ; AND SET THE RECORD COUNT. + RET +; +; MOVE TWO BYTES FROM (DE) TO (HL) IF (AND ONLY IF) (HL) +; POINT TO A ZERO VALUE (16 BIT). +; RETURN WITH ZERO FLAG SET IT (DE) WAS MOVED. REGISTERS (DE) +; AND (HL) ARE NOT CHANGED. HOWEVER (A) IS. +; +MOVEWORD: + LD A,(HL) ; CHECK FOR A ZERO WORD. + INC HL + OR (HL) ; BOTH BYTES ZERO? + DEC HL + RET NZ ; NOPE, JUST RETURN. + LD A,(DE) ; YES, MOVE TWO BYTES FROM (DE) INTO + LD (HL),A ; THIS ZERO SPACE. + INC DE + INC HL + LD A,(DE) + LD (HL),A + DEC DE ; DON'T DISTURB THESE REGISTERS. + DEC HL + RET +; +; GET HERE TO CLOSE A FILE SPECIFIED BY (FCB). +; +CLOSEIT:XOR A ; CLEAR STATUS AND FILE POSITION BYTES. + LD (STATUS),A + LD (FILEPOS),A + LD (FILEPOS+1),A + CALL GETWPRT ; GET WRITE PROTECT BIT FOR THIS DRIVE. + RET NZ ; JUST RETURN IF IT IS SET. + CALL GETS2 ; ELSE GET THE 'S2' BYTE. + AND #0x80 ; AND LOOK AT BIT 7 (FILE UNMODIFIED?). + RET NZ ; JUST RETURN IF SET. + LD C,#15 ; ELSE LOOK UP THIS FILE IN DIRECTORY. + CALL FINDFST + CALL CKFILPOS ; WAS IT FOUND? + RET Z ; JUST RETURN IF NOT. + LD BC,#16 ; SET (HL) POINTING TO RECORDS USED SECTION. + CALL FCB2HL + ADD HL,BC + EX DE,HL + LD HL,(PARAMS) ; DO THE SAME FOR USERS SPECIFIED FCB. + ADD HL,BC + LD C,#16 ; THIS MANY BYTES ARE PRESENT IN THIS EXTENT. +CLOSEIT1: + LD A,(BIGDISK) ; 8 OR 16 BIT RECORD NUMBERS? + OR A + JP Z,CLOSEIT4 + LD A,(HL) ; JUST 8 BIT. GET ONE FROM USERS FCB. + OR A + LD A,(DE) ; NOW GET ONE FROM DIRECTORY FCB. + JP NZ,CLOSEIT2 + LD (HL),A ; USERS BYTE WAS ZERO. UPDATE FROM DIRECTORY. +CLOSEIT2: + OR A + JP NZ,CLOSEIT3 + LD A,(HL) ; DIRECTORIES BYTE WAS ZERO, UPDATE FROM USERS FCB. + LD (DE),A +CLOSEIT3: + CP (HL) ; IF NEITHER ONE OF THESE BYTES WERE ZERO, + JP NZ,CLOSEIT7 ; THEN CLOSE ERROR IF THEY ARE NOT THE SAME. + JP CLOSEIT5 ; OK SO FAR, GET TO NEXT BYTE IN FCBS. +CLOSEIT4: + CALL MOVEWORD ; UPDATE USERS FCB IF IT IS ZERO. + EX DE,HL + CALL MOVEWORD ; UPDATE DIRECTORIES FCB IF IT IS ZERO. + EX DE,HL + LD A,(DE) ; IF THESE TWO VALUES ARE NO DIFFERENT, + CP (HL) ; THEN A CLOSE ERROR OCCURED. + JP NZ,CLOSEIT7 + INC DE ; CHECK SECOND BYTE. + INC HL + LD A,(DE) + CP (HL) + JP NZ,CLOSEIT7 + DEC C ; REMEMBER 16 BIT VALUES. +CLOSEIT5: + INC DE ; BUMP TO NEXT ITEM IN TABLE. + INC HL + DEC C ; THERE ARE 16 ENTRIES ONLY. + JP NZ,CLOSEIT1 ; CONTINUE IF MORE TO DO. + LD BC,#0x0FFEC ; BACKUP 20 PLACES (EXTENT BYTE). + ADD HL,BC + EX DE,HL + ADD HL,BC + LD A,(DE) + CP (HL) ; DIRECTORY'S EXTENT ALREADY GREATER THAN THE + JP C,CLOSEIT6 ; USERS EXTENT? + LD (HL),A ; NO, UPDATE DIRECTORY EXTENT. + LD BC,#3 ; AND UPDATE THE RECORD COUNT BYTE IN + ADD HL,BC ; DIRECTORIES FCB. + EX DE,HL + ADD HL,BC + LD A,(HL) ; GET FROM USER. + LD (DE),A ; AND PUT IN DIRECTORY. +CLOSEIT6: + LD A,#0x0FF ; SET 'WAS OPEN AND IS NOW CLOSED' BYTE. + LD (CLOSEFLG),A + JP UPDATE1 ; UPDATE THE DIRECTORY NOW. +CLOSEIT7: + LD HL,#STATUS ; SET RETURN STATUS AND THEN RETURN. + DEC (HL) + RET +; +; ROUTINE TO GET THE NEXT EMPTY SPACE IN THE DIRECTORY. IT +; WILL THEN BE CLEARED FOR USE. +; +GETEMPTY: + CALL CHKWPRT ; MAKE SURE DISK IS NOT WRITE PROTECTED. + LD HL,(PARAMS) ; SAVE CURRENT PARAMETERS (FCB). + PUSH HL + LD HL,#EMPTYFCB ; USE SPECIAL ONE FOR EMPTY SPACE. + LD (PARAMS),HL + LD C,#1 ; SEARCH FOR FIRST EMPTY SPOT IN DIRECTORY. + CALL FINDFST ; (* ONLY CHECK FIRST BYTE *) + CALL CKFILPOS ; NONE? + POP HL + LD (PARAMS),HL ; RESTORE ORIGINAL FCB ADDRESS. + RET Z ; RETURN IF NO MORE SPACE. + EX DE,HL + LD HL,#15 ; POINT TO NUMBER OF RECORDS FOR THIS FILE. + ADD HL,DE + LD C,#17 ; AND CLEAR ALL OF THIS SPACE. + XOR A +GETMT1: LD (HL),A + INC HL + DEC C + JP NZ,GETMT1 + LD HL,#13 ; CLEAR THE 'S1' BYTE ALSO. + ADD HL,DE + LD (HL),A + CALL CHKNMBR ; KEEP (SCRATCH1) WITHIN BOUNDS. + CALL FCBSET ; WRITE OUT THIS FCB ENTRY TO DIRECTORY. + JP SETS2B7 ; SET 'S2' BYTE BIT 7 (UNMODIFIED AT PRESENT). +; +; ROUTINE TO CLOSE THE CURRENT EXTENT AND OPEN THE NEXT ONE +; FOR READING. +; +GETNEXT:XOR A + LD (CLOSEFLG),A ; CLEAR CLOSE FLAG. + CALL CLOSEIT ; CLOSE THIS EXTENT. + CALL CKFILPOS + RET Z ; NOT THERE??? + LD HL,(PARAMS) ; GET EXTENT BYTE. + LD BC,#12 + ADD HL,BC + LD A,(HL) ; AND INCREMENT IT. + INC A + AND #0x1F ; KEEP WITHIN RANGE 0-31. + LD (HL),A + JP Z,GTNEXT1 ; OVERFLOW? + LD B,A ; MASK EXTENT BYTE. + LD A,(EXTMASK) + AND B + LD HL,#CLOSEFLG ; CHECK CLOSE FLAG (0FFH IS OK). + AND (HL) + JP Z,GTNEXT2 ; IF ZERO, WE MUST READ IN NEXT EXTENT. + JP GTNEXT3 ; ELSE, IT IS ALREADY IN MEMORY. +GTNEXT1:LD BC,#2 ; POINT TO THE 'S2' BYTE. + ADD HL,BC + INC (HL) ; AND BUMP IT. + LD A,(HL) ; TOO MANY EXTENTS? + AND #0x0F + JP Z,GTNEXT5 ; YES, SET ERROR CODE. +; +; GET HERE TO OPEN THE NEXT EXTENT. +; +GTNEXT2:LD C,#15 ; SET TO CHECK FIRST 15 BYTES OF FCB. + CALL FINDFST ; FIND THE FIRST ONE. + CALL CKFILPOS ; NONE AVAILABLE? + JP NZ,GTNEXT3 + LD A,(R.DWRTFLG) ; NO EXTENT PRESENT. CAN WE OPEN AN EMPTY ONE? + INC A ; 0FFH MEANS READING (SO NOT POSSIBLE). + JP Z,GTNEXT5 ; OR AN ERROR. + CALL GETEMPTY ; WE ARE WRITING, GET AN EMPTY ENTRY. + CALL CKFILPOS ; NONE? + JP Z,GTNEXT5 ; ERROR IF TRUE. + JP GTNEXT4 ; ELSE WE ARE ALMOST DONE. +GTNEXT3:CALL OPENIT1 ; OPEN THIS EXTENT. +GTNEXT4:CALL STRDATA ; MOVE IN UPDATED DATA (REC #, EXTENT #, ETC.) + XOR A ; CLEAR STATUS AND RETURN. + JP SETSTAT +; +; ERROR IN EXTENDING THE FILE. TOO MANY EXTENTS WERE NEEDED +; OR NOT ENOUGH SPACE ON THE DISK. +; +GTNEXT5:CALL IOERR1 ; SET ERROR CODE, CLEAR BIT 7 OF 'S2' + JP SETS2B7 ; SO THIS IS NOT WRITTEN ON A CLOSE. +; +; READ A S.EQUENTIAL FILE. +; +RDSEQ: LD A,#1 ; SET S.EQUENTIAL ACCESS MODE. + LD (MODE),A +RDSEQ1: LD A,#0x0FF ; DON'T ALLOW READING UNWRITTEN SPACE. + LD (R.DWRTFLG),A + CALL STRDATA ; PUT REC# AND EXT# INTO FCB. + LD A,(SAVNREC) ; GET NEXT RECORD TO READ. + LD HL,#SAVNXT ; GET NUMBER OF RECORDS IN EXTENT. + CP (HL) ; WITHIN THIS EXTENT? + JP C,RDSEQ2 + CP #128 ; NO. IS THIS EXTENT FULLY USED? + JP NZ,RDSEQ3 ; NO. END-OF-FILE. + CALL GETNEXT ; YES, OPEN THE NEXT ONE. + XOR A ; RESET NEXT RECORD TO READ. + LD (SAVNREC),A + LD A,(STATUS) ; CHECK ON OPEN, SUCCESSFUL? + OR A + JP NZ,RDSEQ3 ; NO, ERROR. +RDSEQ2: CALL COMBLK ; OK. COMPUTE BLOCK NUMBER TO READ. + CALL CHKBLK ; CHECK IT. WITHIN BOUNDS? + JP Z,RDSEQ3 ; NO, ERROR. + CALL LOGICAL ; CONVERT (BLKNMBR) TO LOGICAL SECTOR (128 BYTE). + CALL TRKSEC1 ; SET THE TRACK AND SECTOR FOR THIS BLOCK #. + CALL DOREAD ; AND READ IT. + JP SETNREC ; AND SET THE NEXT RECORD TO BE ACCESSED. +; +; READ ERROR OCCURED. SET STATUS AND RETURN. +; +RDSEQ3: JP IOERR1 +; +; WRITE THE NEXT S.EQUENTIAL RECORD. +; +WTSEQ: LD A,#1 ; SET S.EQUENTIAL ACCESS MODE. + LD (MODE),A +WTSEQ1: LD A,#0 ; ALLOW AN ADDITION EMPTY EXTENT TO BE OPENED. + LD (R.DWRTFLG),A + CALL CHKWPRT ; CHECK WRITE PROTECT STATUS. + LD HL,(PARAMS) + CALL CKROF1 ; CHECK FOR READ ONLY FILE, (HL) ALREADY SET TO FCB. + CALL STRDATA ; PUT UPDATED DATA INTO FCB. + LD A,(SAVNREC) ; GET RECORD NUMBER TO WRITE. + CP #128 ; WITHIN RANGE? + JP NC,IOERR1 ; NO, ERROR(?). + CALL COMBLK ; COMPUTE BLOCK NUMBER. + CALL CHKBLK ; CHECK NUMBER. + LD C,#0 ; IS THERE ONE TO WRITE TO? + JP NZ,WTSEQ6 ; YES, GO DO IT. + CALL GETBLOCK ; GET NEXT BLOCK NUMBER WITHIN FCB TO USE. + LD (RELBLOCK),A ; AND SAVE. + LD BC,#0 ; START LOOKING FOR SPACE FROM THE START + OR A ; IF NONE ALLOCATED AS YET. + JP Z,WTSEQ2 + LD C,A ; EXTRACT PREVIOUS BLOCK NUMBER FROM FCB + DEC BC ; SO WE CAN BE CLOSEST TO IT. + CALL EXTBLK + LD B,H + LD C,L +WTSEQ2: CALL FNDSPACE ; FIND THE NEXT EMPTY BLOCK NEAREST NUMBER (BC). + LD A,L ; CHECK FOR A ZERO NUMBER. + OR H + JP NZ,WTSEQ3 + LD A,#2 ; NO MORE SPACE? + JP SETSTAT +WTSEQ3: LD (BLKNMBR),HL ; SAVE BLOCK NUMBER TO ACCESS. + EX DE,HL ; PUT BLOCK NUMBER INTO (DE). + LD HL,(PARAMS) ; NOW WE MUST UPDATE THE FCB FOR THIS + LD BC,#16 ; NEWLY ALLOCATED BLOCK. + ADD HL,BC + LD A,(BIGDISK) ; 8 OR 16 BIT BLOCK NUMBERS? + OR A + LD A,(RELBLOCK) ; (* UPDATE THIS ENTRY *) + JP Z,WTSEQ4 ; ZERO MEANS 16 BIT ONES. + CALL ADDA2HL ; (HL)=(HL)+(A) + LD (HL),E ; STORE NEW BLOCK NUMBER. + JP WTSEQ5 +WTSEQ4: LD C,A ; COMPUTE SPOT IN THIS 16 BIT TABLE. + LD B,#0 + ADD HL,BC + ADD HL,BC + LD (HL),E ; STUFF BLOCK NUMBER (DE) THERE. + INC HL + LD (HL),D +WTSEQ5: LD C,#2 ; SET (C) TO INDICATE WRITING TO UN-USED DISK SPACE. +WTSEQ6: LD A,(STATUS) ; ARE WE OK SO FAR? + OR A + RET NZ + PUSH BC ; YES, SAVE WRITE FLAG FOR BIOS (REGISTER C). + CALL LOGICAL ; CONVERT (BLKNMBR) OVER TO LOICAL SECTORS. + LD A,(MODE) ; GET ACCESS MODE FLAG (1=S.EQUENTIAL, + DEC A ; 0=RANDOM, 2=SPECIAL?). + DEC A + JP NZ,WTSEQ9 +; +; SPECIAL RANDOM I/O FROM FUNCTION #40. MAYBE FOR M/PM, BUT THE +; CURRENT BLOCK, IF IT HAS NOT BEEN WRITTEN TO, WILL BE ZEROED +; OUT AND THEN WRITTEN (REASON?). +; + POP BC + PUSH BC + LD A,C ; GET WRITE STATUS FLAG (2=WRITING UNUSED SPACE). + DEC A + DEC A + JP NZ,WTSEQ9 + PUSH HL + LD HL,(DIRBUF) ; ZERO OUT THE DIRECTORY BUFFER. + LD D,A ; NOTE THAT (A) IS ZERO HERE. +WTSEQ7: LD (HL),A + INC HL + INC D ; DO 128 BYTES. + JP P,WTSEQ7 + CALL DIRDMA ; TELL THE BIOS THE DMA ADDRESS FOR DIRECTORY ACCESS. + LD HL,(LOGSECT) ; GET SECTOR THAT STARTS CURRENT BLOCK. + LD C,#2 ; SET 'WRITING TO UNUSED SPACE' FLAG. +WTSEQ8: LD (BLKNMBR),HL ; SAVE SECTOR TO WRITE. + PUSH BC + CALL TRKSEC1 ; DETERMINE ITS TRACK AND SECTOR NUMBERS. + POP BC + CALL DOWRITE ; NOW WRITE OUT 128 BYTES OF ZEROS. + LD HL,(BLKNMBR) ; GET SECTOR NUMBER. + LD C,#0 ; SET NORMAL WRITE FLAG. + LD A,(BLKMASK) ; DETERMINE IF WE HAVE WRITTEN THE ENTIRE + LD B,A ; PHYSICAL BLOCK. + AND L + CP B + INC HL ; PREPARE FOR THE NEXT ONE. + JP NZ,WTSEQ8 ; CONTINUE UNTIL (BLKMASK+1) SECTORS WRITTEN. + POP HL ; RESET NEXT SECTOR NUMBER. + LD (BLKNMBR),HL + CALL DEFDMA ; AND RESET DMA ADDRESS. +; +; NORMAL DISK WRITE. SET THE DESIRED TRACK AND SECTOR THEN +; DO THE ACTUAL WRITE. +; +WTSEQ9: CALL TRKSEC1 ; DETERMINE TRACK AND SECTOR FOR THIS WRITE. + POP BC ; GET WRITE STATUS FLAG. + PUSH BC + CALL DOWRITE ; AND WRITE THIS OUT. + POP BC + LD A,(SAVNREC) ; GET NUMBER OF RECORDS IN FILE. + LD HL,#SAVNXT ; GET LAST RECORD WRITTEN. + CP (HL) + JP C,WTSEQ10 + LD (HL),A ; WE HAVE TO UPDATE RECORD COUNT. + INC (HL) + LD C,#2 +; +;* THIS AREA HAS BEEN PATCHED TO CORRECT DISK UPDATE PROBLEM +;* WHEN USING BLOCKING AND DE-BLOCKING IN THE BIOS. +; +WTSEQ10:NOP ; WAS 'DCR C' + NOP ; WAS 'DCR C' + LD HL,#0 ; WAS 'JNZ WTSEQ99' +; +; * END OF PATCH. +; + PUSH AF + CALL GETS2 ; SET 'EXTENT WRITTEN TO' FLAG. + AND #0x7F ; (* CLEAR BIT 7 *) + LD (HL),A + POP AF ; GET RECORD COUNT FOR THIS EXTENT. +WTSEQ99:CP #127 ; IS IT FULL? + JP NZ,WTSEQ12 + LD A,(MODE) ; YES, ARE WE IN S.EQUENTIAL MODE? + CP #1 + JP NZ,WTSEQ12 + CALL SETNREC ; YES, SET NEXT RECORD NUMBER. + CALL GETNEXT ; AND GET NEXT EMPTY SPACE IN DIRECTORY. + LD HL,#STATUS ; OK? + LD A,(HL) + OR A + JP NZ,WTSEQ11 + DEC A ; YES, SET RECORD COUNT TO -1. + LD (SAVNREC),A +WTSEQ11:LD (HL),#0 ; CLEAR STATUS. +WTSEQ12:JP SETNREC ; SET NEXT RECORD TO ACCESS. +; +; FOR RANDOM I/O, SET THE FCB FOR THE DESIRED RECORD NUMBER +; BASED ON THE 'R0,R1,R2' BYTES. THESE BYTES IN THE FCB ARE +; USED AS FOLLOWS: +; +; FCB+35 FCB+34 FCB+33 +; | 'R-2' | 'R-1' | 'R-0' | +; |7 0 | 7 0 | 7 0| +; |0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0| +; | OVERFLOW | | EXTRA | EXTENT | RECORD # | +; | ______________| |_EXTENT|__NUMBER___|_____________| +; ALSO 'S2' +; +; ON ENTRY, REGISTER (C) CONTAINS 0FFH IF THIS IS A READ +; AND THUS WE CAN NOT ACCESS UNWRITTEN DISK SPACE. OTHERWISE, +; ANOTHER EXTENT WILL BE OPENED (FOR WRITING) IF R.EQUIRED. +; +POSITION: + XOR A ; SET RANDOM I/O FLAG. + LD (MODE),A +; +; SPECIAL ENTRY (FUNCTION #40). M/PM ? +; +POSITN1:PUSH BC ; SAVE READ/WRITE FLAG. + LD HL,(PARAMS) ; GET ADDRESS OF FCB. + EX DE,HL + LD HL,#33 ; NOW GET BYTE 'R0'. + ADD HL,DE + LD A,(HL) + AND #0x7F ; KEEP BITS 0-6 FOR THE RECORD NUMBER TO ACCESS. + PUSH AF + LD A,(HL) ; NOW GET BIT 7 OF 'R0' AND BITS 0-3 OF 'R1'. + RLA + INC HL + LD A,(HL) + RLA + AND #0x1F ; AND SAVE THIS IN BITS 0-4 OF (C). + LD C,A ; THIS IS THE EXTENT BYTE. + LD A,(HL) ; NOW GET THE EXTRA EXTENT BYTE. + RRA + RRA + RRA + RRA + AND #0x0F + LD B,A ; AND SAVE IT IN (B). + POP AF ; GET RECORD NUMBER BACK TO (A). + INC HL ; CHECK OVERFLOW BYTE 'R2'. + LD L,(HL) + INC L + DEC L + LD L,#6 ; PREPARE FOR ERROR. + JP NZ,POSITN5 ; OUT OF DISK SPACE ERROR. + LD HL,#32 ; STORE RECORD NUMBER INTO FCB. + ADD HL,DE + LD (HL),A + LD HL,#12 ; AND NOW CHECK THE EXTENT BYTE. + ADD HL,DE + LD A,C + SUB (HL) ; SAME EXTENT AS BEFORE? + JP NZ,POSITN2 + LD HL,#14 ; YES, CHECK EXTRA EXTENT BYTE 'S2' ALSO. + ADD HL,DE + LD A,B + SUB (HL) + AND #0x7F + JP Z,POSITN3 ; SAME, WE ARE ALMOST DONE THEN. +; +; GET HERE WHEN ANOTHER EXTENT IS R.EQUIRED. +; +POSITN2:PUSH BC + PUSH DE + CALL CLOSEIT ; CLOSE CURRENT EXTENT. + POP DE + POP BC + LD L,#3 ; PREPARE FOR ERROR. + LD A,(STATUS) + INC A + JP Z,POSITN4 ; CLOSE ERROR. + LD HL,#12 ; PUT DESIRED EXTENT INTO FCB NOW. + ADD HL,DE + LD (HL),C + LD HL,#14 ; AND STORE EXTRA EXTENT BYTE 'S2'. + ADD HL,DE + LD (HL),B + CALL OPENIT ; TRY AND GET THIS EXTENT. + LD A,(STATUS) ; WAS IT THERE? + INC A + JP NZ,POSITN3 + POP BC ; NO. CAN WE CREATE A NEW ONE (WRITING?). + PUSH BC + LD L,#4 ; PREPARE FOR ERROR. + INC C + JP Z,POSITN4 ; NOPE, READING UNWRITTEN SPACE ERROR. + CALL GETEMPTY ; YES WE CAN, TRY TO FIND SPACE. + LD L,#5 ; PREPARE FOR ERROR. + LD A,(STATUS) + INC A + JP Z,POSITN4 ; OUT OF SPACE? +; +; NORMAL RETURN LOCATION. CLEAR ERROR CODE AND RETURN. +; +POSITN3:POP BC ; RESTORE STACK. + XOR A ; AND CLEAR ERROR CODE BYTE. + JP SETSTAT +; +; ERROR. SET THE 'S2' BYTE TO INDICATE THIS (WHY?). +; +POSITN4:PUSH HL + CALL GETS2 + LD (HL),#0x0C0 + POP HL +; +; RETURN WITH ERROR CODE (PRESENTLY IN L). +; +POSITN5:POP BC + LD A,L ; GET ERROR CODE. + LD (STATUS),A + JP SETS2B7 +; +; READ A RANDOM RECORD. +; +READRAN:LD C,#0x0FF ; SET 'READ' STATUS. + CALL POSITION ; POSITION THE FILE TO PROPER RECORD. + CALL Z,RDSEQ1 ; AND READ IT AS USUAL (IF NO ERRORS). + RET +; +; WRITE TO A RANDOM RECORD. +; +WRITERAN: + LD C,#0 ; SET 'WRITING' FLAG. + CALL POSITION ; POSITION THE FILE TO PROPER RECORD. + CALL Z,WTSEQ1 ; AND WRITE AS USUAL (IF NO ERRORS). + RET +; +; COMPUTE THE RANDOM RECORD NUMBER. ENTER WITH (HL) POINTING +; TO A FCB AN (DE) CONTAINS A RELATIVE LOCATION OF A RECORD +; NUMBER. ON EXIT, (C) CONTAINS THE 'R0' BYTE, (B) THE 'R1' +; BYTE, AND (A) THE 'R2' BYTE. +; +; ON RETURN, THE ZERO FLAG IS SET IF THE RECORD IS WITHIN +; BOUNDS. OTHERWISE, AN OVERFLOW OCCURED. +; +COMPRAND: + EX DE,HL ; SAVE FCB POINTER IN (DE). + ADD HL,DE ; COMPUTE RELATIVE POSITION OF RECORD #. + LD C,(HL) ; GET RECORD NUMBER INTO (BC). + LD B,#0 + LD HL,#12 ; NOW GET EXTENT. + ADD HL,DE + LD A,(HL) ; COMPUTE (BC)=(RECORD #)+(EXTENT)*128. + RRCA ; MOVE LOWER BIT INTO BIT 7. + AND #0x80 ; AND IGNORE ALL OTHER BITS. + ADD A,C ; ADD TO OUR RECORD NUMBER. + LD C,A + LD A,#0 ; TAKE CARE OF ANY CARRY. + ADC A,B + LD B,A + LD A,(HL) ; NOW GET THE UPPER BITS OF EXTENT INTO + RRCA ; BIT POSITIONS 0-3. + AND #0x0F ; AND IGNORE ALL OTHERS. + ADD A,B ; ADD THIS IN TO 'R1' BYTE. + LD B,A + LD HL,#14 ; GET THE 'S2' BYTE (EXTRA EXTENT). + ADD HL,DE + LD A,(HL) + ADD A,A ; AND SHIFT IT LEFT 4 BITS (BITS 4-7). + ADD A,A + ADD A,A + ADD A,A + PUSH AF ; SAVE CARRY FLAG (BIT 0 OF FLAG BYTE). + ADD A,B ; NOW ADD EXTRA EXTENT INTO 'R1'. + LD B,A + PUSH AF ; AND SAVE CARRY (OVERFLOW BYTE 'R2'). + POP HL ; BIT 0 OF (L) IS THE OVERFLOW INDICATOR. + LD A,L + POP HL ; AND SAME FOR FIRST CARRY FLAG. + OR L ; EITHER ONE OF THESE SET? + AND #1 ; ONLY CHECK THE CARRY FLAGS. + RET +; +; ROUTINE TO SETUP THE FCB (BYTES 'R0', 'R1', 'R2') TO +; REFLECT THE LAST RECORD USED FOR A RANDOM (OR OTHER) FILE. +; THIS READS THE DIRECTORY AND LOOKS AT ALL EXTENTS COMPUTING +; THE LARGERST RECORD NUMBER FOR EACH AND KEEPING THE MAXIMUM +; VALUE ONLY. THEN 'R0', 'R1', AND 'R2' WILL REFLECT THIS +; MAXIMUM RECORD NUMBER. THIS IS USED TO COMPUTE THE SPACE USED +; BY A RANDOM FILE. +; +RANSIZE:LD C,#12 ; LOOK THRU DIRECTORY FOR FIRST ENTRY WITH + CALL FINDFST ; THIS NAME. + LD HL,(PARAMS) ; ZERO OUT THE 'R0, R1, R2' BYTES. + LD DE,#33 + ADD HL,DE + PUSH HL + LD (HL),D ; NOTE THAT (D)=0. + INC HL + LD (HL),D + INC HL + LD (HL),D +RANSIZ1:CALL CKFILPOS ; IS THERE AN EXTENT TO PROCESS? + JP Z,RANSIZ3 ; NO, WE ARE DONE. + CALL FCB2HL ; SET (HL) POINTING TO PROPER FCB IN DIR. + LD DE,#15 ; POINT TO LAST RECORD IN EXTENT. + CALL COMPRAND ; AND COMPUTE RANDOM PARAMETERS. + POP HL + PUSH HL ; NOW CHECK THESE VALUES AGAINST THOSE + LD E,A ; ALREADY IN FCB. + LD A,C ; THE CARRY FLAG WILL BE SET IF THOSE + SUB (HL) ; IN THE FCB REPRESENT A LARGER SIZE THAN + INC HL ; THIS EXTENT DOES. + LD A,B + SBC A,(HL) + INC HL + LD A,E + SBC A,(HL) + JP C,RANSIZ2 + LD (HL),E ; WE FOUND A LARGER (IN SIZE) EXTENT. + DEC HL ; STUFF THESE VALUES INTO FCB. + LD (HL),B + DEC HL + LD (HL),C +RANSIZ2:CALL FINDNXT ; NOW GET THE NEXT EXTENT. + JP RANSIZ1 ; CONTINUE TIL ALL DONE. +RANSIZ3:POP HL ; WE ARE DONE, RESTORE THE STACK AND + RET ; RETURN. +; +; FUNCTION TO RETURN THE RANDOM RECORD POSITION OF A GIVEN +; FILE WHICH HAS BEEN READ IN S.EQUENTIAL MODE UP TO NOW. +; +SETRAN: LD HL,(PARAMS) ; POINT TO FCB. + LD DE,#32 ; AND TO LAST USED RECORD. + CALL COMPRAND ; COMPUTE RANDOM POSITION. + LD HL,#33 ; NOW STUFF THESE VALUES INTO FCB. + ADD HL,DE + LD (HL),C ; MOVE 'R0'. + INC HL + LD (HL),B ; AND 'R1'. + INC HL + LD (HL),A ; AND LASTLY 'R2'. + RET +; +; THIS ROUTINE SELECT THE DRIVE SPECIFIED IN (ACTIVE) AND +; UPDATE THE LOGIN VECTOR AND BITMAP TABLE IF THIS DRIVE WAS +; NOT ALREADY ACTIVE. +; +LOGINDRV: + LD HL,(LOGIN) ; GET THE LOGIN VECTOR. + LD A,(ACTIVE) ; GET THE DEFAULT DRIVE. + LD C,A + CALL SHIFTR ; POSITION ACTIVE BIT FOR THIS DRIVE + PUSH HL ; INTO BIT 0. + EX DE,HL + CALL SELECT ; SELECT THIS DRIVE. + POP HL + CALL Z,SLCTERR ; VALID DRIVE? + LD A,L ; IS THIS A NEWLY ACTIVATED DRIVE? + RRA + RET C + LD HL,(LOGIN) ; YES, UPDATE THE LOGIN VECTOR. + LD C,L + LD B,H + CALL SETBIT + LD (LOGIN),HL ; AND SAVE. + JP BITMAP ; NOW UPDATE THE BITMAP. +; +; FUNCTION TO SET THE ACTIVE DISK NUMBER. +; +SETDSK: LD A,(EPARAM) ; GET PARAMETER PASSED AND SEE IF THIS + LD HL,#ACTIVE ; REPRESENTS A CHANGE IN DRIVES. + CP (HL) + RET Z + LD (HL),A ; YES IT DOES, LOG IT IN. + JP LOGINDRV +; +; THIS IS THE 'AUTO DISK SELECT' ROUTINE. THE FIRSST BYTE +; OF THE FCB IS EXAMINED FOR A DRIVE SPECIFICATION. IF NON +; ZERO THEN THE DRIVE WILL BE SELECTED AND LOGED IN. +; +AUTOSEL:LD A,#0x0FF ; SAY 'AUTO-SELECT ACTIVATED'. + LD (AUTO),A + LD HL,(PARAMS) ; GET DRIVE SPECIFIED. + LD A,(HL) + AND #0x1F ; LOOK AT LOWER 5 BITS. + DEC A ; ADJUST FOR (1=A, 2=B) ETC. + LD (EPARAM),A ; AND SAVE FOR THE SELECT ROUTINE. + CP #0x1E ; CHECK FOR 'NO CHANGE' CONDITION. + JP NC,AUTOSL1 ; YES, DON'T CHANGE. + LD A,(ACTIVE) ; WE MUST CHANGE, SAVE CURRENTLY ACTIVE + LD (OLDDRV),A ; DRIVE. + LD A,(HL) ; AND SAVE FIRST BYTE OF FCB ALSO. + LD (AUTOFLAG),A ; THIS MUST BE NON-ZERO. + AND #0x0E0 ; WHATS THIS FOR (BITS 6,7 ARE USED FOR + LD (HL),A ; SOMETHING)? + CALL SETDSK ; SELECT AND LOG IN THIS DRIVE. +AUTOSL1:LD A,(USERNO) ; MOVE USER NUMBER INTO FCB. + LD HL,(PARAMS) ; (* UPPER HALF OF FIRST BYTE *) + OR (HL) + LD (HL),A + RET ; AND RETURN (ALL DONE). +; +; FUNCTION TO RETURN THE CURRENT CP/M VERSION NUMBER. +; +GETVER: LD A,#0x022 ; VERSION 2.2 + JP SETSTAT +; +; FUNCTION TO RESET THE DISK SYSTEM. +; +RSTDSK: LD HL,#0 ; CLEAR WRITE PROTECT STATUS AND LOG + LD (WRTPRT),HL ; IN VECTOR. + LD (LOGIN),HL + XOR A ; SELECT DRIVE 'A'. + LD (ACTIVE),A + LD HL,#TBUFF ; SETUP DEFAULT DMA ADDRESS. + LD (USERDMA),HL + CALL DEFDMA + JP LOGINDRV ; NOW LOG IN DRIVE 'A'. +; +; FUNCTION TO OPEN A SPECIFIED FILE. +; +OPENFIL:CALL CLEARS2 ; CLEAR 'S2' BYTE. + CALL AUTOSEL ; SELECT PROPER DISK. + JP OPENIT ; AND OPEN THE FILE. +; +; FUNCTION TO CLOSE A SPECIFIED FILE. +; +CLOSEFIL: + CALL AUTOSEL ; SELECT PROPER DISK. + JP CLOSEIT ; AND CLOSE THE FILE. +; +; FUNCTION TO RETURN THE FIRST OCCURENCE OF A SPECIFIED FILE +; NAME. IF THE FIRST BYTE OF THE FCB IS '?' THEN THE NAME WILL +; NOT BE CHECKED (GET THE FIRST ENTRY NO MATTER WHAT). +; +GETFST: LD C,#0 ; PREPARE FOR SPECIAL SEARCH. + EX DE,HL + LD A,(HL) ; IS FIRST BYTE A '?'? + CP #QUESTION + JP Z,GETFST1 ; YES, JUST GET VERY FIRST ENTRY (ZERO LENGTH MATCH). + CALL SETEXT ; GET THE EXTENSION BYTE FROM FCB. + LD A,(HL) ; IS IT '?'? IF YES, THEN WE WANT + CP #QUESTION ; AN ENTRY WITH A SPECIFIC 'S2' BYTE. + CALL NZ,CLEARS2 ; OTHERWISE, LOOK FOR A ZERO 'S2' BYTE. + CALL AUTOSEL ; SELECT PROPER DRIVE. + LD C,#15 ; COMPARE BYTES 0-14 IN FCB (12&13 EXCLUDED). +GETFST1:CALL FINDFST ; FIND AN ENTRY AND THEN MOVE IT INTO + JP MOVEDIR ; THE USERS DMA SPACE. +; +; FUNCTION TO RETURN THE NEXT OCCURENCE OF A FILE NAME. +; +GETNXT: LD HL,(SAVEFCB) ; RESTORE POINTERS. NOTE THAT NO + LD (PARAMS),HL ; OTHER .DBOS CALLS ARE ALLOWED. + CALL AUTOSEL ; NO ERROR WILL BE RETURNED, BUT THE + CALL FINDNXT ; RESULTS WILL BE WRONG. + JP MOVEDIR +; +; FUNCTION TO DELETE A FILE BY NAME. +; +DELFILE:CALL AUTOSEL ; SELECT PROPER DRIVE. + CALL ERAFILE ; ERASE THE FILE. + JP STSTATUS ; SET STATUS AND RETURN. +; +; FUNCTION TO EXECUTE A S.EQUENTIAL READ OF THE SPECIFIED +; RECORD NUMBER. +; +READSEQ:CALL AUTOSEL ; SELECT PROPER DRIVE THEN READ. + JP RDSEQ +; +; FUNCTION TO WRITE THE NET S.EQUENTIAL RECORD. +; +WRTSEQ: CALL AUTOSEL ; SELECT PROPER DRIVE THEN WRITE. + JP WTSEQ +; +; CREATE A FILE FUNCTION. +; +FCREATE:CALL CLEARS2 ; CLEAR THE 'S2' BYTE ON ALL CREATES. + CALL AUTOSEL ; SELECT PROPER DRIVE AND GET THE NEXT + JP GETEMPTY ; EMPTY DIRECTORY SPACE. +; +; FUNCTION TO RENAME A FILE. +; +RENFILE:CALL AUTOSEL ; SELECT PROPER DRIVE AND THEN SWITCH + CALL CHGNAMES ; FILE NAMES. + JP STSTATUS +; +; FUNCTION TO RETURN THE LOGIN VECTOR. +; +GETLOG: LD HL,(LOGIN) + JP GETPRM1 +; +; FUNCTION TO RETURN THE CURRENT DISK ASSIGNMENT. +; +GETCRNT:LD A,(ACTIVE) + JP SETSTAT +; +; FUNCTION TO SET THE DMA ADDRESS. +; +PUTDMA: EX DE,HL + LD (USERDMA),HL ; SAVE IN OUR SPACE AND THEN GET TO + JP DEFDMA ; THE BIOS WITH THIS ALSO. +; +; FUNCTION TO RETURN THE ALLOCATION VECTOR. +; +GETALOC:LD HL,(ALOCVECT) + JP GETPRM1 +; +; FUNCTION TO RETURN THE READ-ONLY STATUS VECTOR. +; +GETROV: LD HL,(WRTPRT) + JP GETPRM1 +; +; FUNCTION TO SET THE FILE ATTRIBUTES (READ-ONLY, SYSTEM). +; +SETATTR:CALL AUTOSEL ; SELECT PROPER DRIVE THEN SAVE ATTRIBUTES. + CALL SAVEATTR + JP STSTATUS +; +; FUNCTION TO RETURN THE ADDRESS OF THE DISK PARAMETER BLOCK +; FOR THE CURRENT DRIVE. +; +GETPARM:LD HL,(DISKPB) +GETPRM1:LD (STATUS),HL + RET +; +; FUNCTION TO GET OR SET THE USER NUMBER. IF (E) WAS (FF) +; THEN THIS IS A R.EQUEST TO RETURN THE CURRENT USER NUMBER. +; ELSE SET THE USER NUMBER FROM (E). +; +GETUSER:LD A,(EPARAM) ; GET PARAMETER. + CP #0x0FF ; GET USER NUMBER? + JP NZ,SETUSER + LD A,(USERNO) ; YES, JUST DO IT. + JP SETSTAT +SETUSER:AND #0x1F ; NO, WE SHOULD SET IT INSTEAD. KEEP LOW + LD (USERNO),A ; BITS (0-4) ONLY. + RET +; +; FUNCTION TO READ A RANDOM RECORD FROM A FILE. +; +RDRANDOM: + CALL AUTOSEL ; SELECT PROPER DRIVE AND READ. + JP READRAN +; +; FUNCTION TO COMPUTE THE FILE SIZE FOR RANDOM FILES. +; +WTRANDOM: + CALL AUTOSEL ; SELECT PROPER DRIVE AND WRITE. + JP WRITERAN +; +; FUNCTION TO COMPUTE THE SIZE OF A RANDOM FILE. +; +FILESIZE: + CALL AUTOSEL ; SELECT PROPER DRIVE AND CHECK FILE LENGTH + JP RANSIZE +; +; FUNCTION #37. THIS ALLOWS A PROGRAM TO LOG OFF ANY DRIVES. +; ON ENTRY, SET (DE) TO CONTAIN A WORD WITH BITS SET FOR THOSE +; DRIVES THAT ARE TO BE LOGGED OFF. THE LOG-IN VECTOR AND THE +; WRITE PROTECT VECTOR WILL BE UPDATED. THIS MUST BE A M/PM +; SPECIAL FUNCTION. +; +LOGOFF: LD HL,(PARAMS) ; GET DRIVES TO LOG OFF. + LD A,L ; FOR EACH BIT THAT IS SET, WE WANT + CPL ; TO CLEAR THAT BIT IN (LOGIN) + LD E,A ; AND (WRTPRT). + LD A,H + CPL + LD HL,(LOGIN) ; RESET THE LOGIN VECTOR. + AND H + LD D,A + LD A,L + AND E + LD E,A + LD HL,(WRTPRT) + EX DE,HL + LD (LOGIN),HL ; AND SAVE. + LD A,L ; NOW DO THE WRITE PROTECT VECTOR. + AND E + LD L,A + LD A,H + AND D + LD H,A + LD (WRTPRT),HL ; AND SAVE. ALL DONE. + RET +; +; GET HERE TO RETURN TO THE USER. +; +GOBACK: LD A,(AUTO) ; WAS AUTO SELECT ACTIVATED? + OR A + JP Z,GOBACK1 + LD HL,(PARAMS) ; YES, BUT WAS A CHANGE MADE? + LD (HL),#0 ; (* RESET FIRST BYTE OF FCB *) + LD A,(AUTOFLAG) + OR A + JP Z,GOBACK1 + LD (HL),A ; YES, RESET FIRST BYTE PROPERLY. + LD A,(OLDDRV) ; AND GET THE OLD DRIVE AND SELECT IT. + LD (EPARAM),A + CALL SETDSK +GOBACK1:LD HL,(USRSTACK) ; RESET THE USERS STACK POINTER. + LD SP,HL + LD HL,(STATUS) ; GET RETURN STATUS. + LD A,L ; FORCE VERSION 1.4 COMPATABILITY. + LD B,H + RET ; AND GO BACK TO USER. +; +; FUNCTION #40. THIS IS A SPECIAL ENTRY TO DO RANDOM I/O. +; FOR THE CASE WHERE WE ARE WRITING TO UNUSED DISK SPACE, THIS +; SPACE WILL BE ZEROED OUT FIRST. THIS MUST BE A M/PM SPECIAL +; PURPOSE FUNCTION, BECAUSE WHY WOULD ANY NORMAL PROGRAM EVEN +; CARE ABOUT THE PREVIOUS CONTENTS OF A SECTOR ABOUT TO BE +; WRITTEN OVER. +; +WTSPECL:CALL AUTOSEL ; SELECT PROPER DRIVE. + LD A,#2 ; USE SPECIAL WRITE MODE. + LD (MODE),A + LD C,#0 ; SET WRITE INDICATOR. + CALL POSITN1 ; POSITION THE FILE. + CALL Z,WTSEQ1 ; AND WRITE (IF NO ERRORS). + RET +; +;************************************************************** +;* +;* BDOS DATA STORAGE POOL. +;* +;************************************************************** +; +EMPTYFCB: + .DB 0x0E5 ; EMPTY DIRECTORY SEGMENT INDICATOR. +WRTPRT: .DW 0 ; WRITE PROTECT STATUS FOR ALL 16 DRIVES. +LOGIN: .DW 0 ; DRIVE ACTIVE WORD (1 BIT PER DRIVE). +USERDMA:.DW 0x80 ; USER'S DMA ADDRESS (DEFAULTS TO 80H). +; +; SCRATCH AREAS FROM PARAMETER BLOCK. +; +SCRATCH1: + .DW 0 ; RELATIVE POSITION WITHIN DIR SEGMENT FOR FILE (0-3). +SCRATCH2: + .DW 0 ; LAST SELECTED TRACK NUMBER. +SCRATCH3: + .DW 0 ; LAST SELECTED SECTOR NUMBER. +; +; DISK STORAGE AREAS FROM PARAMETER BLOCK. +; +DIRBUF: .DW 0 ; ADDRESS OF DIRECTORY BUFFER TO USE. +DISKPB: .DW 0 ; CONTAINS ADDRESS OF DISK PARAMETER BLOCK. +CHKVECT:.DW 0 ; ADDRESS OF CHECK VECTOR. +ALOCVECT: + .DW 0 ; ADDRESS OF ALLOCATION VECTOR (BIT MAP). +; +; PARAMETER BLOCK RETURNED FROM THE BIOS. +; +SECTORS:.DW 0 ; SECTORS PER TRACK FROM BIOS. +BLKSHFT:.DB 0 ; BLOCK SHIFT. +BLKMASK:.DB 0 ; BLOCK MASK. +EXTMASK:.DB 0 ; EXTENT MASK. +DSKSIZE:.DW 0 ; DISK SIZE FROM BIOS (NUMBER OF BLOCKS-1). +DIRSIZE:.DW 0 ; DIRECTORY SIZE. +ALLOC0: .DW 0 ; STORAGE FOR FIRST BYTES OF BIT MAP (DIR SPACE USED). +ALLOC1: .DW 0 +OFFSET: .DW 0 ; FIRST USABLE TRACK NUMBER. +XLATE: .DW 0 ; SECTOR TRANSLATION TABLE ADDRESS. +; +; +CLOSEFLG: + .DB 0 ; CLOSE FLAG (=0FFH IS EXTENT WRITTEN OK). +R.DWRTFLG: + .DB 0 ; READ/WRITE FLAG (0FFH=READ, 0=WRITE). +FNDSTAT:.DB 0 ; FILENAME FOUND STATUS (0=FOUND FIRST ENTRY). +MODE: .DB 0 ; I/O MODE SELECT (0=RANDOM, 1=S.EQUENTIAL, 2=SPECIAL RANDOM). +EPARAM: .DB 0 ; STORAGE FOR REGISTER (E) ON ENTRY TO BDOS. +RELBLOCK: + .DB 0 ; RELATIVE POSITION WITHIN FCB OF BLOCK NUMBER WRITTEN. +COUNTER:.DB 0 ; BYTE COUNTER FOR DIRECTORY NAME SEARCHES. +SAVEFCB:.DW 0,0 ; SAVE SPACE FOR ADDRESS OF FCB (FOR DIRECTORY SEARCHES). +BIGDISK:.DB 0 ; IF =0 THEN DISK IS > 256 BLOCKS LONG. +AUTO: .DB 0 ; IF NON-ZERO, THEN AUTO SELECT ACTIVATED. +OLDDRV: .DB 0 ; ON AUTO SELECT, STORAGE FOR PREVIOUS DRIVE. +AUTOFLAG: + .DB 0 ; IF NON-ZERO, THEN AUTO SELECT CHANGED DRIVES. +SAVNXT: .DB 0 ; STORAGE FOR NEXT RECORD NUMBER TO ACCESS. +SAVEXT: .DB 0 ; STORAGE FOR EXTENT NUMBER OF FILE. +SAVNREC:.DW 0 ; STORAGE FOR NUMBER OF RECORDS IN FILE. +BLKNMBR:.DW 0 ; BLOCK NUMBER (PHYSICAL SECTOR) USED WITHIN A FILE OR LOGICAL SEC +LOGSECT:.DW 0 ; STARTING LOGICAL (128 BYTE) SECTOR OF BLOCK (PHYSICAL SECTOR). +FCBPOS: .DB 0 ; RELATIVE POSITION WITHIN BUFFER FOR FCB OF FILE OF INTEREST. +FILEPOS:.DW 0 ; FILES POSITION WITHIN DIRECTORY (0 TO MAX ENTRIES -1). +; +; DISK DIRECTORY BUFFER CHECKSUM BYTES. ONE FOR EACH OF THE +; 16 POSSIBLE DRIVES. +; +CKSUMTBL: + .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +; +;************************************************************** +;* +;* B I O S J U M P T A B L E +;* +;************************************************************** +; + +BIOS = BIOSO ;BIOS ORIGIN +; +BOOT = BIOS ;(BOOT) Cold boot entry +WBOOT = BIOS+3 ;Warm boot entry +CONST = BIOS+6 ;Console status +CONIN = BIOS+9 ;Console char in +CONOUT = BIOS+12 ;Console char out +LIST = BIOS+15 ;List char out +PUNCH = BIOS+18 ;Punch char out +READER = BIOS+21 ;Reader char in +HOME = BIOS+24 ;Home disk +SELDSK = BIOS+27 ;Select disk +SETTRK = BIOS+30 ;Set disk track addr +SETSEC = BIOS+33 ;Set disk sector addr +SETDMA = BIOS+36 ;Set DMA buffer addr +READ = BIOS+39 ;Read sector +WRITE = BIOS+42 ;Write sector +SECTRN = BIOS+48 ;Sector translation routine +; +;dwg; .IF ENDFIL +;dwg; .ORG BDOSO+0DFFH +;dwg; .DB 55H +;dwg; .ENDIF + +;dwg; .END + +_bdos_end:: + .area _CODE + .area _CABS diff --git a/doug/src/bdosb01.sym b/doug/src/bdosb01.sym new file mode 100755 index 00000000..21a81a34 --- /dev/null +++ b/doug/src/bdosb01.sym @@ -0,0 +1,136 @@ + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 1. +bdosb01.s derived from bdosb01.asm +Symbol Table + + .__.ABS.= 0000 G | 6 ACTIVE 0342 R | 6 ADDA2HL 0564 R + 6 ALLOC0 0DCA R | 6 ALLOC1 0DCC R | 6 ALOCVECT 0DBF R + ASCIIA = 0041 | AT = 0040 | 6 AUTO 0DDE R + 6 AUTOFLAG 0DE0 R | 6 AUTOSEL 0C51 R | 6 AUTOSL1 0C75 R + 6 BACKUP 01A4 R | 6 BACKUP1 01AC R | 6 BADSCTR 0009 R + 6 BADSEC 00CA R | 6 BADSEL 00D5 R | 6 BADSLCT 000B R + BASE = 9C00 | 6 BDOSDRV 00C6 R | 6 BDOSERR 00BA R + BDOSO = D800 | 6 BIGDISK 0DDD R | BIOS = E600 + BIOSO = E600 | 6 BITMAP 06A3 R | 6 BITMAP1 06B1 R + 6 BITMAP2 06D2 R | 6 BITMAP3 06F6 R | 6 BLKMASK 0DC4 R + 6 BLKNMBR 0DE5 R | 6 BLKSHFT 0DC3 R | BOOT = E600 + BS = 0008 | CCPO = D000 | 6 CHARBUF 030E R + 6 CHECKDIR 059E R | 6 CHECKSUM 04F7 R | 6 CHGNAM1 0827 R + 6 CHGNAMES 0816 R | 6 CHKBLK 0484 R | 6 CHKCHAR 0114 R + 6 CHKDIR1 05C4 R | 6 CHKNMBR 058C R | 6 CHKROFL 0544 R + 6 CHKSUM1 04FD R | 6 CHKVECT 0DBD R | 6 CHKWPRT 0554 R + 6 CKBITMAP 0635 R | 6 CKBMAP1 0656 R | 6 CKCON1 0142 R + 6 CKCON2 0145 R | 6 CKCONSOL 0123 R | 6 CKFILPOS 05F5 R + 6 CKROF1 0547 R | 6 CKSUMTBL 0DEC R | 6 CLEARS2 0572 R + 6 CLOSEFIL 0CA5 R | 6 CLOSEFLG 0DD2 R | 6 CLOSEIT 08A2 R + 6 CLOSEIT1 08CD R | 6 CLOSEIT2 08DB R | 6 CLOSEIT3 08E1 R + 6 CLOSEIT4 08E8 R | 6 CLOSEIT5 08FD R | 6 CLOSEIT6 0917 R + 6 CLOSEIT7 091F R | CNTRLC = 0003 | CNTRLE = 0005 + CNTRLP = 0010 | CNTRLR = 0012 | CNTRLS = 0013 + CNTRLU = 0015 | CNTRLX = 0018 | CNTRLZ = 001A + 6 COMBLK 0477 R | 6 COMPRAND 0BA5 R | CONIN = E609 + CONOUT = E60C | CONST = E606 | 6 COUNTER 0DD8 R + CR = 000D | 6 CURPOS 030C R | 6 DE2HL 034F R + 6 DE2HL1 0350 R | 6 DEFDMA 05DA R | DEL = 007F + 6 DELFILE 0CD7 R | 6 DIRBUF 0DB9 R | 6 DIRC1 02E0 R + 6 DIRCIO 02D4 R | 6 DIRDMA 05E0 R | 6 DIRDMA1 05E3 R + 6 DIRREAD 05D4 R | 6 DIRSIZE 0DC8 R | 6 DIRWRITE 05C6 R + 6 DISKPB 0DBB R | 6 DISKRO 00E1 R | DOLLAR = 0024 + 6 DOREAD 03B2 R | 6 DOWRITE 03B8 R | 6 DSKSIZE 0DC6 R + 6 EMPTYFCB 0DAC R | ENDFIL = 0001 | ENTRY = 0005 + 6 EPARAM 0DD6 R | 6 ERAFIL1 07A4 R | 6 ERAFILE 079C R + 6 ERROR1 0099 R | 6 ERROR2 00A5 R | 6 ERROR3 00AB R + 6 ERROR4 00B1 R | 6 ERROR5 00B4 R | 6 EXTBLK 045E R + 6 EXTBLK1 0471 R | 6 EXTMASK 0DC5 R | 6 FBASE 0006 R + 6 FBASE1 0011 R | 6 FCB2HL 055E R | 6 FCBPOS 0DE9 R + 6 FCBSET 07FD R | 6 FCREATE 0CEC R | FF = 000C + 6 FILEPOS 0DEA R | 6 FILERO 00DC R | 6 FILESIZE 0D4D R + 6 FINDFST 0718 R | 6 FINDNXT 072D R | 6 FNDNXT1 074A R + 6 FNDNXT2 0753 R | 6 FNDNXT3 0773 R | 6 FNDNXT4 077C R + 6 FNDNXT5 0783 R | 6 FNDNXT6 0794 R | 6 FNDSPA1 07C0 R + 6 FNDSPA2 07D1 R | 6 FNDSPA3 07EC R | 6 FNDSPA4 07F4 R + 6 FNDSPACE 07BE R | 6 FNDSTAT 0DD4 R | 6 FUNCTNS 0047 R + 6 GETALOC 0D11 R | 6 GETBLK1 0445 R | 6 GETBLK2 0453 R + 6 GETBLK3 045C R | 6 GETBLOCK 043E R | 6 GETCHAR 00FB R + 6 GETCON 02C8 R | 6 GETCRNT 0D04 R | 6 GETCSTS 02FE R + 6 GETECHO 0106 R | 6 GETEMPTY 0924 R | 6 GETFST 0CAB R + 6 GETFST1 0CC2 R | 6 GETIOB 02ED R | 6 GETLOG 0CFE R + 6 GETMT1 0946 R | 6 GETNEXT 095A R | 6 GETNXT 0CC8 R + 6 GETPARM 0D26 R | 6 GETPRM1 0D29 R | 6 GETRDR 02CE R + 6 GETROV 0D17 R | 6 GETS2 0569 R | 6 GETUSER 0D2D R + 6 GETVER 0C7E R | 6 GETWPRT 051E R | 6 GOBACK 0D74 R + 6 GOBACK1 0D91 R | 6 GTNEXT1 0983 R | 6 GTNEXT2 098E R + 6 GTNEXT3 09AC R | 6 GTNEXT4 09AF R | 6 GTNEXT5 09B6 R + HOME = E618 | 6 HOMEDRV 03A1 R | IOBYTE = 0003 + 6 IOERR1 0305 R | 6 IORET 03BB R | 6 JUMPHL 034A R + LF = 000A | LIST = E60F | 6 LOGICAL 048A R + 6 LOGICL1 0490 R | 6 LOGIN 0DAF R | 6 LOGINDRV 0C21 R + 6 LOGOFF 0D53 R | 6 LOGSECT 0DE7 R | 6 MODE 0DD5 R + 6 MOREFLS 057F R | 6 MOVEDIR 05E9 R | 6 MOVEWORD 0894 R + 6 NEWLINE 01B1 R | 6 NEWLN1 01B9 R | NFUNCTS = 0029 + NK = 003B | 6 NXENT1 0619 R | 6 NXENT2 0620 R + 6 NXENTRY 0605 R | 6 OFFSET 0DCE R | 6 OLDDRV 0DDF R + 6 OPENFIL 0C9C R | 6 OPENIT 0851 R | 6 OPENIT1 085A R + 6 OPENIT2 088B R | 6 OUTCHAR 0148 R | 6 OUTCHR1 0162 R + 6 OUTCHR2 0179 R | 6 OUTCON 0190 R | 6 OUTCON1 0196 R + 6 OUTCRLF 01C9 R | 6 OUTFLAG 030A R | 6 PARAMS 0343 R + 6 POSITION 0B03 R | 6 POSITN1 0B07 R | 6 POSITN2 0B47 R + 6 POSITN3 0B7F R | 6 POSITN4 0B84 R | 6 POSITN5 0B8B R + POUND = 0023 | 6 PRTERR 00E5 R | 6 PRTFLAG 030D R + 6 PRTMESG 01D3 R | 6 PRTSTR 02F8 R | PUNCH = E612 + 6 PUTDMA 0D0A R | QUESTION= 003F | 6 R.DBUF1 01EF R + 6 R.DBUF10 0270 R | 6 R.DBUF11 0278 R | 6 R.DBUF12 028A R + 6 R.DBUF13 0299 R | 6 R.DBUF14 02A6 R | 6 R.DBUF15 02A9 R + 6 R.DBUF16 02BD R | 6 R.DBUF17 02C1 R | 6 R.DBUF2 01F1 R + 6 R.DBUF3 0216 R | 6 R.DBUF4 0226 R | 6 R.DBUF5 0237 R + 6 R.DBUF6 0248 R | 6 R.DBUF7 024E R | 6 R.DBUF8 025F R + 6 R.DBUF9 026B R | 6 R.DBUFF 01E1 R | 6 R.DWRTFL 0DD3 R + 6 RANSIZ1 0BE4 R | 6 RANSIZ2 0C06 R | 6 RANSIZ3 0C0C R + 6 RANSIZE 0BD2 R | 6 RDRANDOM 0D41 R | 6 RDSEQ 09BC R + 6 RDSEQ1 09C1 R | 6 RDSEQ2 09E6 R | 6 RDSEQ3 09FB R + READ = E627 | READER = E615 | 6 READRAN 0B93 R + 6 READSEQ 0CE0 R | 6 RELBLOCK 0DD7 R | 6 RENFILE 0CF5 R + 6 RODISK 000D R | 6 ROFILE 000F R | 6 RSTDSK 0C83 R + 6 RTN 0304 R | 6 SAMEXT 0707 R | 6 SAVATR1 0840 R + 6 SAVEATTR 083B R | 6 SAVEFCB 0DD9 R | 6 SAVEXT 0DE2 R + 6 SAVNREC 0DE3 R | 6 SAVNXT 0DE1 R | 6 SCRATCH1 0DB3 R + 6 SCRATCH2 0DB5 R | 6 SCRATCH3 0DB7 R | 6 SECTORS 0DC1 R + SECTRN = E630 | SELDSK = E61B | 6 SELECT 0359 R + 6 SELECT1 039D R | 6 SETATTR 0D1D R | 6 SETBIT 050B R + 6 SETDIR 059C R | SETDMA = E624 | 6 SETDSK 0C45 R + 6 SETEXT 04A6 R | 6 SETFILE 066B R | 6 SETFL1 0675 R + 6 SETFL2 0688 R | 6 SETFL3 068E R | 6 SETFL4 069D R + 6 SETHLDE 04AE R | 6 SETIOB 02F3 R | 6 SETNREC 04D2 R + 6 SETRAN 0C0E R | 6 SETS2B7 0578 R | SETSEC = E621 + 6 SETSTAT 0301 R | SETTRK = E61E | 6 SETUSER 0D3B R + 6 SHIFTL 0504 R | 6 SHIFTL1 0505 R | 6 SHIFTR 04EA R + 6 SHIFTR1 04EB R | 6 SHOWIT 017F R | 6 SLCTERR 0347 R + SPACE = 0020 | 6 STARTING 030B R | 6 STATUS 0345 R + 6 STBITMAP 065C R | 6 STBMAP1 0664 R | 6 STFILPOS 05FE R + 6 STKAREA 0341 R | 6 STNREC1 04DE R | 6 STRDATA 04BB R + 6 STSTATUS 0701 R | 6 SUBHL 0595 R | TAB = 0009 + TBASE = 0100 | TBUFF = 0080 | TDRIVE = 0004 + TFCB = 005C | 6 TRKSEC 03C3 R | 6 TRKSEC1 03D1 R + 6 TRKSEC2 03E4 R | 6 TRKSEC3 03FA R | 6 TRKSEC4 040F R + UP = 005E | 6 UPDATE 0801 R | 6 UPDATE1 0810 R + 6 USERDMA 0DB1 R | 6 USERNO 0341 R | 6 USRSTACK 030F R + WBOOT = E603 | WRITE = E62A | 6 WRITERAN 0B9C R + 6 WRTPRT 0DAD R | 6 WRTPRTD 052C R | 6 WRTSEQ 0CE6 R + 6 WTRANDOM 0D47 R | 6 WTSEQ 09FE R | 6 WTSEQ1 0A03 R + 6 WTSEQ10 0AD2 R | 6 WTSEQ11 0AFE R | 6 WTSEQ12 0B00 R + 6 WTSEQ2 0A3B R | 6 WTSEQ3 0A48 R | 6 WTSEQ4 0A64 R + 6 WTSEQ5 0A6C R | 6 WTSEQ6 0A6E R | 6 WTSEQ7 0A8C R + 6 WTSEQ8 0A9A R | 6 WTSEQ9 0ABB R | 6 WTSEQ99 0ADF R + 6 WTSPECL 0D9B R | 6 XLATE 0DD0 R | 0 _bdos 0000 GR + 6 _bdos_en 0DFC GR | 0 _bdos_st 0000 GR + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 2. +bdosb01.s derived from bdosb01.asm +Area Table + + 0 _CODE size 0 flags 0 + 1 _DATA size 0 flags 0 + 2 _OVERLAY size 0 flags 0 + 3 _HOME size 0 flags 0 + 4 _GSINIT size 0 flags 0 + 5 _GSFINAL size 0 flags 0 + 6 _BDOSB01 size DFC flags 0 + 7 _CABS size 0 flags 0 diff --git a/doug/src/cbios.lst b/doug/src/cbios.lst new file mode 100755 index 00000000..869b7cfe --- /dev/null +++ b/doug/src/cbios.lst @@ -0,0 +1,2750 @@ + 1 .title cbios.s derived from cbios.asm + 2 .sbttl by Douglas Goodall for N8VEM use '11 + 3 + 4 .module cbios + 5 .optsdcc -mz80 + 6 + 7 ;-------------------------------------------------------- + 8 ; Public variables in this module + 9 ;-------------------------------------------------------- + 10 .globl _cbios + 11 ;-------------------------------------------------------- + 12 ; special function registers + 13 ;-------------------------------------------------------- + 14 ;-------------------------------------------------------- + 15 ; ram data + 16 ;-------------------------------------------------------- + 17 .area _DATA + 18 ;-------------------------------------------------------- + 19 ; overlayable items in ram + 20 ;-------------------------------------------------------- + 21 .area _OVERLAY + 22 ;-------------------------------------------------------- + 23 ; external initialized ram data + 24 ;-------------------------------------------------------- + 25 ;-------------------------------------------------------- + 26 ; global & static initialisations + 27 ;-------------------------------------------------------- + 28 .area _HOME + 29 .area _GSINIT + 30 .area _GSFINAL + 31 .area _GSINIT + 32 ;-------------------------------------------------------- + 33 ; Home + 34 ;-------------------------------------------------------- + 35 .area _HOME + 36 .area _HOME + 37 ;-------------------------------------------------------- + 38 ; code + 39 ;-------------------------------------------------------- + 40 + 41 ; .area _CODE + 42 .area _CBIOS + 43 + 0000 44 _cbios_start:: + 0000 45 _cbios: + 46 + 47 ; CBIOS FOR N8VEM + 48 ; + 49 ; Supports: Floppy, IDE HDD, ATAPI ZIP, RAM & ROM DRIVES, on board 16550, DSKY & VDU CARD + 50 ; + 51 ; BY ANDREW LYNCH, WITH INPUT FROM MANY SOURCES + 52 ; + 53 ; DATA CONSTANTS + 54 ;__________________________________________________________________________________________________ + 0000 55 FALSE = 0 + 0001 56 TRUE = 1 + 57 + 58 ; LIST OF CONDITIONAL ASSEMBLY INSTRUCTIONS + 59 + 0001 60 CONDIDESOFT = TRUE ; IF NO IDE DRIVE, HAS A SIGNIFICANT DELAY ON SOFT BOOT (TRUE) OR QUICK (FALSE) + 0001 61 CONDSHORTMSG = TRUE ; TRUE FOR ORIGINAL WARM BOOT SIGNON, FALSE FOR SHORTER ONE WITH LESS + 0001 62 CONDSUPERSUB = TRUE ; TRUE FOR NO SUPERSUB AUTOEXEC, FALSE TO RUN SUPERSUB AUTOEXEC + 0001 63 CONDABONLY = TRUE ; TRUE FOR ORIGINAL, FALSE TO ONLY HAVE DRIVE A AND B + 64 + 0000 65 CONDUSEVDU = FALSE ; TRUE FOR USE VDU CARD, FALSE TO USE SERIAL PORT (FOR CONSOLE) + 0001 66 CONDUSEFLOPPY = TRUE ; TRUE FOR USE FLOPPY, FALSE FOR NO FLOPPY DRIVE + 0001 67 COND144FLOPPY = TRUE ; TRUE FOR 1.44Mb FLOPPY ON DRIVE G: + 0000 68 CONDUSEATAPI = FALSE ; TRUE FOR USE ZIP DISK, FALSE FOR NO ZIP DISK + 0000 69 CONDUSEDSKY = FALSE ; TRUE FOR USE DSKY, FALSE FOR NO DSKY + 70 + 71 ; POINTERS TO VDU ROUTINES IN HIGH ROM BANK (NOT NEEDED IF NOT USING VDU CARD) + 72 + 0100 73 VDU_INIT = 0x0100 ; VECTOR TO VDU INIT CODE + 0395 74 IS_KBHIT = 0x0395 ; VECTOR TO KB HIT CODE + 039C 75 GET_KEY = 0x039C ; VECTOR TO GET KEY CODE + 011B 76 CHARIN = 0x011B ; VECTOR TO CHARIN CODE + 0CD6 77 PR_OUTCHAR = 0x0CD6 ; VECTOR TO PRINTER CODE + 78 + 79 ; + 003B 80 MSIZE = 59 ;CP/M VERSION MEMORY SIZE IN KILOBYTES + 81 ; + 82 ; "BIAS" IS ADDRESS OFFSET FROM 3400H FOR MEMORY SYSTEMS + 83 ; THAN 16K (REFERRED TO AS "B" THROUGHOUT THE TEXT) + 84 ; + 9C00 85 BIAS = (MSIZE-20)*1024 ; + D000 86 CCP = 0x3400+BIAS ; BASE OF CCP + D806 87 BDOS = CCP+0x806 ; BASE OF BDOS + E600 88 BIOS = CCP+0x1600 ; BASE OF BIOS + 0004 89 CDISK = 4 ; CURRENT DISK NUMBER 0=A,...,15=P + 0003 90 IOBYTE = 3 ; I/O DEFINITION BYTE. + 91 + 00FF 92 END = 0x0FF + 000D 93 CR = 0x0D + 000A 94 LF = 0x0A + 95 + 96 ; TEST PROTOTYPE SPECIFIC HARDWARE IO PORT ADDRESSES AND MEMORY LOCATIONS + 97 + 0068 98 UART = 0x68 ; BASE IO ADDRESS OF UART + 0078 99 MPCL_RAM = 0x78 ; BASE IO ADDRESS OF RAM MEMORY PAGER CONFIGURATION LATCH + 007C 100 MPCL_ROM = 0x7C ; BASE IO ADDRESS OF ROM MEMORY PAGER CONFIGURATION LATCH + 101 + 0A00 102 ROMSTART_CPM= 0x00A00 ; WHERE THE CCP+BDOS+BIOS IS STORED IN ROM + D000 103 RAMTARG_CPM= 0x0D000 ; WHERE THE CCP+BDOS+BIOS STARTS IN RAM (ENTRY POINT) + 2BFF 104 MOVSIZ_CPM= 0x02BFF ; CCP, BDOS + 0800 105 CCPSIZ_CPM= 0x00800 ; CCP 0800h BYTES IN LENGTH + 106 + 107 ; IDE REGISTER IO PORT ; FUNCTION + 0020 108 IDELO = 0x20 ; DATA PORT (LOW BYTE) + 0021 109 IDEERR = 0x21 ; READ: ERROR REGISTER; WRITE: PRECOMP + 0022 110 IDESECTC = 0x22 ; SECTOR COUNT + 0023 111 IDESECTN = 0x23 ; SECTOR NUMBER + 0024 112 IDECYLLO = 0x24 ; CYLINDER LOW + 0025 113 IDECYLHI = 0x25 ; CYLINDER HIGH + 0026 114 IDEHEAD = 0x26 ; DRIVE/HEAD + 0027 115 IDESTTS = 0x27 ; READ: STATUS; WRITE: COMMAND + 0028 116 IDEHI = 0x28 ; DATA PORT (HIGH BYTE) + 002E 117 IDECTRL = 0x2E ; READ: ALTERNATIVE STATUS; WRITE; DEVICE CONTROL + 002F 118 IDEADDR = 0x2F ; DRIVE ADDRESS (READ ONLY) + 0036 119 FMSR = 0x36 ; ADDRESS OF MAIN STATUS REGISTER + 0037 120 FDATA = 0x37 ; FLOPPY DATA REGISTER + 003A 121 FLATCH = 0x3A ; FLOPPY CONFIGURATION LATCH + 003C 122 FDMA = 0x3C ; PSEUDO DMA ADDRESS + 123 ; + 124 ; FDC CONFIGURATION LATCH OUTPUT BIT PATTERNS + 0000 125 MOTOR = 0b00000000 ; BIT PATTERN IN LATCH FOR MOTOR CONTROL (ON) + 0001 126 TERMCN = 0b00000001 ; BIT PATTERN IN LATCH TO WRITE A TC STROBE + 0002 127 RESETL = 0b00000010 ; BIT PATTERN IN LATCH TO RESET ALL BITS + 0004 128 MINI = 0b00000100 ; BIT PATTERN IN LATCH TO SET MINI MODE FDC9229 LOW DENS=1, HIGH DENS=0 + 0020 129 PRECOMP = 0b00100000 ; BIT PATTERN IN LATCH TO SET WRITE PRECOMP 125 NS: + 0040 130 FDDENSITY = 0b01000000 ; BIT PATTERN IN LATCH TO FLOPPY LOW DENSITY (HIGH IS 0) + 0080 131 FDREADY = 0b10000000 ; BIT PATTERN IN LATCH TO FLOPPY READY (P-34): + 132 ; + 133 ; PIO 82C55 I/O IS DECODED TO PORT 60-67 + 0060 134 PORTA = 0x60 ; PORT A + 0061 135 PORTB = 0x61 ; PORT B + 0062 136 PORTC = 0x62 ; PORT C + 0063 137 PIOCONT = 0x63 ; PIO CONTROL PORT + 138 + 139 + 140 ;dwg; .ORG BIOS + 141 + 142 ;__________________________________________________________________________________________________ + 143 ; + 144 ; CP/M JUMP VECTOR TABLE FOR INDIVIDUAL SUBROUTINES + 145 ;__________________________________________________________________________________________________ + 146 ; + 0000 C3r1Bs01 147 JP BOOT ; COLD START + 0003 C3r46s01 148 WBOOTE: JP WBOOT ; WARM START + 0006 C3r9Cs01 149 JP CONST ; CONSOLE STATUS + 0009 C3rA6s01 150 JP CONIN ; CONSOLE CHARACTER IN + 000C C3rB1s01 151 JP CONOUT ; CONSOLE CHARACTER OUT + 000F C3rBCs01 152 JP LIST ; LIST CHARACTER OUT (NULL ROUTINE) + 0012 C3rC0s01 153 JP PUNCH ; PUNCH CHARACTER OUT (NULL ROUTINE) + 0015 C3rC2s01 154 JP READER ; READER CHARACTER OUT (NULL ROUTINE) + 0018 C3rDAs01 155 JP HOME ; MOVE HEAD TO HOME POSITION + 001B C3rC4s01 156 JP SELDSK ; SELECT DISK + 001E C3rDDs01 157 JP SETTRK ; SET TRACK NUMBER + 0021 C3rE3s01 158 JP SETSEC ; SET SECTOR NUMBER + 0024 C3rECs01 159 JP SETDMA ; SET DMA ADDRESS + 0027 C3rF2s01 160 JP READ ; READ DISK + 002A C3rD7s03 161 JP WRITE ; WRITE DISK + 002D C3rBEs01 162 JP LISTST ; RETURN LIST STATUS (NULL ROUTINE) + 0030 C3rE9s01 163 JP SECTRN ; SECTOR TRANSLATE + 164 + 165 ;__________________________________________________________________________________________________ + 166 ; + 167 ; FIXED DATA TABLES FOR ALL DRIVES + 168 ; 0= FLOPPY DISK OR RAM DISK, 1=RAM DISK, 2=IDE, 3=ATAPI OR RAM DISK, 4=HDPART4 + 169 ; 5= 1MB ROM DISK,6=32K ROM DISK + 170 ; + 171 ; NOTE: The RAM disk area is used as a substitute if the Floppy and/or ZIP drives are not enabled + 172 ; in the sustem. This RAM disk is the same "disk" as drive B. + 173 ; + 174 ;__________________________________________________________________________________________________ + 175 + 176 ; DISK PARAMETER HEADER FOR DISK 00 + 0033 177 DPBASE: + 0033 00 00 00 00 178 .DW 0000,0000 + 0037 00 00 00 00 179 .DW 0000,0000 + 003Br1Ds0BrB2s00 180 .DW DIRBF,DPBLK1 + 003Fr4Es0FrDEs0B 181 .DW CHK01,ALL01 + 182 + 183 ; DISK PARAMETER HEADER FOR DISK 01 + 0001 184 .IF CONDUSEFLOPPY + 0001 185 .IF COND144FLOPPY + 0043 00 00 00 00 186 .DW 0000,0000 + 0047 00 00 00 00 187 .DW 0000,0000 + 004Br1Ds0Br0Cs01 188 .DW DIRBF,DPBLK7 ; FOR 1.44M FLOPPIES + 004FrCEs0FrC2s0E 189 .DW CHK07,ALL07 + 190 .ELSE + 191 .DW 0000,0000 + 192 .DW 0000,0000 + 193 .DW DIRBF,DPBLK0 + 194 .DW CHK00,ALL00 + 195 .ENDIF + 196 .ELSE + 197 .DW 0000,0000 + 198 .DW 0000,0000 + 199 .DW DIRBF,DPBLK1 + 200 .DW CHK01,ALL01 + 201 .ENDIF + 202 ; DISK PARAMETER HEADER FOR DISK 02 + 0053 00 00 00 00 203 .DW 0000,0000 + 0057 00 00 00 00 204 .DW 0000,0000 + 005Br1Ds0BrC1s00 205 .DW DIRBF,DPBLK2 + 005Fr4Es0FrFFs0B 206 .DW CHK02,ALL02 + 207 + 0000 208 .IF CONDUSEATAPI + 209 ; DISK PARAMETER HEADER FOR DISK 03 + 210 .DW 0000,0000 + 211 .DW 0000,0000 + 212 .DW DIRBF,DPBLK3 + 213 .DW CHK03,ALL03 + 214 .ELSE + 0063 00 00 00 00 215 .DW 0000,0000 + 0067 00 00 00 00 216 .DW 0000,0000 + 006Br1Ds0BrB2s00 217 .DW DIRBF,DPBLK1 + 006Fr4Es0FrDEs0B 218 .DW CHK01,ALL01 + 219 .ENDIF + 220 + 221 ; DISK PARAMETER HEADER FOR DISK 04 + 0073 00 00 00 00 222 .DW 0000,0000 + 0077 00 00 00 00 223 .DW 0000,0000 + 007Br1Ds0BrDFs00 224 .DW DIRBF,DPBLK4 + 007FrCEs0FrFFs0D 225 .DW CHK04,ALL04 + 226 + 227 ; DISK PARAMETER HEADER FOR DISK 05 + 0083 00 00 00 00 228 .DW 0000,0000 + 0087 00 00 00 00 229 .DW 0000,0000 + 008Br1Ds0BrEEs00 230 .DW DIRBF,DPBLK5 + 008FrCEs0Fr40s0E 231 .DW CHK05,ALL05 + 232 + 233 ; DISK PARAMETER HEADER FOR DISK 06 + 0093 00 00 00 00 234 .DW 0000,0000 + 0097 00 00 00 00 235 .DW 0000,0000 + 009Br1Ds0BrFDs00 236 .DW DIRBF,DPBLK6 + 009FrCEs0Fr81s0E 237 .DW CHK06,ALL06 + 238 ; + 239 + 00A3 240 DPBLK0: ; DISK PARAMETER BLOCK (FLOPPY DISK 720KB) + 00A3 24 00 241 SPT_0: .DW 36 ; 36 SECTORS OF 128 BYTES PER 4.5K TRACK + 00A5 04 242 BSH_0: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 00A6 0F 243 BLM_0: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 00A7 00 244 EXM_0: .DB 0 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 00A8 5E 01 245 DSM_0: .DW 350 ; BLOCKSIZE [2048] * NUMBER OF BLOCKS + 1 = DRIVE SIZE + 00AA 7F 00 246 DRM_0: .DW 127 ; NUMBER OF DIRECTORY ENTRIES + 00AC C0 247 AL0_0: .DB 0b11000000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 00AD 00 248 AL1_0: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 00AE 20 00 249 CKS_0: .DW 32 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 00B0 04 00 250 OFF_0: .DW 4 ; FIRST 4 TRACKS TRACKS RESERVED (18K FOR SYSTEM) + 251 ; + 00B2 252 DPBLK1: ; DISK PARAMETER BLOCK (RAMDISK 512K, 448K USABLE) + 00B2 00 01 253 SPT_1: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK + 00B4 04 254 BSH_1: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 00B5 0F 255 BLM_1: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 00B6 01 256 EXM_1: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 00B7 E1 00 257 DSM_1: .DW 225 ; BLOCKSIZE [2048] * NUMBER OF BLOCKS + 1 = DRIVE SIZE + 00B9 FF 00 258 DRM_1: .DW 255 ; NUMBER OF DIRECTORY ENTRIES + 00BB F0 259 AL0_1: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 00BC 00 260 AL1_1: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 00BD 00 00 261 CKS_1: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 00BF 01 00 262 OFF_1: .DW 1 ; 1 TRACK RESERVED [FIRST 32K OF RAM] + 263 ; + 00C1 264 DPBLK2: ; DISK PARAMETER BLOCK (IDE HARD DISK 8MB) + 00C1 00 01 265 SPT_2: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK + 00C3 05 266 BSH_2: .DB 5 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 00C4 1F 267 BLM_2: .DB 31 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 00C5 01 268 EXM_2: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 00C6 E1 07 269 DSM_2: .DW 2017 ; BLOCKSIZE [4096] * NUMBER OF BLOCKS + 1 = DRIVE SIZE + 00C8 FF 01 270 DRM_2: .DW 511 ; NUMBER OF DIRECTORY ENTRIES + 00CA F0 271 AL0_2: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 00CB 00 272 AL1_2: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 00CC 00 00 273 CKS_2: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 00CE F1 03 274 OFF_2: .DW 0x03F1 ; TRACKS (32K) RESERVED FOR SYSTEM AND OTHER PARTITIONS + 275 ; + 00D0 276 DPBLK3: ; DISK PARAMETER BLOCK (ATAPI DRIVE 8MB) + 00D0 00 01 277 SPT_3: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK + 00D2 05 278 BSH_3: .DB 5 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 00D3 1F 279 BLM_3: .DB 31 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 00D4 01 280 EXM_3: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 00D5 E1 07 281 DSM_3: .DW 2017 ; BLOCKSIZE [4096] * NUMBER OF BLOCKS + 1 = DRIVE SIZE + 00D7 FF 01 282 DRM_3: .DW 511 ; NUMBER OF DIRECTORY ENTRIES + 00D9 F0 283 AL0_3: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 00DA 00 284 AL1_3: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 00DB 00 00 285 CKS_3: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 00DD 01 00 286 OFF_3: .DW 1 ; 1 TRACK (32K) RESERVED FOR SYSTEM + 287 ; + 00DF 288 DPBLK4: ; DISK PARAMETER BLOCK (IDE HARD DISK 1024K) + 00DF 00 01 289 SPT_4: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK + 00E1 04 290 BSH_4: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 00E2 0F 291 BLM_4: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 00E3 01 292 EXM_4: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 00E4 F1 01 293 DSM_4: .DW 497 ; BLOCKSIZE [2048] * NUMBER OF BLOCKS + 1 = DRIVE SIZE + 00E6 FF 00 294 DRM_4: .DW 255 ; NUMBER OF DIRECTORY ENTRIES + 00E8 F0 295 AL0_4: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 00E9 00 296 AL1_4: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 00EA 00 00 297 CKS_4: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 00EC 01 00 298 OFF_4: .DW 1 ; 1 TRACK RESERVED [FIRST 32K OF PARTITION] + 299 ; + 00EE 300 DPBLK5: ; DISK PARAMETER BLOCK (ROMDISK 1MB) + 00EE 00 01 301 SPT_5: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK + 00F0 04 302 BSH_5: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 00F1 0F 303 BLM_5: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 00F2 00 304 EXM_5: .DB 0 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 00F3 FF 01 305 DSM_5: .DW 511 ; BLOCKSIZE [2048] * NUMBER OF BLOCKS +1 =DRIVE SIZE + 00F5 FF 00 306 DRM_5: .DW 255 ; NUMBER OF DIRECTORY ENTRIES + 00F7 F0 307 AL0_5: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 00F8 00 308 AL1_5: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 00F9 00 00 309 CKS_5: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 00FB 01 00 310 OFF_5: .DW 1 ; 1 TRACK RESERVED [FIRST 32K OF ROM] + 311 ; + 00FD 312 DPBLK6: ; DISK PARAMETER BLOCK (ROMDISK 32KB) + 00FD 10 00 313 SPT_6: .DW 16 ; 16 SECTORS OF 128 BYTES PER 2K TRACK + 00FF 03 314 BSH_6: .DB 3 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 0100 07 315 BLM_6: .DB 7 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 0101 01 316 EXM_6: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 0102 1F 00 317 DSM_6: .DW 31 ; BLOCKSIZE [1024] * NUMBER OF BLOCKS + 1 = DRIVE SIZE + 0104 1F 00 318 DRM_6: .DW 31 ; NUMBER OF DIRECTORY ENTRIES + 0106 80 319 AL0_6: .DB 0b10000000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 0107 00 320 AL1_6: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 0108 00 00 321 CKS_6: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 010A 0A 00 322 OFF_6: .DW 10 ; FIRST 10 TRACKS TRACKS RESERVED (20K FOR SYSTEM) + 323 ; SYSTEM IS ROM LOADER, CCP, BDOS, CBIOS, AND MONITOR + 010C 324 DPBLK7: ; DISK PARAMETER BLOCK FLOPPY 1.44M + 010C 48 00 325 SPT_7: .DW 72 ; 16 SECTORS OF 128 BYTES PER 2K TRACK + 010E 04 326 BSH_7: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 010F 0F 327 BLM_7: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 0110 00 328 EXM_7: .DB 0 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 0111 C6 02 329 DSM_7: .DW 710 ; BLOCKSIZE [1024] * NUMBER OF BLOCKS + 1 = DRIVE SIZE + 0113 FF 00 330 DRM_7: .DW 255 ; NUMBER OF DIRECTORY ENTRIES + 0115 F0 331 AL0_7: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 0116 00 332 AL1_7: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 333 + 0117 20 00 334 CKS_7: .DW 32 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 0119 02 00 335 OFF_7: .DW 2 ; FIRST 10 TRACKS TRACKS RESERVED (20K FOR SYSTEM) + 336 ; SYSTEM IS ROM LOADER, CCP, BDOS, CBIOS, AND MONITOR + 337 ; + 338 ; IMPORTANT NOTE: TRACKS 00h - 0AH OF 2K BYTES + 339 ; EACH ARE MARKED WITH THE OFF_6 SET TO 5 AS + 340 ; SYSTEM TRACKS USABLE ROM DRIVE SPACE + 341 ; STARTING AFTER THE TENTH TRACK (IE, TRACK 0AH) + 342 ; MOST LIKELY FIX TO THIS IS PLACING A DUMMY + 343 ; FIRST 20K ROM CONTAINS THE ROM LOADER, MONITOR, + 344 ; CCP, BDOS, BIOS, ETC (10 TRACKS * 2K EACH) + 345 ;__________________________________________________________________________________________________ + 346 ; + 347 ; END OF FIXED CP/M TABLES + 348 ; + 349 ; INDIVIDUAL SUBROUTINES TO PERFORM EACH FUNCTION + 350 ;__________________________________________________________________________________________________ + 351 + 352 + 353 ;___BOOT___________________________________________________________________________________________ + 011B 354 BOOT: ; SIMPLEST CASE IS TO JUST PERFORM PARAMETER INITIALIZATION + 355 ; + 011B 3E 80 356 LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + 011D D3 7C 357 OUT (MPCL_ROM),A ; SWITCH OUT ROM, BRING IN LOWER 32K RAM PAGE + 358 ; + 359 ; + 011F 3E 81 360 LD A,#0b10000001 ; SWITCH IN FIRST 32K LOWER PAGE (FIRST TRACK) + 0121 D3 78 361 OUT (MPCL_RAM),A ; + 362 ; FORMATTING THE RAM IS SIMPLE AS CLEARING THE DIRECTORY AREA + 363 ; TO A VALUE OF E5H (THE FIRST 8K OF TRACK 1 OR THE RAMDISK) + 0123 21 00 00 364 LD HL,#0000 ; STARTING MEMORY ADDRESS OF TRACK 1, SECTOR 0 IN HL + 0126 01 FF 1F 365 LD BC,#0x1FFF ; 8K OF DIRECTORY SECTORS RESERVED (LENGTH IN BC) + 0129 3E E5 366 LD A,#0x0E5 ; INITIALIZING VALUE IN A + 012B 5D 367 LD E,L ; + 012C 54 368 LD D,H ; + 012D 13 369 INC DE ; + 012E 77 370 LD (HL),A ; + 012F ED B0 371 LDIR ; + 372 ; + 0131 3E 80 373 LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + 0133 D3 7C 374 OUT (MPCL_ROM),A ; SWITCH OUT ROM, BRING IN LOWER 32K RAM PAGE + 375 ; + 0135 3E 00 376 LD A,#0 ; ENSURE LOWEST RAM PAGE SELECTED + 0137 D3 78 377 OUT (MPCL_RAM),A ; BRING IN LOWEST 32K RAM PAGE + 378 ; + 0139 AF 379 XOR A ; ZERO IN THE ACCUM + 013A 32 03 00 380 LD (IOBYTE),A ; CLEAR THE IOBYTE + 013D 32 04 00 381 LD (CDISK),A ; SELECT DISK 0 + 382 ; + 0140 CDrC3s05 383 CALL IDE_SOFT_RESET ; RESET THE IDE HARD DISK + 384 ; + 385 ; + 0143 C3r67s01 386 JP GOCPM ; INITIALIZE AND GO TO CP/M + 387 ; + 388 ; + 389 ;___WBOOT__________________________________________________________________________________________ + 0146 390 WBOOT: ; SIMPLEST CASE IS TO READ THE DISK UNTIL ALL SECTORS LOADED + 391 ; WITH A ROMDISK WE SELECT THE ROM AND THE CORRECT PAGE [0] + 392 ; THEN COPY THE CP/M IMAGE (CCP, BDOS, BIOS, MONITOR) TO HIGH RAM + 393 ; LOAD ADDRESS + 394 ; FOR Z80 IT LOOKS LIKE THIS . USING 8080 NEMONICS + 395 ; + 0146 F3 396 DI ; DISABLE INTERRUPT + 0147 31 80 00 397 LD SP,#0x80 ; USE SPACE BELOW BUFFER FOR STACK + 014A ED 56 398 IM 1 ; SET INTERRUPT MODE 1 + 399 ; + 014C AF 400 XOR A ; CHEAP ZERO IN ACC + 014D D3 7C 401 OUT (MPCL_ROM),A ; SEND 0 TO ROM MAP PORT (SWITCH IN LOWER 32K ROM PAGE) + 402 ; + 014F AF 403 XOR A ; CHEAP ZERO IN ACC + 0150 D3 78 404 OUT (MPCL_RAM),A ; SEND 0 TO RAM MAP PORT (SELECT LOWEST RAM PAGE) + 405 ; + 0152 21 00 0A 406 LD HL,#ROMSTART_CPM ; WHERE IN ROM CP/M IS STORED (FIRST BYTE) + 0155 11 00 D0 407 LD DE,#RAMTARG_CPM ; WHERE IN RAM TO MOVE MONITOR TO (FIRST BYTE) + 0158 01 00 08 408 LD BC,#CCPSIZ_CPM ; NUMBER OF BYTES TO MOVE FROM ROM TO RAM + 015B ED B0 409 LDIR ; + 410 ; + 411 ; + 412 ;;;;; EI ; ENABLE INTERRUPTS + 015D 3E 80 413 LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + 015F D3 7C 414 OUT (MPCL_ROM),A ; SWITCH OUT ROM, BRING IN LOWER 32K RAM PAGE + 415 ; + 0161 AF 416 XOR A ; CHEAP ZERO IN ACC + 0162 D3 78 417 OUT (MPCL_RAM),A ; SEND 0 TO RAM MAP PORT (SELECT LOWEST RAM PAGE) + 418 ; + 0164 CDrC3s05 419 CALL IDE_SOFT_RESET ; RESET THE IDE HARD DISK + 420 ; + 0001 421 .IF CONDSUPERSUB ; + 422 ; DO NOTHING FOR ORIGINAL CODE + 423 .ELSE ; + 424 ; CLEAR THE AUTOSUB BUFFER, DO ON A WARM BOOT + 425 XOR A ; + 426 LD (INBUFF+1),A ; SECOND BYTE IS ACTUAL LENGTH + 427 .ENDIF ; + 428 ; FALL THROUGH TO GOCPM ROUTINE + 429 ; + 430 ; END OF LOAD OPERATION, SET PARAMETERS AND GO TO CP/M + 431 ; + 432 ;___GOCPM__________________________________________________________________________________________ + 0167 433 GOCPM: + 434 ; CPU RESET HANDLER + 0167 3E C3 435 LD A,#0x0C3 ; C3 IS A JMP INSTRUCTION + 0169 32 00 00 436 LD (0),A ; FOR JMP TO WBOOT + 016C 21r03s00 437 LD HL,#WBOOTE ; WBOOT ENTRY POINT + 016F 22 01 00 438 LD (1),HL ; SET ADDRESS FIELD FOR JMP AT 0 + 439 ; + 440 ; CPU INTERRUPT HANDLER + 0172 3E C3 441 LD A,#0x0C3 ; C3 IS A JMP INSTRUCTION + 0174 32 38 00 442 LD (0x0038),A ; FOR JMP TO WBOOT + 0177 21r03s00 443 LD HL,#WBOOTE ; WBOOT ENTRY POINT + 017A 22 01 00 444 LD (1),HL ; SET ADDRESS FIELD FOR JMP AT 0 + 445 ; + 017D 32 05 00 446 LD (5),A ; FOR JMP TO BDOS + 0180 21 06 D8 447 LD HL,#BDOS ; BDOS ENTRY POINT + 0183 22 06 00 448 LD (6),HL ; ADDRESS FIELD OF JUMP AT 5 TO BDOS + 449 ; + 0186 01 80 00 450 LD BC,#0x80 ; DEFAULT DMA ADDRESS IS 80H + 0189 CDrECs01 451 CALL SETDMA ; + 452 ; + 0001 453 .IF CONDUSEFLOPPY ; + 018C CDrBFs07 454 CALL SETUPDRIVE ; SETUP FLOPPY PARAMETERS + 455 .ENDIF ; + 456 ; + 0000 457 .IF CONDUSEVDU ; + 458 DI ; DISABLE INTERRUPTS + 459 LD A,#0x1F ; SET HIGH ROM PAGE + 460 OUT (MPCL_ROM),A ; SEND TO ROM PORT MAPPER + 461 LD HL,#0 ; + 462 ADD HL,SP ; GET STACK POINTER INTO HL + 463 LD (PARKSTACK),HL ; SAVE STACK POINTER + 464 LD SP,#FLOPPYSTACK ; + 465 CALL VDU_INIT ; + 466 LD SP,(PARKSTACK) ; RESTORE STACK + 467 LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + 468 OUT (MPCL_ROM),A ; + 469 LD A,#0 ; CHOOSE HIGHEST RAM PAGE + 470 OUT (MPCL_RAM),A ; SEND 19H TO RAM MAP PORT (SELECT HIGHEST RAM PAGE) + 471 ;;;;; EI ; ENABLE INTERRUPTS + 472 .ENDIF ; + 018F 21rADs0A 473 LD HL,#TXT_STARTUP_MSG ; PRINT STARTUP MESSAGE + 0192 CDrBCs04 474 CALL PRTMSG ; + 475 ; + 0195 3A 04 00 476 LD A,(CDISK) ; GET CURRENT DISK NUMBER + 0198 4F 477 LD C,A ; SEND TO THE CCP + 0199 C3 00 D0 478 JP CCP ; GO TO CP/M FOR FURTHER PROCESSING + 479 ; + 480 ;__________________________________________________________________________________________________ + 481 ; + 482 ; ** CONSOLE & PRINTER I/O -- VDU CARD DRIVER INTERFACE + 483 ; + 484 ;__________________________________________________________________________________________________ + 0000 485 .IF CONDUSEVDU + 486 CONST: + 487 PUSH HL ; STORE HL + 488 DI ; DISABLE INTERRUPTS + 489 LD A,#1FH ; SET HIGH ROM PAGE + 490 OUT (MPCL_ROM),A ; SEND TO ROM PORT MAPPER + 491 LD HL,#0 ; + 492 ADD HL,SP ; GET STACK POINTER INTO HL + 493 LD (PARKSTACK),HL ; SAVE STACK POINTER + 494 LD SP,#FLOPPYSTACK ; + 495 CALL IS_KBHIT ; CHECK FOR KB HIT + 496 LD C,A ; STORE RESULT + 497 LD SP,(PARKSTACK) ; RESTORE STACK + 498 LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + 499 OUT (MPCL_ROM),A ; + 500 LD A,#0 ; CHOOSE HIGHEST RAM PAGE + 501 OUT (MPCL_RAM),A ; SEND 19H TO RAM MAP PORT (SELECT HIGHEST RAM PAGE) + 502 LD A,C ; RESTORE RESULT + 503 ;;;;; EI ; ENABLE INTERRUPTS + 504 POP HL ; RESTORE HL + 505 RET + 506 + 507 CONIN: + 508 PUSH HL ; STORE HL + 509 DI ; DISABLE INTERRUPTS + 510 LD A,#0x1F ; SET HIGH ROM PAGE + 511 OUT (MPCL_ROM),A ; SEND TO ROM PORT MAPPER + 512 LD HL,#0 ; + 513 ADD HL,SP ; GET STACK POINTER INTO HL + 514 LD (PARKSTACK),HL ; SAVE STACK POINTER + 515 LD SP,#FLOPPYSTACK ; + 516 CALL GET_KEY ; GET KEY FROM KEYBOARD + 517 LD C,A ; STORE RESULT + 518 LD SP,(PARKSTACK) ; RESTORE STACK + 519 LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + 520 OUT (MPCL_ROM),A ; + 521 LD A,#0x00 ; CHOOSE HIGHEST RAM PAGE + 522 OUT (MPCL_RAM),A ; SEND 19H TO RAM MAP PORT (SELECT HIGHEST RAM PAGE) + 523 LD A,C ; RESTORE RESULT + 524 ;;;;; EI ; ENABLE INTERRUPTS + 525 POP HL ; RESTORE HL + 526 RET + 527 + 528 CONOUT: + 529 PUSH HL ; STORE HL + 530 DI ; DISABLE INTERRUPTS + 531 LD A,#0x1F ; SET HIGH ROM PAGE + 532 OUT (MPCL_ROM),A ; SEND TO ROM PORT MAPPER + 533 LD HL,#0 ; + 534 ADD HL,SP ; GET STACK POINTER INTO HL + 535 LD (PARKSTACK),HL ; SAVE STACK POINTER + 536 LD SP,#FLOPPYSTACK ; + 537 LD A,C ; RESTORE CHARACTER + 538 CALL CHARIN ; DISPLAY CHARACTER + 539 LD SP,(PARKSTACK) ; RESTORE STACK + 540 LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + 541 OUT (MPCL_ROM),A ; + 542 LD A,#0x00 ; CHOOSE HIGHEST RAM PAGE + 543 OUT (MPCL_RAM),A ; SEND 19H TO RAM MAP PORT (SELECT HIGHEST RAM PAGE) + 544 ;;;;; EI ; ENABLE INTERRUPTS + 545 POP HL ; RESTORE HL + 546 RET + 547 LIST: + 548 PUSH HL ; STORE HL + 549 DI ; DISABLE INTERRUPTS + 550 LD A,#0x1F ; SET HIGH ROM PAGE + 551 OUT (MPCL_ROM),A ; SEND TO ROM PORT MAPPER + 552 LD HL,#0 ; + 553 ADD HL,SP ; GET STACK POINTER INTO HL + 554 LD (PARKSTACK),HL ; SAVE STACK POINTER + 555 LD SP,#FLOPPYSTACK ; + 556 LD A,C ; RESTORE CHARACTER + 557 CALL PR_OUTCHAR ; + 558 LD SP,(PARKSTACK) ; RESTORE STACK + 559 LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + 560 OUT (MPCL_ROM),A ; + 561 LD A,#0x00 ; CHOOSE HIGHEST RAM PAGE + 562 OUT (MPCL_RAM),A ; SEND 19H TO RAM MAP PORT (SELECT HIGHEST RAM PAGE) + 563 ;;;;; EI ; ENABLE INTERRUPTS + 564 POP HL ; RESTORE HL + 565 RET + 566 + 567 ;__________________________________________________________________________________________________ + 568 ; + 569 ; ** CONSOLE I/O -- ON-BOARD 16550 SERIAL INTERFACE + 570 ; + 571 ;__________________________________________________________________________________________________ + 572 .ELSE + 019C 573 CONST: ; CONSOLE STATUS, RETURN 0FFH IF CHARACTER READY, 00H IF NOT + 019C DB 6D 574 IN A,(UART + 5) ; READ LINE STATUS REGISTER (UART5 = 068h + $05) + 019E E6 01 575 AND #0x01 ; TEST IF DATA IN RECEIVE BUFFER + 576 ; IS THERE A CHAR READY? 0=NO, 1=YES + 01A0 CArA5s01 577 JP Z,NOT_READY ; + 01A3 3E FF 578 LD A,#0x0FF ; YES, PUT 0FFh IN A AND RETURN + 01A5 579 NOT_READY: ; + 580 ; NO, LEAVE 000h IN A AND RETURN + 01A5 C9 581 RET ; + 01A6 582 CONIN: ; CONSOLE CHARACTER INTO REGISTER A + 583 ; + 01A6 CDr9Cs01 584 CALL CONST ; IS A CHAR READY TO BE READ FROM UART? + 01A9 FE 00 585 CP #0 ; + 01AB CArA6s01 586 JP Z,CONIN ; NO? TRY AGAIN + 01AE DB 68 587 IN A,(UART) ; YES? READ THE CHAR FROM THE UART (UART0 = 068h + $00) + 588 ; REGISTER AND PASS BACK TO USER + 01B0 C9 589 RET ; + 590 ; + 01B1 591 CONOUT: ; CONSOLE CHARACTER OUTPUT FROM REGISTER C + 01B1 DB 6D 592 IN A,(UART + 5) ; READ LINE STATUS REGISTER + 01B3 E6 20 593 AND #0x20 ; TEST IF UART IS READY TO SEND + 01B5 CArB1s01 594 JP Z,CONOUT ; IF NOT REPEAT + 595 ; + 01B8 79 596 LD A,C ; GET TO ACCUMULATOR + 01B9 D3 68 597 OUT (UART),A ; THEN WRITE THE CHAR TO UART (UART0 = 068h + $00) + 01BB C9 598 RET ; + 599 ; + 01BC 600 LIST: ;LIST CHARACTER FROM REGISTER C + 01BC 79 601 LD A,C ;CHARACTER TO REGISTER A + 01BD C9 602 RET ;NULL SUBROUTINE + 603 .ENDIF + 604 ; + 01BE 605 LISTST: ;RETURN LIST STATUS (0 IF NOT READY, 1 IF READY) + 01BE AF 606 XOR A ;0 IS ALWAYS OK TO RETURN + 01BF C9 607 RET ; + 608 ; + 609 ; + 610 ;__________________________________________________________________________________________________ + 611 ; + 612 ; ** PUNCH & READER I/O -- STUB + 613 ; + 614 ;__________________________________________________________________________________________________ + 01C0 615 PUNCH: ;PUNCH CHARACTER FROM REGISTER C + 01C0 79 616 LD A,C ;CHARACTER TO REGISTER A + 01C1 C9 617 RET ;NULL SUBROUTINE + 618 ; + 01C2 619 READER: ;READ CHARACTER INTO REGISTER A FROM READER DEVICE + 01C2 79 620 LD A,C ;CHARACTER TO REGISTER A + 01C3 C9 621 RET + 622 + 623 + 624 ;__________________________________________________________________________________________________ + 625 ; + 626 ; ** DISK STORAGE I/O + 627 ; + 628 ;__________________________________________________________________________________________________ + 629 ; + 630 ; SELECT DISK GIVEN BY REGISTER C + 631 ;__________________________________________________________________________________________________ + 632 + 01C4 21 00 00 633 SELDSK: LD HL,#0x0000 ; ERROR RETURN CODE + 01C7 79 634 LD A,C ; + 0001 635 .IF CONDABONLY ; + 01C8 FE 07 636 CP #7 ; MUST BE BETWEEN 0 AND 6 + 637 .ELSE ; + 638 CP #2 ; IF NO IDE THEN ONLY DRIVE A AND B FOR THE MINI N8VEM SO 0 OR 1 ONLY + 639 .ENDIF ; + 01CA D0 640 RET NC ; RETURN IF OUT OF RANGE + 01CB 32r12s0B 641 LD (DISKNO),A ; + 642 ; DISK NUMBER IS IN THE PROPER RANGE + 643 ; COMPUTE PROPER DISK PARAMETER HEADER ADDRESS + 01CE 6F 644 LD L,A ; L=DISK NUMBER 0,1,2,3,4 + 01CF 26 00 645 LD H,#0 ; HIGH ORDER ZERO + 01D1 29 646 ADD HL,HL ; *2 + 01D2 29 647 ADD HL,HL ; *4 + 01D3 29 648 ADD HL,HL ; *8 + 01D4 29 649 ADD HL,HL ; *16 (SIZE OF EACH HEADER) + 01D5 11r33s00 650 LD DE,#DPBASE ; + 01D8 19 651 ADD HL,DE ; HL= DPBASE(DISKNO*16) + 01D9 C9 652 RET + 653 ;__________________________________________________________________________________________________ + 01DA 654 HOME: ; MOVE TO THE TRACK 00 POSITION OF CURRENT DRIVE + 655 ; TRANSLATE THIS CALL INTO A SETTRK CALL WITH PARAMETER 00 + 01DA 01 00 00 656 LD BC,#0 ; SELECT TRACK 0000 + 657 ;__________________________________________________________________________________________________ + 01DD 658 SETTRK: ; SET TRACK GIVEN BY REGISTER BC + 01DD 60 659 LD H,B ; + 01DE 69 660 LD L,C ; + 01DF 22r02s0B 661 LD (TRACK),HL ; + 01E2 C9 662 RET + 663 ;__________________________________________________________________________________________________ + 01E3 664 SETSEC: ; SET SECTOR GIVEN BY REGISTER BC + 01E3 60 665 LD H,B ; + 01E4 69 666 LD L,C ; + 01E5 22r0As0B 667 LD (SECTOR),HL ; + 01E8 C9 668 RET ; + 669 ;__________________________________________________________________________________________________ + 670 ; + 671 ; TRANSLATE THE SECTOR GIVEN BY BC USING THE + 672 ; TRANSLATE TABLE GIVEN BY DE + 673 ; ONLY USED FOR FLOPPIES! FOR ROMDISK/RAMDISK/IDE/ATAPI IT'S 1:1 + 674 ; DO THE NEXT ROUTINE IS A NULL (RETURNS THE SAME) + 675 ;__________________________________________________________________________________________________ + 01E9 676 SECTRN: + 01E9 60 677 LD H,B ; + 01EA 69 678 LD L,C ; + 01EB C9 679 RET ; + 680 ;__________________________________________________________________________________________________ + 01EC 681 SETDMA: ; SET DMA ADDRESS GIVEN BY REGISTERS B AND C + 01EC 69 682 LD L,C ; LOW ORDER ADDRESS + 01ED 60 683 LD H,B ; HIGH ORDER ADDRESS + 01EE 22r10s0B 684 LD (DMAAD),HL ; SAVE THE ADDRESS + 01F1 C9 685 RET + 686 ;________________________________________________________________________________________________________ + 687 ; DISK DRIVERS . + 688 ; + 689 ; DRIVER NEEDS TO DO SEVERAL THINGS FOR ROM AND RAM DISKS + 690 ; - INTERRUPTS ARE NOT ALLOWED DURING LOW RAM/ROM ACCESS (DISABLE!) + 691 ; -TRANSLATE TRACK AND SECTOR INTO A POINTER TO WHERE THE 128 BYTE + 692 ; SECTOR BEGINS IN THE RAM/ROM + 693 ; -TRANSLATE THE DRIVE INTO A RAM/ROM SELECT, COMBINE WITH TRACK ADDRESS + 694 ; AND SEND TO THE MAP PORT + 695 ; -COPY 128 BYTE FROM OR TO THE ROM/RAMDISK AND MEMORY POINTED TO BY THE DMA + 696 ; ADDRESS PREVIOUSLY STORED + 697 ; -RESTORE MAP PORT TO PRIOR CONDITION BEFOR READ/WRITE + 698 ; + 699 ; - FIRST TRICK IS THAT WE MADE SECTORS 256 AS 256*128=32768 SO WE COPY + 700 ; THE LOW SECTOR ADDRESS TO THE LOW BYTE OF THE HL REGISTER AND THEN + 701 ; MULTIPLY BY 128 THIS RESULTS IN THE STARTING ADDRESS IN THE RAM OR ROM + 702 ; (0000 -> 7F80H) 32K PAGE + 703 ; + 704 ; - TRICK TWO IS THE TRACK ADDRESS EQUALS THE 32K PAGE ADDRESS AND IS A + 705 ; DIRECT SELECT THAT CAN BE COPIED TO THE MAP PORT D0 THROUGH D5 D7 + 706 ; SELECTS THE DRIVE (ROM OR RAM) + 707 ; THAT MEANS THE LOW BYTE OF TRACK CONTAINS THE D0-D5 VALUE AND + 708 ; DISKNO HAS THE DRIVE SELECTED WE FIRST COPY DISKNO TO ACC + 709 ; AND RIGHTSHIFT IT TO PLACE THAT IN BIT 7, WE THEN ADD THE LOW BYTE OF + 710 ; TRACK TO ACC AND THEN SEND THAT TO THE MAP PORT + 711 ; + 712 ; NOTE 1: A WRITE TO ROM SHOULD BE FLAGGED AS AN ERROR + 713 ; NOTE 2: RAM MUST START AS A "FORMATTED DISK" IF BATTERY BACKED UP + 714 ; IT'S A DO ONCE AT COLD COLD START IF NOT BATTERY BACKED U + 715 ; IT WILL HAVE TO BE DONE EVERY TIME THE SYSTEM IS POWERED + 716 ; FORMATTING THE RAM IS SIMPLE AS CLEARING THE DIRECTORY AREA + 717 ; TO A VALUE OF E5H (THE FIRST 8K OF TRACK 1 OR THE RAMDISK) + 718 ; IT COULD BE DONE AS A SIMPLE UTILITY PROGRAM STORED IN ROMD + 719 ; OR ANYTIME COLBOOT IS CALLED(LESS DESIREABLE) + 720 ; + 721 ; -WE NOW CAN COPY TO OR FROM AS CORRECT FOR THE DEVICE 128 BYTES (SECTOR) + 722 ; TO OR FROM THE DMA ADDRESS ALMOST! SINCE ROM OR RAM IS BEING PAGED + 723 ; WE HAVE TO COPY ANYTHING DETINED FOR BELOW 8000H TO A TEMP BUFFER THEN + 724 ; HANDLE THE PAGING + 725 ; + 726 ; + 727 ; - LAST STEP IS TO RESTORE THE MAP PORT TO POINT TO THE RAM (TRACK 0) SO T + 728 ; MEMORY MAP IS ALL RAM AGAIN AND NOT POINTING INTO THE DATA AREAS OR THE + 729 ; SINCE THE RAM 0TH PAGE IS NOMINALLY THE LOW 32K OF RAM IN THE SYSTEM WE + 730 ; SEND A SIMPLE MVI A,80H ; OUT MPCL_ROM ; MVI A,00H ; OUT MPCL_RAM + 731 ; + 732 ; - THE READ OR WRITE OPERATION IS DONE + 733 ; + 734 ; READ DISK + 735 ; USES DE,DL, BC, ACC FLAGS + 736 ; Z80 COULD USE BLOCK MOVE [LDIR] BUT WRITTEN IN 8080 + 737 ;________________________________________________________________________________________________________ + 738 + 739 ;__READ__________________________________________________________________________________________________ + 740 ; + 741 ; PERFORM CP/M SECTOR READ + 742 ;________________________________________________________________________________________________________ + 01F2 743 READ: + 01F2 F3 744 DI ; DISABLE INTERRUPTS + 01F3 3Ar12s0B 745 LD A,(DISKNO) ; GET DRIVE + 01F6 FE 01 746 CP #0x01 ; "B" + 0001 747 .IF CONDUSEFLOPPY + 01F8 CArFEs02 748 JP Z,READ_FLPY_DSK ; READ FLOPPY + 749 .ELSE + 750 JP Z,READ_RAM_DISK ; READ FROM 448K RAM DISK + 751 .ENDIF + 01FB FE 00 752 CP #0 ; "B" + 01FD CAr5As02 753 JP Z,READ_RAM_DISK ; READ FROM 448K RAM DISK + 0200 FE 02 754 CP #2 ; "C" + 0202 CAr78s03 755 JP Z,READ_IDE ; READ FROM 8 MB IDE HARD DISK + 0205 FE 03 756 CP #3 ; "D" + 0000 757 .IF CONDUSEATAPI + 758 JP Z,READ_ATAPI ; READ FROM 8 MB ATAPI + 759 .ELSE + 0207 CAr5As02 760 JP Z,READ_RAM_DISK ; READ FROM 448K RAM DISK + 761 .ENDIF + 762 + 020A FE 04 763 CP #4 ; "E" + 020C CArD6s03 764 JP Z,READ_HDPART4 ; READ FROM 1 MB IDE HARD DISK, PARTITION 4 ** future use + 020F FE 05 765 CP #5 ; "F" + 0211 CAr5As02 766 JP Z,READ_RAM_DISK ; READ FROM 1M ROM DISK (UTILIZES SAME + 767 ; ROUTINES AS RAM_DISK + 768 ; "G" + 769 ; READ FROM 22K EEPROM DISK , SO FALL THROUGH + 770 + 771 ;___READ_EEPROM_DISK_____________________________________________________________________________________ + 772 ; + 773 ; READ EEPROM DISK + 774 ;________________________________________________________________________________________________________ + 0214 775 READ_EEPROM_DISK: + 776 ; + 777 ; IF ROM, MAP TRACK/SECTOR TO VIRTUAL TRACK/SECTOR + 778 ; HANDLE READING FROM ROM HERE + 779 ; + 780 ; PURPOSE OF THIS ROUTINE IS TO MAP 32K ROM PART + 781 ; TRACK/SECTOR MAP (2K TRACK SIZE MADE OF 16 128 + 782 ; BYTE SECTORS EACH) ONTO WHAT THE RAM/ROM SECTOR + 783 ; READ ROUTINES ARE EXPECTING (32K TRACK SIZE MADE + 784 ; OF 256 128 BYTE SECTORS EACH) THE ROUTINE + 785 ; CONVERTS 4 BIT TRACK # AND 4 BIT SECTOR # + 786 ; INTO A VIRTUAL 1 TRACK, 256 SECTOR ACCESS + 0214 2Ar02s0B 787 LD HL,(TRACK) ; TRACK # IS UPPER 4 BITS OF SECTOR ADDRESS + 0217 29 788 ADD HL,HL ; SHIFT BITS LEFT 1 (*2) + 0218 29 789 ADD HL,HL ; SHIFT BITS LEFT 1 (*4) + 0219 29 790 ADD HL,HL ; SHIFT BITS LEFT 1 (*8) + 021A 29 791 ADD HL,HL ; SHIFT BITS LEFT 1 (*16) + 021B 44 792 LD B,H ; PUT UPPER 4 BITS OF SECTOR ADDRESS IN BC + 021C 4D 793 LD C,L ; (B IS UPPER BYTE AND C IS LOWER BYTE) + 794 ; BC NOW CONTAINS THE UPDATED TRACK # + 021D 2Ar0As0B 795 LD HL,(SECTOR) ; SECTOR # IS LOWER 4 BITS OF SECTOR ADDRESS + 0220 09 796 ADD HL,BC ; VIRTUAL SECTOR = (UPDATED TRACK #) + SECTOR # + 0221 22r0Cs0B 797 LD (PSECTOR),HL ; STORE VIRTUAL SECTOR # + 798 ; NOW CONTINUE READING ROM WITH REGULAR RAM + 799 ; SETUP FOR READ OF RAM OR ROM DISK + 0224 2Ar0Cs0B 800 LD HL,(PSECTOR) ; + 0227 29 801 ADD HL,HL ; SHIFT BITS LEFT 1 (*2) + 0228 29 802 ADD HL,HL ; SHIFT BITS LEFT 1 (*4) + 0229 29 803 ADD HL,HL ; SHIFT BITS LEFT 1 (*8) + 022A 29 804 ADD HL,HL ; SHIFT BITS LEFT 1 (*16) + 022B 29 805 ADD HL,HL ; SHIFT BITS LEFT 1 (*32) + 022C 29 806 ADD HL,HL ; SHIFT BITS LEFT 1 (*64) + 022D 29 807 ADD HL,HL ; SHIFT BITS LEFT 1 (*128) + 022E 22r0Es0B 808 LD (SECST),HL ; SAVE SECTOR STARTING ADDRESS + 809 ; SET PAGER WITH DRIVE (0) AND TRACK (0) + 0231 3E 00 810 LD A,#0 ; SWITCH IN ROM PAGE + 0233 D3 7C 811 OUT (MPCL_ROM),A ; SEND TO PORT MAPPER + 0235 32r08s0B 812 LD (PAGER),A ; SAVE COPY (JUST BECAUSE) + 0238 21rE2s0F 813 LD HL,#SECTOR_BUFFER ; LOAD HL WITH TEMP BUF ADDRESS + 023B 5D 814 LD E,L ; + 023C 54 815 LD D,H ; GET IT INTO DE + 023D 2Ar0Es0B 816 LD HL,(SECST) ; GET ROM/RAM ADDRESS + 0240 CDr10s05 817 CALL COPY_CPM_SECTOR ; + 0243 CDr04s05 818 CALL RPAGE ; SET PAGE TO CP/M RAM + 0246 2Ar10s0B 819 LD HL,(DMAAD) ; LOAD HL WITH DMA ADDRESS + 0249 5D 820 LD E,L ; + 024A 54 821 LD D,H ; GET IT INTO DE + 024B 21rE2s0F 822 LD HL,#SECTOR_BUFFER ; GET ROM/RAM ADDRESS + 024E CDr10s05 823 CALL COPY_CPM_SECTOR ; + 0251 3Ar12s0B 824 LD A,(DISKNO) ; STORE CURRENT DRIVE IN BUFFER + 0254 32rDDs0F 825 LD (CUDISK),A ; + 0257 3E 00 826 LD A,#0 ; + 827 ;;;;; EI ; RE-ENABLE INTERRUPTS + 0259 C9 828 RET + 829 ;___READ_RAM_DISK_________________________________________________________________________________________ + 830 ; + 831 ; READ RAM DISK + 832 ;________________________________________________________________________________________________________ + 025A 833 READ_RAM_DISK: ; + 834 ; IF RAM, PROCEED WITH NORMAL TRACK/SECTOR READ + 025A CDrCBs04 835 CALL SECPAGE ; SETUP FOR READ OF RAM OR ROM DISK + 025D CDrD9s04 836 CALL PAGERB ; SET PAGER WITH DRIVE AND TRACK + 0260 21rE2s0F 837 LD HL,#SECTOR_BUFFER ; LOAD HL WITH TEMP BUF ADDRESS + 0263 5D 838 LD E,L ; + 0264 54 839 LD D,H ; GET IT INTO DE + 0265 2Ar0Es0B 840 LD HL,(SECST) ; GET ROM/RAM ADDRESS + 0268 CDr10s05 841 CALL COPY_CPM_SECTOR ; MOVE SECTOR TO SECTOR_BUFFER + 026B CDr04s05 842 CALL RPAGE ; SET PAGE TO CP/M RAM + 026E 2Ar10s0B 843 LD HL,(DMAAD) ; LOAD HL WITH DMA ADDRESS ; + 0271 5D 844 LD E,L ; + 0272 54 845 LD D,H ; GET IT INTO DE + 0273 21rE2s0F 846 LD HL,#SECTOR_BUFFER ; GET ROM/RAM ADDRESS + 0276 CDr10s05 847 CALL COPY_CPM_SECTOR ; MOVE SECTOR FROM SECTOR_BUFFER TO DMA AREA + 0279 3Ar12s0B 848 LD A,(DISKNO) ; STORE CURRENT DRIVE IN BUFFER + 027C 32rDDs0F 849 LD (CUDISK),A ; + 027F 3E 00 850 LD A,#0 ; + 851 ;;;;; EI ; RE-ENABLE INTERRUPTS + 0281 C9 852 RET + 853 + 854 ;___TRFLSEC______________________________________________________________________________________________ + 855 ; + 856 ; TRANSLATE LOGICAL FLOPPY DISK SECTOR TO PHYSICAL SECTOR + 857 ; IN: TRACK,SECTOR + 858 ; OUT: PTRACK,PSECTOR,SECTOR_INDEX + 859 ;________________________________________________________________________________________________________ + 0282 860 TRFLSEC: + 0282 3Ar02s0B 861 LD A,(TRACK) ; LOAD TRACK # (LOW BYTE) + 0285 E6 01 862 AND #1 ; FILTER OUT HEAD + 0287 32rEBs0A 863 LD (HEAD),A ; STORE HEAD + 028A 3Ar02s0B 864 LD A,(TRACK) ; SAVE TRACK IN A + 028D CB 3F 865 SRL A ; REMOVE HEAD BIT + 028F 32r04s0B 866 LD (PTRACK),A ; STORE IN TRACK + 0292 3Ar0As0B 867 LD A,(SECTOR) ; LOAD SECTOR # (LOW BYTE) + 0295 32r1Cs0B 868 LD (SECTOR_INDEX),A ; STORE SECTOR IN SECTOR INDEX + 0298 CB 3F 869 SRL A ; + 029A CB 3F 870 SRL A ; DIVIDE BY 4 (FOR BLOCKING) + 029C 32r0Cs0B 871 LD (PSECTOR),A ; STORE IN SECTOR + 029F 3Ar1Cs0B 872 LD A,(SECTOR_INDEX) ; FILTER OUT UNWANTED BITS + 02A2 E6 03 873 AND #3 ; + 02A4 32r1Cs0B 874 LD (SECTOR_INDEX),A ; + 02A7 C9 875 RET + 876 + 877 ;___DEBSEC_______________________________________________________________________________________________ + 878 ; + 879 ; DEBLOCK 512 BYTE SECTOR FOR CP/M + 880 ; + 881 ;________________________________________________________________________________________________________ + 02A8 882 DEBSEC: + 02A8 2Ar10s0B 883 LD HL,(DMAAD) ; LOAD HL WITH DMA ADDRESS + 02AB 54 884 LD D,H ; TRANSFER HL REGISTERS TO DE + 02AC 5D 885 LD E,L ; + 02AD D5 886 PUSH DE ; STORE DE + 887 ; COMPUTE STARTING ADDRESS OF CP/M SECTOR IN READ SECTOR BUFFER + 02AE 21rE2s0F 888 LD HL,#SECTOR_BUFFER ; LOAD HL WITH SECTOR BUFFER ADDRESS + 02B1 3Ar1Cs0B 889 LD A,(SECTOR_INDEX) ; GET THE SECTOR INDEX (CP/M SECTOR OFFSET IN BUFFER) + 02B4 0F 890 RRCA ; MOVE BIT 0 TO BIT 7 + 02B5 0F 891 RRCA ; DO AGAIN - IN EFFECT MULTIPLY BY 4 + 02B6 16 00 892 LD D,#0 ; PUT RESULT AS 16 VALUE IN DE, UPPER BYTE IN D IS 000h + 02B8 5F 893 LD E,A ; PUT ADDRESS OFFSET IN E + 02B9 19 894 ADD HL,DE ; MULTIPLY BY 2, TOTAL MULTIPLICATION IS X 128 + 02BA 19 895 ADD HL,DE ; CP/M SECTOR STARTING ADDRESS IN IDE HD SECTOR BUFFER + 896 ; COPY CP/M SECTOR TO BDOS DMA ADDRESS BUFFER + 02BB D1 897 POP DE ; RESTORE DE + 02BC CDr10s05 898 CALL COPY_CPM_SECTOR ; + 02BF C9 899 RET + 900 + 901 ;___BLKSEC_______________________________________________________________________________________________ + 902 ; + 903 ; BLOCK 512 BYTE SECTOR FOR CP/M + 904 ; + 905 ;________________________________________________________________________________________________________ + 02C0 906 BLKSEC: + 907 ; COMPUTE STARTING ADDRESS OF CP/M SECTOR IN READ SECTOR BUFFER + 02C0 21rE2s0F 908 LD HL,#SECTOR_BUFFER ; LOAD HL WITH SECTOR BUFFER ADDRESS + 02C3 3Ar1Cs0B 909 LD A,(SECTOR_INDEX) ; GET THE SECTOR INDEX (CP/M SECTOR OFFSET IN BUFFER) + 02C6 0F 910 RRCA ; MOVE BIT 0 TO BIT 7 + 02C7 0F 911 RRCA ; DO AGAIN - IN EFFECT MULTIPLY BY 64 + 02C8 16 00 912 LD D,#0 ; PUT RESULT AS 16 VALUE IN DE, UPPER BYTE IN D IS 000h + 02CA 5F 913 LD E,A ; PUT ADDRESS OFFSET IN E + 02CB 19 914 ADD HL,DE ; CP/M SECTOR STARTING ADDRESS IN IDE HD SECTOR BUFFER + 02CC 19 915 ADD HL,DE ; MULTIPLY BY 2, TOTAL MULTIPLICATION IS X 128 + 02CD 22r0Es0B 916 LD (SECST),HL ; KEEP CP/M SECTOR ADDRESS FOR LATER USE + 917 ; COPY CP/M SECTOR FROM BDOS DMA ADDRESS BUFFER + 02D0 2Ar0Es0B 918 LD HL,(SECST) ; LOAD CP/M SECTOR ADDRESS (WHERE THE DATA IS TO BE WRITTEN) + 02D3 54 919 LD D,H ; TRANSFER HL REGISTERS TO DE + 02D4 5D 920 LD E,L ; + 02D5 2Ar10s0B 921 LD HL,(DMAAD) ; LOAD HL WITH DMA ADDRESS (WHERE THE DATA TO BE WRITTEN IS) + 02D8 CDr10s05 922 CALL COPY_CPM_SECTOR ; + 02DB C9 923 RET + 924 + 925 ;___ISCUR_______________________________________________________________________________________________ + 926 ; + 927 ; IS CURRENT SECTOR IN BUFFER? + 928 ; + 929 ;________________________________________________________________________________________________________ + 02DC 930 ISCUR: + 02DC 2Ar0Cs0B 931 LD HL,(PSECTOR) ; COMPARE REQUESTED SECTOR WITH SECTOR IN BUFFER + 02DF 3ArDEs0F 932 LD A,(CUSECTOR) ; + 02E2 BD 933 CP L ; + 02E3 C0 934 RET NZ ; LOW BYTE NOT EQUAL + 02E4 3ArDFs0F 935 LD A,(CUSECTOR+1) ; + 02E7 BC 936 CP H ; + 02E8 C0 937 RET NZ ; HIGH BYTE NOT EQUAL + 02E9 2Ar04s0B 938 LD HL,(PTRACK) ; COMPARE REQUESTED TRACK WITH TRACK IN BUFFER + 02EC 3ArE0s0F 939 LD A,(CUTRACK) ; + 02EF BD 940 CP L ; LOW BYTE NOT EQUAL + 02F0 C0 941 RET NZ ; + 02F1 3ArE1s0F 942 LD A,(CUTRACK+1) ; + 02F4 BC 943 CP H ; + 02F5 C0 944 RET NZ ; HIGH BYTE NOT EQUAL + 02F6 2Ar12s0B 945 LD HL,(DISKNO) ; COMPARE REQUESTED DRIVE WITH DRIVE IN BUFFER + 02F9 3ArDDs0F 946 LD A,(CUDISK) ; + 02FC BD 947 CP L ; + 02FD C9 948 RET ; EXIT WITH RESULT + 949 + 950 ;___READ_FLPY_DSK________________________________________________________________________________________ + 951 ; + 952 ; READ FLOPPY DISK + 953 ; + 954 ;________________________________________________________________________________________________________ + 955 + 02FE 956 READ_FLPY_DSK: + 02FE F3 957 DI ; DISABLE INTERRUPTS + 02FF 21 00 00 958 LD HL,#0 ; + 0302 39 959 ADD HL,SP ; GET STACK POINTER INTO HL + 0303 22r64s0A 960 LD (PARKSTACK),HL ; SAVE STACK POINTER + 0306 31r63s0A 961 LD SP,#FLOPPYSTACK ; + 0309 CDr82s02 962 CALL TRFLSEC ; TRANSLATE SECTOR INFORMATION + 030C CDr1As03 963 CALL READ_FLPY_SEC ; + 030F CDrA8s02 964 CALL DEBSEC ; DEBLOCK SECTOR + 0312 3ArF7s0A 965 LD A,(ST1) ; LOAD RESULT CODE INTO A + 0315 966 READ_FLPY_DSK_EXIT: ; + 0315 ED 7Br64s0A 967 LD SP,(PARKSTACK) ; RETURN STACK + 968 ;;;;; EI ; RE-ENABLE INTERRUPTS + 0319 C9 969 RET + 970 + 971 + 972 ;___READ_FLPY_SEC________________________________________________________________________________________ + 973 ; + 974 ; READ A SECTOR FROM A FLOPPY DISK + 975 ; + 976 ;________________________________________________________________________________________________________ + 031A 977 READ_FLPY_SEC: + 031A 3E 00 978 LD A,#0 ; RESET STATUS FLAG 1 + 031C 32rF7s0A 979 LD (ST1),A ; + 031F CDrDCs02 980 CALL ISCUR ; IS CURRENT SECTOR ALREADY IN BUFFER + 0322 CAr65s03 981 JP Z,READ_FLPY_SEC_OK + 0325 3E 14 982 LD A,#20 ; 20 RETRIES + 0327 32rFFs0A 983 LD (RETRY),A ; + 032A 3E 02 984 LD A,#2 ; 2 ITERATIONS OF RETRIES + 032C 32r00s0B 985 LD (RETRY1),A ; + 032F 986 READ_FLPY_SEC_RETRY: ; + 032F CDr1Es08 987 CALL FLOPPYREAD ; READ THE FLOPPY DISK SECTOR + 0332 3ArF6s0A 988 LD A,(ST0) ; GET STATUS FLAG 0 + 0335 E6 F8 989 AND #0x0F8 ; MASK OF DRIVE AND HEAD SELECTION + 0337 47 990 LD B,A ; MOVE STATUS FLAG 0 TO B + 0338 3ArF7s0A 991 LD A,(ST1) ; GET STATUS FLAG 1 + 033B B0 992 OR B ; IF ZERO READ WAS OK + 033C CAr65s03 993 JP Z,READ_FLPY_SEC_OK + 033F 3ArFFs0A 994 LD A,(RETRY) ; READ NOT OK, DEC RETRY COUNTER + 0342 3D 995 DEC A ; + 0343 32rFFs0A 996 LD (RETRY),A ; STORE NEW RETRY COUNTER + 0346 C2r2Fs03 997 JP NZ,READ_FLPY_SEC_RETRY + 0349 CDr61s09 998 CALL CYCLEFLOPPY ; CYCLE FLOPPY HEAD + 034C 3E 14 999 LD A,#20 ; RESET TO 20 RETRIES + 034E 32rFFs0A 1000 LD (RETRY),A ; STORE RETRY COUNTER + 0351 3Ar00s0B 1001 LD A,(RETRY1) ; DEC RETRY ITERATION COUNTER + 0354 3D 1002 DEC A ; + 0355 32r00s0B 1003 LD (RETRY1),A ; + 0358 C2r2Fs03 1004 JP NZ,READ_FLPY_SEC_RETRY + 035B 21 FF FF 1005 LD HL,#0x0FFFF ; SET INVALID CONDITION, BUFFER IS INVALID + 035E 22rDEs0F 1006 LD (CUSECTOR),HL ; CURRENT PHYSICAL DISK SECTOR IN BUFFER + 0361 22rE0s0F 1007 LD (CUTRACK),HL ; CURRENT PHYSICAL DISK TRACK IN BUFFER + 0364 C9 1008 RET ; + 0365 1009 READ_FLPY_SEC_OK: ; + 0365 2Ar0Cs0B 1010 LD HL,(PSECTOR) ; STORE PHYSICAL SECTOR IN BUFFER + 0368 22rDEs0F 1011 LD (CUSECTOR),HL ; + 036B 2Ar04s0B 1012 LD HL,(PTRACK) ; STORE PHYSICAL DISK TRACK IN BUFFER + 036E 22rE0s0F 1013 LD (CUTRACK),HL ; + 0371 3Ar12s0B 1014 LD A,(DISKNO) ; STORE CURRENT DRIVE IN BUFFER + 0374 32rDDs0F 1015 LD (CUDISK),A ; + 0377 C9 1016 RET + 1017 + 1018 ;___READ_IDE_____________________________________________________________________________________________ + 1019 ; + 1020 ; READ FROM IDE HARD DISK + 1021 ;________________________________________________________________________________________________________ + 1022 + 0378 1023 READ_IDE: + 0378 F3 1024 DI ; DISABLE INTERRUPTS + 0379 21 00 00 1025 LD HL,#0 ; + 037C 39 1026 ADD HL,SP ; GET STACK POINTER INTO HL + 037D 22r64s0A 1027 LD (PARKSTACK),HL ; SAVE STACK POINTER + 0380 31r63s0A 1028 LD SP,#FLOPPYSTACK ; + 1029 ; DISABLE INTERRUPTS + 0383 CDr16s05 1030 CALL CONVERT_IDE_SECTOR_CPM + 0386 CDr6As05 1031 CALL IDE_READ_SECTOR ; READ THE IDE HARD DISK SECTOR + 0389 D2r96s03 1032 JP NC,READ_IDE_ERROR + 038C CDrA8s02 1033 CALL DEBSEC ; + 038F ED 7Br64s0A 1034 LD SP,(PARKSTACK) ; RETURN STACK + 1035 ;;;;; EI ; RE-ENABLE INTERRUPTS + 0393 3E 00 1036 LD A,#0 ; RETURN ERROR CODE READ SUCCESSFUL A=0 + 0395 C9 1037 RET ; + 0396 1038 READ_IDE_ERROR: ; + 0396 ED 7Br64s0A 1039 LD SP,(PARKSTACK) ; RETURN STACK + 1040 ;;;;; EI ; RE-ENABLE INTERRUPTS + 039A 3E FF 1041 LD A,#0x0FF ; RETURN ERROR CODE READ ERROR A=FF + 039C C9 1042 RET + 1043 + 1044 ;___READ_ATAPI_________________________________________________________________________________________ + 1045 ; + 1046 ; READ FROM ATAPI DEVICE + 1047 ;________________________________________________________________________________________________________ + 039D 1048 READ_ATAPI: + 039D 3E FF 1049 LD A,#0x0FF ; 255 RETRIES + 039F 32rFFs0A 1050 LD (RETRY),A ; + 03A2 1051 READ_ATAPI_RETRY: + 03A2 3E 10 1052 LD A,#0x10 ; SET TO SECONDARY DEVICE + 03A4 32r17s0B 1053 LD (IDEDEVICE),A ; + 03A7 F3 1054 DI ; DISABLE INTERRUPTS + 03A8 21 00 00 1055 LD HL,#0 ; + 03AB 39 1056 ADD HL,SP ; GET STACK POINTER INTO HL + 03AC 22r64s0A 1057 LD (PARKSTACK),HL ; SAVE STACK POINTER + 03AF 31r63s0A 1058 LD SP,#FLOPPYSTACK ; + 03B2 CDr16s05 1059 CALL CONVERT_IDE_SECTOR_CPM + 03B5 CDrDFs06 1060 CALL ATAPI_READ_SECTOR + 03B8 D2rC5s03 1061 JP NC,READ_ATAPI_ERROR + 03BB CDrA8s02 1062 CALL DEBSEC ; + 03BE ED 7Br64s0A 1063 LD SP,(PARKSTACK) ; RETURN STACK + 1064 ;;;;; EI ; RE-ENABLE INTERRUPTS + 03C2 3E 00 1065 LD A,#0 ; RETURN ERROR CODE READ SUCCESSFUL A=0 + 03C4 C9 1066 RET ; + 03C5 1067 READ_ATAPI_ERROR: + 03C5 3ArFFs0A 1068 LD A,(RETRY) ; READ NOT OK, DEC RETRY COUNTER + 03C8 3D 1069 DEC A ; + 03C9 32rFFs0A 1070 LD (RETRY),A ; STORE NEW RETRY COUNTER + 03CC C2rA2s03 1071 JP NZ,READ_ATAPI_RETRY + 03CF ED 7Br64s0A 1072 LD SP,(PARKSTACK) ; RETURN STACK + 1073 ;;;;; EI ; RE-ENABLE INTERRUPTS + 03D3 3E FF 1074 LD A,#0x0FF ; RETURN ERROR CODE READ ERROR A=FF + 03D5 C9 1075 RET ; + 1076 + 03D6 1077 READ_HDPART4: + 1078 ; STUB + 03D6 C9 1079 RET + 1080 + 1081 ;___WRITE______________________________________________________________________________________________ + 1082 ; + 1083 ; HANDLE CP/M WRITE CALL + 1084 ; + 1085 ;________________________________________________________________________________________________________ + 03D7 1086 WRITE: + 03D7 F3 1087 DI ; DISABLE INTERRUPTS + 03D8 3Ar12s0B 1088 LD A,(DISKNO) ; GET DRIVE + 03DB FE 01 1089 CP #1 ; FIND OUT WHICH DRIVE IS BEING REQUESTED + 0001 1090 .IF CONDUSEFLOPPY + 03DD CAr25s04 1091 JP Z,WRITE_FLP_DSK ; + 1092 .ELSE + 1093 JP Z,WRITE_RAM_DISK ; WRITE TO 448K RAM DISK + 1094 .ENDIF + 03E0 FE 00 1095 CP #0 ; + 03E2 CArFDs03 1096 JP Z,WRITE_RAM_DISK ; WRITE TO 448K RAM DISK + 03E5 FE 02 1097 CP #2 ; + 03E7 CAr66s04 1098 JP Z,WRITE_IDE ; WRITE TO 8 MB IDE HARD DISK, PARTITION 2 + 03EA FE 03 1099 CP #3 ; + 0000 1100 .IF CONDUSEATAPI + 1101 JP Z,WRITE_ATAPI ; WRITE TO 8 MB IDE HARD DISK, PARTITION 3 + 1102 .ELSE + 03EC CArFDs03 1103 JP Z,WRITE_RAM_DISK ; WRITE TO 448K RAM DISK + 1104 .ENDIF + 03EF FE 04 1105 CP #4 ; + 03F1 CArBBs04 1106 JP Z,WRITE_HDPART4 ; WRITE TO 1 MB IDE HARD DISK, PARTITION 4 + 1107 + 1108 + 1109 ;___RDONLY______________________________________________________________________________________________ + 1110 ; + 1111 ; HANDLE WRITE TO READ ONLY + 1112 ; + 1113 ; SENDS A MESSAGE TO TERMINAL THAT ROM DRIVE IS NOT WRITEABLE + 1114 ; DOES A PAUSE THEN RETURNS TO CPM WITH ERROR FLAGGED THIS IS + 1115 ; DONE TO ALLOW A POSSIBLE GRACEFUL EXIT (SOME APPS MAY PUKE) + 1116 ;________________________________________________________________________________________________________ + 03F4 1117 RDONLY: + 03F4 21r8Cs0A 1118 LD HL,#TXT_RO_ERROR ; SET HL TO START OF ERROR MESSAGE + 03F7 CDrBCs04 1119 CALL PRTMSG ; PRINT ERROR MESSAGE + 03FA 3E 01 1120 LD A,#1 ; SEND BAD SECTOR ERROR BACK + 1121 ; BDOS WILL ALSO PRINT ITS OWN ERROR MESSAGE + 03FC C9 1122 RET + 1123 + 1124 ;___WRITE_RAM_DISK_____________________________________________________________________________________ + 1125 ; + 1126 ; WRITE RAM DISK + 1127 ;________________________________________________________________________________________________________ + 03FD 1128 WRITE_RAM_DISK: + 03FD 21rE2s0F 1129 LD HL,#SECTOR_BUFFER ; LOAD HL WITH TEMP BUF ADDRESS + 0400 5D 1130 LD E,L ; + 0401 54 1131 LD D,H ; GET IT INTO DE + 0402 2Ar10s0B 1132 LD HL,(DMAAD) ; GET DMA ADDRESS + 0405 CDr10s05 1133 CALL COPY_CPM_SECTOR ; + 0408 CDrCBs04 1134 CALL SECPAGE ; GET RAM PAGE WRITE ADDRESS + 040B CDrD9s04 1135 CALL PAGERB ; SET PAGER WITH DRIVE AND TRACK + 040E 2Ar0Es0B 1136 LD HL,(SECST) ; LOAD HL WITH DMA ADDRESS (WHERE TO WRITE TO) + 0411 5D 1137 LD E,L ; + 0412 54 1138 LD D,H ; GET IT INTO DE + 0413 21rE2s0F 1139 LD HL,#SECTOR_BUFFER ; GET TEMP BUFFER ADDRESS + 0416 CDr10s05 1140 CALL COPY_CPM_SECTOR ; + 0419 CDr04s05 1141 CALL RPAGE ; SET BACK TO RAM + 041C 3Ar12s0B 1142 LD A,(DISKNO) ; STORE CURRENT DRIVE IN BUFFER + 041F 32rDDs0F 1143 LD (CUDISK),A ; + 0422 3E 00 1144 LD A,#0 ; + 1145 ;;;;; EI ; RE-ENABLE INTERRUPTS + 0424 C9 1146 RET + 1147 + 1148 ;___WRITE_FLP_DSK_____________________________________________________________________________________ + 1149 ; + 1150 ; WRITE FLOPPY DISK + 1151 ;________________________________________________________________________________________________________ + 0425 1152 WRITE_FLP_DSK: + 0425 F3 1153 DI ; DISABLE INTERRUPTS + 0426 21 00 00 1154 LD HL,#0 ; + 0429 39 1155 ADD HL,SP ; MOVE STACK POINTER TO HL + 042A 22r64s0A 1156 LD (PARKSTACK),HL ; SAVE STACK POINTER + 042D 31r63s0A 1157 LD SP,#FLOPPYSTACK ; + 0430 CDr82s02 1158 CALL TRFLSEC ; TRANSLATE SECTOR INFORMATION + 0433 CDr1As03 1159 CALL READ_FLPY_SEC ; + 0436 3ArF7s0A 1160 LD A,(ST1) ; GET STATUS CODE + 0439 C2r5Es04 1161 JP NZ,WRITE_FLP_DSK_OK + 043C 1162 WRITE_READ_FLPY_DSK_OK: ; + 043C CDrC0s02 1163 CALL BLKSEC ; BLOCK SECTOR + 1164 ; IDE HD SECTOR IS NOW UPDATED WITH CURRENT CP/M SECTOR DATA SO WRITE TO DISK + 043F 3E 14 1165 LD A,#20 ; 20 RETRIES + 0441 32rFFs0A 1166 LD (RETRY),A ; + 0444 1167 WRITE_FLP_DSK_RETRY: ; + 0444 CDr26s08 1168 CALL FLOPPYWRITE ; WRITE THE FLOPPY DISK SECTOR + 0447 3ArF6s0A 1169 LD A,(ST0) ; GET STATUS CODE 0 + 044A E6 F8 1170 AND #0x0F8 ; MASK OF DRIVE AND HEAD SELECTION + 044C 47 1171 LD B,A ; MOVE STATUS CODE 0 TO B + 044D 3ArF7s0A 1172 LD A,(ST1) ; GET STATUS CODE 1 + 0450 B0 1173 OR B ; IF ZERO WRITE WAS OK + 0451 CAr5Es04 1174 JP Z,WRITE_FLP_DSK_OK ; + 0454 3ArFFs0A 1175 LD A,(RETRY) ; BAD WRITE, DEC RETRY COUNTER + 0457 3D 1176 DEC A ; + 0458 32rFFs0A 1177 LD (RETRY),A ; STORE NEW RETRY COUNTER + 045B C2r44s04 1178 JP NZ,WRITE_FLP_DSK_RETRY ; + 045E 1179 WRITE_FLP_DSK_OK: ; + 045E ED 7Br64s0A 1180 LD SP,(PARKSTACK) ; RESTORE STACK + 0462 3ArF7s0A 1181 LD A,(ST1) ; GET STATUS CODE 1 + 1182 ;;;;; EI ; RE-ENABLE INTERRUPTS + 0465 C9 1183 RET + 1184 + 1185 + 1186 + 1187 ;___WRITE_IDE____________________________________________________________________________________________ + 1188 ; + 1189 ; WRITE TO IDE DEVICE + 1190 ;________________________________________________________________________________________________________ + 0466 1191 WRITE_IDE: + 0466 F3 1192 DI ; DISABLE INTERRUPTS + 0467 21 00 00 1193 LD HL,#0 ; + 046A 39 1194 ADD HL,SP ; GET STACK POINTER INTO HL + 046B 22r64s0A 1195 LD (PARKSTACK),HL ; SAVE STACK POINTER + 046E 31r63s0A 1196 LD SP,#FLOPPYSTACK ; + 0471 CDr16s05 1197 CALL CONVERT_IDE_SECTOR_CPM ; + 0474 CDr6As05 1198 CALL IDE_READ_SECTOR ; READ THE IDE HARD DISK SECTOR + 0477 D2r87s04 1199 JP NC,WRITE_IDE_ERROR ; + 047A CDrC0s02 1200 CALL BLKSEC ; DEBLOCK SECTOR + 047D CDr9Fs05 1201 CALL IDE_WRITE_SECTOR ; WRITE THE UPDATED IDE HARD DISK SECTOR + 0480 ED 7Br64s0A 1202 LD SP,(PARKSTACK) ; RESTORE STACK + 1203 ;;;;; EI ; RE-ENABLE INTERRUPTS + 0484 3E 00 1204 LD A,#0 ; RETURN ERROR CODE WRITE SUCCESSFUL A=0 + 0486 C9 1205 RET ; + 0487 1206 WRITE_IDE_ERROR: ; + 0487 ED 7Br64s0A 1207 LD SP,(PARKSTACK) ; RESTORE STACK + 1208 ;;;;; EI ; RE-ENABLE INTERRUPTS + 048B 3E FF 1209 LD A,#0x0FF ; RETURN ERROR CODE WRITE ERROR A=FF + 048D C9 1210 RET + 1211 + 1212 ;___WRITE_ATAPI__________________________________________________________________________________________ + 1213 ; + 1214 ; WRITE TO ATAPI DEVICE + 1215 ;________________________________________________________________________________________________________ + 048E 1216 WRITE_ATAPI: + 048E 3E 10 1217 LD A,#0x10 ; SET TO SECONDARY DEVICE + 0490 32r17s0B 1218 LD (IDEDEVICE),A ; + 0493 F3 1219 DI ; DISABLE INTERRUPTS + 0494 21 00 00 1220 LD HL,#0 ; + 0497 39 1221 ADD HL,SP ; GET STACK POINTER INTO HL + 0498 22r64s0A 1222 LD (PARKSTACK),HL ; SAVE STACK POINTER + 049B 31r63s0A 1223 LD SP,#FLOPPYSTACK ; + 1224 ; + 049E CDr16s05 1225 CALL CONVERT_IDE_SECTOR_CPM ; + 1226 ; + 04A1 CDrDFs06 1227 CALL ATAPI_READ_SECTOR ; + 04A4 D2rB4s04 1228 JP NC,WRITE_ATAPI_ERROR ; + 04A7 CDrC0s02 1229 CALL BLKSEC ; DEBLOCK SECTOR + 04AA CDr3Cs07 1230 CALL ATAPI_WRITE_SECTOR ; + 1231 ; + 04AD ED 7Br64s0A 1232 LD SP,(PARKSTACK) ; RESTORE STACK + 1233 ;;;;; EI ; RE-ENABLE INTERRUPTS + 04B1 3E 00 1234 LD A,#0 ; RETURN ERROR CODE WRITE SUCCESSFUL A=0 + 04B3 C9 1235 RET ; + 04B4 1236 WRITE_ATAPI_ERROR: ; + 04B4 ED 7Br64s0A 1237 LD SP,(PARKSTACK) ; RESTORE STACK + 1238 ;;;;; EI ; RE-ENABLE INTERRUPTS + 04B8 3E FF 1239 LD A,#0x0FF ; RETURN ERROR CODE WRITE ERROR A=FF + 04BA C9 1240 RET ; + 1241 + 04BB 1242 WRITE_HDPART4: + 1243 ; STUB + 04BB C9 1244 RET + 1245 + 1246 + 1247 ;___PRTMSG_______________________________________________________________________________________________ + 1248 ; + 1249 ; PRINT MESSAGE POINTED TO BY HL ON CONSOLE DEVICE + 1250 ;________________________________________________________________________________________________________ + 04BC 1251 PRTMSG: + 04BC 7E 1252 LD A,(HL) ; GET CHARACTER TO A + 04BD FE FF 1253 CP #END ; TEST FOR END BYTE + 04BF CArCAs04 1254 JP Z,PRTMSG1 ; JUMP IF END BYTE IS FOUND + 04C2 4F 1255 LD C,A ; PUT CHAR TO PRINT VALUE IN REG C FOR CONOUT + 04C3 CDrB1s01 1256 CALL CONOUT ; SEND CHARACTER TO CONSOLE FROM REG C + 04C6 23 1257 INC HL ; INC POINTER, TO NEXT CHAR + 04C7 C3rBCs04 1258 JP PRTMSG ; TRANSMIT LOOP + 04CA 1259 PRTMSG1: + 04CA C9 1260 RET + 1261 + 1262 + 1263 ;___SECPAGE_______________________________________________________________________________________________ + 1264 ; + 1265 ; UTILITY ROUTINE FOR SECTOR TO PAGE ADDRESS + 1266 ;________________________________________________________________________________________________________ + 04CB 1267 SECPAGE: + 04CB 2Ar0As0B 1268 LD HL,(SECTOR) ; GET SECTOR INTO HL + 04CE 29 1269 ADD HL,HL ; SHIFT BITS 1 TO LEFT (*2) + 04CF 29 1270 ADD HL,HL ; SHIFT BITS 1 TO LEFT (*4) + 04D0 29 1271 ADD HL,HL ; SHIFT BITS 1 TO LEFT (*8) + 04D1 29 1272 ADD HL,HL ; SHIFT BITS 1 TO LEFT (*16) + 04D2 29 1273 ADD HL,HL ; SHIFT BITS 1 TO LEFT (*32) + 04D3 29 1274 ADD HL,HL ; SHIFT BITS 1 TO LEFT (*64) + 04D4 29 1275 ADD HL,HL ; SHIFT BITS 1 TO LEFT (*128) + 04D5 22r0Es0B 1276 LD (SECST),HL ; SAVE SECTOR STARTING ADDRESS + 04D8 C9 1277 RET + 1278 + 1279 ;___PAGERB_______________________________________________________________________________________________ + 1280 ; + 1281 ; PAGER BYTE CREATION + 1282 ; ASSEMBLES DRIVE AND TRACK AND SENDS IT TO PAGER PORT + 1283 ;________________________________________________________________________________________________________ + 04D9 1284 PAGERB: + 04D9 2Ar02s0B 1285 LD HL,(TRACK) ; LOAD TRACK INTO HL + 04DC 3Ar12s0B 1286 LD A,(DISKNO) ; LOAD DISK INTO A + 04DF FE 05 1287 CP #5 ; IS ROM? + 04E1 CArF3s04 1288 JP Z,ROMD ; READ FROM 1M ROM DISK + 04E4 FE 06 1289 CP #6 ; IS ROM? + 04E6 CArF3s04 1290 JP Z,ROMD ; READ FROM 22K ROM DISK + 04E9 E6 01 1291 AND #1 ; MASK FOR 1 BIT OF DRIVE SELECT + 04EB 0F 1292 RRCA ; MOVE BIT 0 TO BIT 7 + 04EC B5 1293 OR L ; OR L WITH ACC TO COMBINE TRACK AND DRIVE + 04ED D3 78 1294 OUT (MPCL_RAM),A ; SEND TO RAM PORT MAPPER + 04EF 32r08s0B 1295 LD (PAGER),A ; SAVE COPY (JUST BECAUSE) + 04F2 C9 1296 RET ; + 04F3 1297 ROMD: ; + 04F3 3E 05 1298 LD A,#5 ; + 04F5 E6 01 1299 AND #1 ; MASK FOR 1 BIT OF DRIVE SELECT + 04F7 0F 1300 RRCA ; MOVE BIT 0 TO BIT 7 + 04F8 B5 1301 OR L ; OR L WITH ACC TO COMBINE TRACK AND DRIVE + 04F9 E6 7F 1302 AND #0x7F ; STRIP OFF BIT 7 (ROM_ENABLE BIT) + 04FB D3 7C 1303 OUT (MPCL_ROM),A ; SEND TO ROM PORT MAPPER + 04FD 32r08s0B 1304 LD (PAGER),A ; SAVE COPY (JUST BECAUSE) + 0500 32r09s0B 1305 LD (DB_PAGER),A ; SAVE COPY (JUST BECAUSE) (DEBUG) + 0503 C9 1306 RET + 1307 + 1308 ;___RPAGE_______________________________________________________________________________________________ + 1309 ; + 1310 ; RESET PAGER BACK TO RAM + 1311 ;________________________________________________________________________________________________________ + 0504 1312 RPAGE: + 0504 3E 80 1313 LD A,#0x80 ; DESELECT ROM PAGE + 0506 D3 7C 1314 OUT (MPCL_ROM),A ; SELECT RAM + 0508 3E 00 1315 LD A,#0 ; SET TO RAM, TRACK 0 + 050A D3 78 1316 OUT (MPCL_RAM),A ; SELECT RAM + 050C 32r08s0B 1317 LD (PAGER),A ; SAVE COPY OF PAGER BYTE + 050F C9 1318 RET + 1319 + 1320 ;___COPY_CPM_SECTOR______________________________________________________________________________________ + 1321 ; + 1322 ; COPIES ONE CPM SECTOR FROM ONE MEMORY ADDRESS TO ANOTHER + 1323 ; INPUT + 1324 ; DE SOURCE ADDRESS + 1325 ; HL TARGET ADDRESS + 1326 ; USES C REGISTER + 1327 ;________________________________________________________________________________________________________ + 0510 1328 COPY_CPM_SECTOR: + 0510 01 80 00 1329 LD BC,#128 ; BC IS COUNTER FOR FIXED SIZE TRANSFER (128 BYTES) + 0513 ED B0 1330 LDIR ; TRANSFER + 0515 C9 1331 RET + 1332 + 1333 ;___CONVERT_IDE_SECTOR_CPM________________________________________________________________________________ + 1334 ; + 1335 ; COMPUTES WHERE THE CP/M SECTOR IS IN THE LBA PARTITION + 1336 ; LBA HD SECTORS ARE 512 BYTES EACH, CP/M SECTORS ARE 128 BYTES EACH + 1337 ; MAXIMUM SIZE OF CP/M DISK IS 8 MB = 65536 (16 BITS) X 128 BYTES PER SECTOR + 1338 ; LBA HD PARTITION CAN HAVE AT MOST 16777215 IDE SECTORS -> 67108860 CP/M SECTORS + 1339 ; EACH IDE HD SECTOR CONTAINS 4 ADJACENT CP/M SECTORS + 1340 ; + 1341 ; + 1342 ; INPUT: + 1343 ; - CP/M TRACK AND SECTOR 16 BIT WORDS + 1344 ; + 1345 ; OUTPUT: + 1346 ; IDE TARGET SECTOR (SENT TO IDE HD CONTROLLER FOR READ OPERATION) + 1347 ; - LOWER 16 BITS STORED IN LBA_TARGET_LO + 1348 ; - UPPER 16 BITS STORED IN LBA_TARGET_HI + 1349 ; CP/M TO IDE HD SECTOR MAPPING PARAMETER STORED IN SECTOR_INDEX + 1350 ; - 8 BIT VALUE WITH 4 LEGAL STATES (00, 01, 02, 04) WHICH IS + 1351 ; TO BE USED TO COMPUTE STARTING ADDRESS OF 128 BYTE CP/M SECTOR ONCE + 1352 ; 512 BYTE IDE HD SECTOR READ INTO MEMORY BUFFER + 1353 ; LBA ADDRESS FORMAT = 00TTTTSS + 1354 ; + 1355 ; ROTATE WITH CARRY 16 BIT TRACK,SECTOR VALUE IN HL TO GET 14 BIT IDE HD + 1356 ; TARGET SECTOR IN PARTITION + 1357 ; KEEP LAST TWO BITS IN B FOR IDE HD SECTOR TO CP/M SECTOR TRANSLATION + 1358 ; COMPUTE SECTOR_INDEX + 1359 ;________________________________________________________________________________________________________ + 0516 1360 CONVERT_IDE_SECTOR_CPM: + 1361 + 0516 3Ar02s0B 1362 LD A,(TRACK) ; LOAD TRACK # (LOW BYTE) + 0519 67 1363 LD H,A ; + 051A 3Ar0As0B 1364 LD A,(SECTOR) ; LOAD SECTOR# (LOW BYTE) + 051D 6F 1365 LD L,A ; + 051E CDr61s05 1366 CALL RRA16 ; ROTATE 'HL' RIGHT (DIVIDE BY 2) + 0521 CDr61s05 1367 CALL RRA16 ; ROTATE 'HL' RIGHT (DIVIDE BY 2) + 0524 3Ar03s0B 1368 LD A,(TRACK+1) ; GET HIGH BYTE OF TRACK INTO A + 0527 CB 27 1369 SLA A ; + 0529 CB 27 1370 SLA A ; + 052B CB 27 1371 SLA A ; + 052D CB 27 1372 SLA A ; + 052F CB 27 1373 SLA A ; + 0531 CB 27 1374 SLA A ; + 0533 B4 1375 OR H ; + 0534 67 1376 LD H,A ; + 0535 3Ar03s0B 1377 LD A,(TRACK+1) ; GET HIGH BYTE OF TRACK INTO A + 0538 CB 3F 1378 SRL A ; + 053A CB 3F 1379 SRL A ; + 053C 32r15s0B 1380 LD (LBA_TARGET_HI),A ; + 053F 7D 1381 LD A,L ; + 0540 32r13s0B 1382 LD (LBA_TARGET_LO),A ; LBA REGISTER IS 00TTTTSS / 4 + 0543 7C 1383 LD A,H ; + 0544 32r14s0B 1384 LD (LBA_TARGET_LO+1),A ; + 0547 3E 00 1385 LD A,#0 ; + 0549 32r16s0B 1386 LD (LBA_TARGET_HI+1),A ; + 1387 ; + 054C 2Ar13s0B 1388 LD HL,(LBA_TARGET_LO) ; STORE PHYSICAL SECTOR + 054F 22r0Cs0B 1389 LD (PSECTOR),HL ; + 0552 2Ar15s0B 1390 LD HL,(LBA_TARGET_HI) ; STORE PHYSICAL TRACK + 0555 22r04s0B 1391 LD (PTRACK),HL ; + 0558 3Ar0As0B 1392 LD A,(SECTOR) ; LOAD SECTOR # + 055B E6 03 1393 AND #0b000000011 ; + 055D 32r1Cs0B 1394 LD (SECTOR_INDEX),A ; LOCATES WHERE THE 128 BYTE CP/M SECTOR + 1395 ; IS WITHIN THE 512 BYTE IDE HD SECTOR + 1396 ; COMPUTE WHICH IDE HD SECTOR TO READ TO WITHIN 4 CP/M SECTORS + 1397 ; SHIFTS 16 BIT PARTITION OFFSET TO THE RIGHT 2 BITS AND ADDS RESULT TO + 1398 ; IDE HD PARTITION STARTING SECTOR + 1399 ; SHIFT PARTITION OFFSET RIGHT 1 BIT + 0560 C9 1400 RET + 0561 1401 RRA16: + 0561 37 1402 SCF ; + 0562 3F 1403 CCF ; CLEAR CARRY FLAG + 0563 7C 1404 LD A,H ; 16 BIT ROTATE HL WITH CARRY + 0564 1F 1405 RRA ; + 0565 67 1406 LD H,A ; ROTATE HL RIGHT 1 BIT (DIVIDE BY 2) + 0566 7D 1407 LD A,L ; + 0567 1F 1408 RRA ; + 0568 6F 1409 LD L,A ; + 0569 C9 1410 RET + 1411 + 1412 + 1413 ;___IDE_READ_SECTOR______________________________________________________________________________________ + 1414 ; + 1415 ; READ IDE SECTOR + 1416 ;________________________________________________________________________________________________________ + 056A 1417 IDE_READ_SECTOR: + 056A CDrDCs02 1418 CALL ISCUR ; IS CURRENT SECTOR IN BUFFER? + 056D CAr8Bs05 1419 JP Z,IDE_READ_SECTOR_OK ; + 0570 CDrF3s05 1420 CALL IDE_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + 0573 D0 1421 RET NC ; ERROR, RETURN + 0574 CDr66s06 1422 CALL IDE_SETUP_LBA ; TELL DRIVE WHAT SECTOR IS REQUIRED + 0577 3E 20 1423 LD A,#0x20 ; + 0579 D3 27 1424 OUT (IDESTTS),A ; 020h = IDE 'READ SECTOR' COMMAND + 057B 1425 IDE_SREX: ; + 057B CDrF3s05 1426 CALL IDE_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + 057E D0 1427 RET NC ; ERROR, RETURN + 057F CDr0Fs06 1428 CALL IDE_TEST_ERROR ; ENSURE NO ERROR WAS REPORTED + 0582 D0 1429 RET NC ; ERROR, RETURN + 0583 CDr22s06 1430 CALL IDE_WAIT_BUFFER ; WAIT FOR FULL BUFFER SIGNAL FROM DRIVE + 0586 D0 1431 RET NC ; ERROR, RETURN + 0587 CDr3Cs06 1432 CALL IDE_READ_BUFFER ; GRAB THE 256 WORDS FROM THE BUFFER + 058A 37 1433 SCF ; CARRY = 1 ON RETURN = OPERATION OK + 058B 1434 IDE_READ_SECTOR_OK: ; + 058B 2Ar0Cs0B 1435 LD HL,(PSECTOR) ; STORE PHYSICAL SECTOR IN BUFFER + 058E 22rDEs0F 1436 LD (CUSECTOR),HL ; + 0591 2Ar04s0B 1437 LD HL,(PTRACK) ; STORE PHYSICAL DISK TRACK IN BUFFER + 0594 22rE0s0F 1438 LD (CUTRACK),HL ; + 0597 3Ar12s0B 1439 LD A,(DISKNO) ; STORE CURRENT DRIVE IN BUFFER + 059A 32rDDs0F 1440 LD (CUDISK),A ; + 059D 37 1441 SCF ; CARRY = 1 ON RETURN = OPERATION OK + 059E C9 1442 RET + 1443 + 1444 ;___IDE_WRITE_SECTOR_____________________________________________________________________________________ + 1445 ; + 1446 ; WRITE IDE SECTOR + 1447 ;________________________________________________________________________________________________________ + 059F 1448 IDE_WRITE_SECTOR: + 059F CDrF3s05 1449 CALL IDE_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + 05A2 D0 1450 RET NC ; ERROR, RETURN + 05A3 CDr66s06 1451 CALL IDE_SETUP_LBA ; TELL DRIVE WHAT SECTOR IS REQUIRED + 05A6 3E 30 1452 LD A,#0x30 ; + 05A8 D3 27 1453 OUT (IDESTTS),A ; 030h = IDE 'WRITE SECTOR' COMMAND + 05AA CDrF3s05 1454 CALL IDE_WAIT_BUSY_READY ; + 05AD D0 1455 RET NC ; ERROR, RETURN + 05AE CDr0Fs06 1456 CALL IDE_TEST_ERROR ; ENSURE NO ERROR WAS REPORTED + 05B1 D0 1457 RET NC ; ERROR, RETURN + 05B2 CDr22s06 1458 CALL IDE_WAIT_BUFFER ; WAIT FOR BUFFER READY SIGNAL FROM DRIVE + 05B5 D0 1459 RET NC ; ERROR, RETURN + 05B6 CDr50s06 1460 CALL IDE_WRITE_BUFFER ; SEND 256 WORDS TO DRIVE'S BUFFER + 05B9 CDrF3s05 1461 CALL IDE_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + 05BC D0 1462 RET NC ; ERROR, RETURN + 05BD CDr0Fs06 1463 CALL IDE_TEST_ERROR ; ENSURE NO ERROR WAS REPORTED + 05C0 D0 1464 RET NC ; ERROR, RETURN + 05C1 37 1465 SCF ; CARRY = 1 ON RETURN = OPERATION OK + 05C2 C9 1466 RET + 1467 + 1468 ;___IDE_SOFT_RESET_______________________________________________________________________________________ + 1469 ; + 1470 ; RESET IDE CHANNEL + 1471 ;________________________________________________________________________________________________________ + 05C3 1472 IDE_SOFT_RESET: + 0001 1473 .IF CONDIDESOFT ; + 05C3 3E 06 1474 LD A,#0b000000110 ; NO INTERRUPTS, RESET DRIVE = 1 + 05C5 D3 2E 1475 OUT (IDECTRL),A ; + 05C7 3E 02 1476 LD A,#0b000000010 ; NO INTERRUPTS, RESET DRIVE = 0 + 05C9 D3 2E 1477 OUT (IDECTRL),A ; + 05CB CDrF3s05 1478 CALL IDE_WAIT_BUSY_READY ;THIS TAKES A COUPLE OF SECONDS + 05CE C9 1479 RET + 1480 .ELSE + 1481 ; SKIP THIS IF NO IDE DRIVE WHICH SPEEDS UP REBOOTS AND STARTUPS + 1482 RET + 1483 .ENDIF + 1484 + 1485 ;___ATAPI_WAIT_BUSY_READY________________________________________________________________________________ + 1486 ; + 1487 ; WAIT FOR ATAPI CHANNEL TO BE READY + 1488 ;________________________________________________________________________________________________________ + 05CF 1489 ATAPI_WAIT_BUSY_READY: + 05CF 11 00 00 1490 LD DE,#0 ; CLEAR OUT DE + 05D2 1491 ATAPI_WBSY: ; + 05D2 06 F0 1492 LD B,#0x0F0 ; SETUP TIMEOUT + 05D4 1493 ATAPI_DLP: ; + 05D4 10 FE 1494 DJNZ ATAPI_DLP ; + 05D6 13 1495 INC DE ; + 05D7 7A 1496 LD A,D ; + 05D8 B3 1497 OR E ; + 05D9 28 08 1498 JR Z,ATAPI_TO ; + 05DB DB 27 1499 IN A,(IDESTTS) ; READ ERROR REG + 05DD E6 80 1500 AND #0b010000000 ; MASK OFF BUSY BIT + 05DF 20 F1 1501 JR NZ,ATAPI_WBSY ; WE WANT BUSY(7) TO BE 0 + 05E1 37 1502 SCF ; CARRY 1 = OK + 05E2 C9 1503 RET ; + 05E3 1504 ATAPI_TO: ; + 05E3 AF 1505 XOR A ; CARRY 0 = TIMED OUT + 05E4 C9 1506 RET ; + 1507 + 1508 ;___IDE_WAIT_DRQ_READY___________________________________________________________________________________ + 1509 ; + 1510 ; WAIT FOR IDE CHANNEL TO BE READY + 1511 ;________________________________________________________________________________________________________ + 05E5 1512 IDE_WAIT_DRQ_READY: + 05E5 DB 27 1513 IN A,(IDESTTS) ; READ ERROR REG + 05E7 E6 08 1514 AND #0b000001000 ; MASK OFF RDY BIT + 05E9 28 FA 1515 JR Z,IDE_WAIT_DRQ_READY ; WE WANT DRQ(3) TO BE 1 + 05EB C9 1516 RET + 1517 + 1518 ;___IDE_WAIT_DRQ_ZERO____________________________________________________________________________________ + 1519 ; + 1520 ; WAIT FOR IDE DRQ TO BE ZERO + 1521 ;________________________________________________________________________________________________________ + 05EC 1522 IDE_WAIT_DRQ_ZERO: + 05EC DB 27 1523 IN A,(IDESTTS) ; READ ERROR REG + 05EE E6 08 1524 AND #0b000001000 ; MASK OFF RDY BIT + 05F0 20 FA 1525 JR NZ,IDE_WAIT_DRQ_ZERO ; WE WANT DRQ(3) TO BE 0 + 05F2 C9 1526 RET + 1527 + 1528 ;___IDE_WAIT_BUSY_READY___________________________________________________________________________________ + 1529 ; + 1530 ; WAIT FOR IDE CHANNEL TO BE READY + 1531 ;________________________________________________________________________________________________________ + 05F3 1532 IDE_WAIT_BUSY_READY: + 05F3 11 00 00 1533 LD DE,#0 ; CLEAR DE + 05F6 1534 IDE_WBSY: ; + 05F6 06 05 1535 LD B,#5 ; SETUP TIMEOUT + 05F8 1536 IDE_DLP: ; + 05F8 05 1537 DEC B ; + 05F9 C2rF8s05 1538 JP NZ,IDE_DLP ; + 05FC 13 1539 INC DE ; + 05FD 7A 1540 LD A,D ; + 05FE B3 1541 OR E ; + 05FF CAr0Ds06 1542 JP Z,IDE_TO ; + 0602 DB 27 1543 IN A,(IDESTTS) ; READ ERROR REG + 0604 E6 C0 1544 AND #0b011000000 ; MASK OFF BUSY AND RDY BITS + 0606 EE 40 1545 XOR #0b001000000 ; WE WANT BUSY(7) TO BE 0 AND RDY(6) TO BE 1 + 0608 C2rF6s05 1546 JP NZ,IDE_WBSY ; + 060B 37 1547 SCF ; CARRY 1 = OK + 060C C9 1548 RET + 060D 1549 IDE_TO: + 060D AF 1550 XOR A ; CARRY 0 = TIMED OUT + 060E C9 1551 RET + 1552 + 1553 ;___IDE_TEST_ERROR_______________________________________________________________________________________ + 1554 ; + 1555 ; CHECK FOR IDE ERROR CONDITION + 1556 ;________________________________________________________________________________________________________ + 060F 1557 IDE_TEST_ERROR: + 060F 37 1558 SCF ; + 0610 DB 27 1559 IN A,(IDESTTS) ; + 0612 47 1560 LD B,A ; + 0613 E6 01 1561 AND #0b000000001 ; TEST ERROR BIT + 0615 37 1562 SCF ; + 0616 C8 1563 RET Z ; + 0617 78 1564 LD A,B ; + 0618 E6 20 1565 AND #0b000100000 ; + 061A 37 1566 SCF ; + 061B C2r20s06 1567 JP NZ,IDE_ERR ; TEST WRITE ERROR BIT + 061E DB 21 1568 IN A,(IDEERR) ; READ ERROR FLAGS + 0620 1569 IDE_ERR: + 0620 B7 1570 OR A ; CARRY 0 = ERROR + 0621 C9 1571 RET ; IF A = 0, IDE BUSY TIMED OUT + 1572 + 1573 ;___IDE_WAIT_BUFFER_______________________________________________________________________________________ + 1574 ; + 1575 ; WAIT FOR DATA BUFFER READY + 1576 ;________________________________________________________________________________________________________ + 0622 1577 IDE_WAIT_BUFFER: + 0622 11 00 00 1578 LD DE,#0 ; + 0625 1579 IDE_WDRQ: ; + 0625 06 05 1580 LD B,#5 ; + 0627 1581 IDE_BLP: ; + 0627 05 1582 DEC B ; + 0628 C2r27s06 1583 JP NZ,IDE_BLP ; + 062B 13 1584 INC DE ; + 062C 7A 1585 LD A,D ; + 062D B3 1586 OR E ; + 062E CAr3As06 1587 JP Z,IDE_TO2 ; + 0631 DB 27 1588 IN A,(IDESTTS) ; WAIT FOR DRIVE'S 512 BYTE READ BUFFER + 0633 E6 08 1589 AND #0b000001000 ; TO FILL (OR READY TO FILL) + 0635 CAr25s06 1590 JP Z,IDE_WDRQ ; + 0638 37 1591 SCF ; CARRY 1 = OK + 0639 C9 1592 RET ; + 063A 1593 IDE_TO2: ; + 063A AF 1594 XOR A ; CARRY 0 = TIMED OUT + 063B C9 1595 RET ; + 1596 + 1597 ;___IDE_READ_BUFFER_______________________________________________________________________________________ + 1598 ; + 1599 ; READ IDE BUFFER + 1600 ;________________________________________________________________________________________________________ + 063C 1601 IDE_READ_BUFFER: + 063C E5 1602 PUSH HL ; + 063D 21rE2s0F 1603 LD HL,#SECTOR_BUFFER ; + 0640 06 00 1604 LD B,#0 ; 256 WORDS (512 BYTES PER SECTOR) + 0642 1605 IDEBUFRD: ; + 0642 DB 20 1606 IN A,(IDELO) ; LOW BYTE OF WORD FIRST + 0644 77 1607 LD (HL),A ; + 0645 DB 28 1608 IN A,(IDEHI) ; THEN HIGH BYTE OF WORD + 0647 23 1609 INC HL ; + 0648 77 1610 LD (HL),A ; + 0649 23 1611 INC HL ; + 064A 05 1612 DEC B ; + 064B C2r42s06 1613 JP NZ,IDEBUFRD ; + 064E E1 1614 POP HL ; + 064F C9 1615 RET + 1616 + 1617 ;___IDE_WRITE_BUFFER_______________________________________________________________________________________ + 1618 ; + 1619 ; WRITE TO IDE BUFFER + 1620 ;________________________________________________________________________________________________________ + 0650 1621 IDE_WRITE_BUFFER: + 0650 E5 1622 PUSH HL ; + 0651 21rE2s0F 1623 LD HL,#SECTOR_BUFFER ; + 0654 06 00 1624 LD B,#0 ; 256 WORDS (512 BYTES PER SECTOR) + 0656 1625 IDEBUFWT: + 0656 23 1626 INC HL ; + 0657 7E 1627 LD A,(HL) ; + 0658 2B 1628 DEC HL ; + 0659 D3 28 1629 OUT (IDEHI),A ; SET UP HIGH LATCHED BYTE BEFORE + 065B 7E 1630 LD A,(HL) ; + 065C D3 20 1631 OUT (IDELO),A ; WRITING WORD WITH WRITE TO LOW BYTE + 065E 23 1632 INC HL ; + 065F 23 1633 INC HL ; + 0660 05 1634 DEC B ; + 0661 C2r56s06 1635 JP NZ,IDEBUFWT ; + 0664 E1 1636 POP HL ; + 0665 C9 1637 RET + 1638 + 1639 ;___IDE_SETUP_LDA________________________________________________________________________________________ + 1640 ; + 1641 ; SETUP IDE DRIVE FOR LDA OPERATION + 1642 ;________________________________________________________________________________________________________ + 0666 1643 IDE_SETUP_LBA: + 0666 3Ar13s0B 1644 LD A,(LBA_TARGET_LO) ; LOAD LBA REGISTER 0 WITH SECTOR ADDRESS TO READ + 0669 32r18s0B 1645 LD (IDE_LBA0),A ; + 066C 3Ar14s0B 1646 LD A,(LBA_TARGET_LO+1) ; LOAD LBA REGISTER 1 WITH SECTOR ADDRESS TO READ + 066F 32r19s0B 1647 LD (IDE_LBA1),A ; + 0672 3Ar15s0B 1648 LD A,(LBA_TARGET_HI) ; LOAD LBA REGISTER 2 WITH SECTOR ADDRESS TO READ + 0675 32r1As0B 1649 LD (IDE_LBA2),A ; + 0678 3Ar16s0B 1650 LD A,(LBA_TARGET_HI+1) ; LOAD LBA REGISTER 3 WITH SECTOR ADDRESS TO READ + 067B E6 0F 1651 AND #0b000001111 ; ONLY LOWER FOUR BITS ARE VALID + 067D C6 E0 1652 ADD A,#0b011100000 ; ENABLE LBA BITS 5:7=111 IN IDE_LBA3 + 067F 32r1Bs0B 1653 LD (IDE_LBA3),A ; + 1654 ; READ IDE HD SECTOR + 0682 3E 01 1655 LD A,#1 ; + 0684 D3 22 1656 OUT (IDESECTC),A ; SET SECTOR COUNT = 1 + 1657 ; + 0686 3Ar18s0B 1658 LD A,(IDE_LBA0) ; + 0689 D3 23 1659 OUT (IDESECTN),A ; SET LBA 0:7 + 1660 ; + 068B 3Ar19s0B 1661 LD A,(IDE_LBA1) ; + 068E D3 24 1662 OUT (IDECYLLO),A ; SET LBA 8:15 + 1663 ; + 0690 3Ar1As0B 1664 LD A,(IDE_LBA2) ; + 0693 D3 25 1665 OUT (IDECYLHI),A ; SET LBA 16:23 + 1666 ; + 0695 3Ar1Bs0B 1667 LD A,(IDE_LBA3) ; + 0698 E6 0F 1668 AND #0b000001111 ; LOWEST 4 BITS USED ONLY + 069A F6 E0 1669 OR #0b011100000 ; TO ENABLE LBA MODE + 069C D3 26 1670 OUT (IDEHEAD),A ; SET LBA 24:27 + BITS 5:7=111 + 0000 1671 .IF CONDUSEDSKY + 1672 CALL IDESEGDISPLAY ; + 1673 .ENDIF + 069E C9 1674 RET + 1675 + 1676 ;___ATAPI_SOFT_RESET_____________________________________________________________________________________ + 1677 ; + 1678 ; RESET ATAPI BUS + 1679 ;________________________________________________________________________________________________________ + 069F 1680 ATAPI_SOFT_RESET: + 069F 3E 0E 1681 LD A,#0b000001110 ;NO INTERRUPTS, RESET DRIVE = 1 + 06A1 D3 2E 1682 OUT (IDECTRL),A ; + 06A3 CDrD7s09 1683 CALL DELAY24 ; + 06A6 3E 0A 1684 LD A,#0b000001010 ;NO INTERRUPTS, RESET DRIVE = 0 + 06A8 D3 2E 1685 OUT (IDECTRL),A ; + 06AA CDrCFs05 1686 CALL ATAPI_WAIT_BUSY_READY ; + 06AD D0 1687 RET NC ; ERROR, RETURN + 06AE CDrD7s06 1688 CALL ATAPI_DEVICE_SELECTION ; + 06B1 CDrD7s09 1689 CALL DELAY24 ; + 06B4 CDrB8s06 1690 CALL REQUEST_SENSE_LOOP ; + 06B7 C9 1691 RET + 1692 + 1693 ;___REQUEST_SENSE_LOOP____________________________________________________________________________________ + 1694 ; + 1695 ; ATAPI_REQUEST SENSE DATA + 1696 ;_________________________________________________________________________________________________________ + 06B8 1697 REQUEST_SENSE_LOOP: + 06B8 21r80s0A 1698 LD HL,#ATAPI_REQUEST_SENSE ; + 06BB CDr7Ds07 1699 CALL ATAPI_SEND_PACKET ; + 06BE CDrCFs05 1700 CALL ATAPI_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + 06C1 D0 1701 RET NC ; ERROR, RETURN + 06C2 06 00 1702 LD B,#0 ; 256 WORDS (512 BYTES PER SECTOR) + 06C4 1703 REQUEST_SENSE_LOOP1: ; + 06C4 DB 20 1704 IN A,(IDELO) ; + 06C6 DD 23 1705 INC IX ; + 06C8 DB 28 1706 IN A,(IDEHI) ; + 06CA DD 23 1707 INC IX ; + 06CC 10 F6 1708 DJNZ REQUEST_SENSE_LOOP1 ; + 06CE ED 67 1709 RRD ; DELAY ONLY + 06D0 DB 27 1710 IN A,(IDESTTS) ;READ ERROR REG + 06D2 E6 01 1711 AND #0b000000001 ;MASK OFF BIT + 06D4 20 E2 1712 JR NZ,REQUEST_SENSE_LOOP ; + 06D6 C9 1713 RET + 1714 + 1715 ;___ATAPI_DEVICE_SELECTION________________________________________________________________________________ + 1716 ; + 1717 ; ATAPI DEVICE SELECTION + 1718 ;_________________________________________________________________________________________________________ + 06D7 1719 ATAPI_DEVICE_SELECTION: + 1720 + 06D7 3Ar17s0B 1721 LD A,(IDEDEVICE) ; SELECTS DEVICE + 06DA F6 A0 1722 OR #0x0A0 ; + 06DC D3 26 1723 OUT (IDEHEAD),A ; + 06DE C9 1724 RET ; + 1725 + 1726 + 1727 + 1728 ;__ATAPI_READ_SECTOR_____________________________________________________________________________________________________________ + 1729 ; READ ATAPI SECTOR + 1730 ; + 1731 ; D E H L = SECTOR (DOUBLE WORD) TO READ + 1732 ;________________________________________________________________________________________________________________________________ + 06DF 1733 ATAPI_READ_SECTOR: + 06DF CDrDCs02 1734 CALL ISCUR ; + 06E2 CAr28s07 1735 JP Z,ATAPI_READ_DATA_EXIT ; + 06E5 3Ar13s0B 1736 LD A,(LBA_TARGET_LO) ; LOAD LBA REGISTER 0 WITH SECTOR ADDRESS TO READ + 06E8 32r6Ds0A 1737 LD (READ_DISK_PACKET+5),A ; + 06EB 3Ar14s0B 1738 LD A,(LBA_TARGET_LO+1) ; LOAD LBA REGISTER 1 WITH SECTOR ADDRESS TO READ + 06EE 32r6Cs0A 1739 LD (READ_DISK_PACKET+4),A ; + 06F1 3Ar15s0B 1740 LD A,(LBA_TARGET_HI) ; LOAD LBA REGISTER 2 WITH SECTOR ADDRESS TO READ + 06F4 32r6Bs0A 1741 LD (READ_DISK_PACKET+3),A ; + 06F7 3Ar16s0B 1742 LD A,(LBA_TARGET_HI+1) ; LOAD LBA REGISTER 3 WITH SECTOR ADDRESS TO READ + 06FA 32r6As0A 1743 LD (READ_DISK_PACKET+2),A ; + 0000 1744 .IF CONDUSEDSKY + 1745 CALL ATAPISEGDISPLAY ; + 1746 .ENDIF + 06FD CDrB8s06 1747 CALL REQUEST_SENSE_LOOP ; GET ATAPI SENSE CODES TO CLEAR ERRORS + 0700 21r68s0A 1748 LD HL,#READ_DISK_PACKET ; SET POINTER TO READ SECTOR PACKET + 0703 CDr7Ds07 1749 CALL ATAPI_SEND_PACKET ; SEND PACKET COMMAND + 0706 CDrCFs05 1750 CALL ATAPI_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + 0709 D0 1751 RET NC ; ERROR, RETURN + 070A 06 00 1752 LD B,#0 ; 256 WORDS (512 BYTES PER SECTOR) + 070C DD 21rE2s0F 1753 LD IX,#SECTOR_BUFFER ; + 0710 DB 27 1754 IN A,(IDESTTS) ; READ REG + 0712 E6 08 1755 AND #0b000001000 ; MASK OFF BIT + 0714 FE 08 1756 CP #8 ; IS DATA WAITING? + 0716 20 10 1757 JR NZ,ATAPI_READ_DATA_EXIT ; NO, EXIT + 0718 1758 ATAPI_READ_DATA_LOOP: + 0718 DB 20 1759 IN A,(IDELO) ; + 1760 + 071A DD 77 00 1761 LD (IX),A ; + 1762 + 071D DD 23 1763 INC IX ; + 071F DB 28 1764 IN A,(IDEHI) ; + 1765 + 0721 DD 77 00 1766 LD (IX),A ; + 1767 + 0724 DD 23 1768 INC IX ; + 0726 10 F0 1769 DJNZ ATAPI_READ_DATA_LOOP ; + 0728 1770 ATAPI_READ_DATA_EXIT: ; + 0728 2Ar0Cs0B 1771 LD HL,(PSECTOR) ; STORE PHYSICAL SECTOR IN BUFFER + 072B 22rDEs0F 1772 LD (CUSECTOR),HL ; + 072E 2Ar04s0B 1773 LD HL,(PTRACK) ; STORE PHYSICAL DISK TRACK IN BUFFER + 0731 22rE0s0F 1774 LD (CUTRACK),HL ; + 0734 3Ar12s0B 1775 LD A,(DISKNO) ; STORE CURRENT DRIVE IN BUFFER + 0737 32rDDs0F 1776 LD (CUDISK),A ; + 073A 37 1777 SCF ; CARRY = 1 ON RETURN = OPERATION OK + 073B C9 1778 RET ; + 1779 + 1780 + 1781 + 1782 ;__ATAPI_WRITE_SECTOR_____________________________________________________________________________________________________________ + 1783 ; WRITE ATAPI SECTOR + 1784 ; + 1785 ; D E H L = SECTOR (DOUBLE WORD) TO WRITE + 1786 ;________________________________________________________________________________________________________________________________ + 073C 1787 ATAPI_WRITE_SECTOR: + 1788 + 073C 3Ar13s0B 1789 LD A,(LBA_TARGET_LO) ; LOAD LBA REGISTER 0 WITH SECTOR ADDRESS TO READ + 073F 32r79s0A 1790 LD (WRITE_DISK_PACKET+5),A ; + 0742 3Ar14s0B 1791 LD A,(LBA_TARGET_LO+1) ; LOAD LBA REGISTER 1 WITH SECTOR ADDRESS TO READ + 0745 32r78s0A 1792 LD (WRITE_DISK_PACKET+4),A ; + 0748 3Ar15s0B 1793 LD A,(LBA_TARGET_HI) ; LOAD LBA REGISTER 2 WITH SECTOR ADDRESS TO READ + 074B 32r77s0A 1794 LD (WRITE_DISK_PACKET+3),A ; + 074E 3Ar16s0B 1795 LD A,(LBA_TARGET_HI+1) ; LOAD LBA REGISTER 3 WITH SECTOR ADDRESS TO READ + 0751 32r76s0A 1796 LD (WRITE_DISK_PACKET+2),A ; + 0000 1797 .IF CONDUSEDSKY + 1798 CALL ATAPISEGDISPLAY ; + 1799 .ENDIF + 0754 CDrB8s06 1800 CALL REQUEST_SENSE_LOOP ; + 0757 21r74s0A 1801 LD HL,#WRITE_DISK_PACKET ; SET POINTER TO WRITE PACKET COMMAND + 075A CDr7Ds07 1802 CALL ATAPI_SEND_PACKET ; SEND THE PACKET COMMAND + 075D CDrCFs05 1803 CALL ATAPI_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + 0760 D0 1804 RET NC ; ERROR, RETURN + 0761 06 00 1805 LD B,#0 ; 256 WORDS (512 BYTES PER SECTOR) + 0763 DD 21rE2s0F 1806 LD IX,#SECTOR_BUFFER ; + 0767 1807 ATAPI_WRITE_DATA_LOOP: + 0767 DB 27 1808 IN A,(IDESTTS) ; READ REG + 1809 + 0769 DD 7E 00 1810 LD A,(IX) ; + 1811 + 076C F5 1812 PUSH AF ; + 076D DD 23 1813 INC IX ; + 1814 + 076F DD 7E 00 1815 LD A,(IX) ; + 1816 + 0772 D3 28 1817 OUT (IDEHI),A ; + 0774 F1 1818 POP AF ; + 0775 D3 20 1819 OUT (IDELO),A ; + 0777 DD 23 1820 INC IX ; + 0779 10 EC 1821 DJNZ ATAPI_WRITE_DATA_LOOP ; + 077B 37 1822 SCF ; CARRY = 1 ON RETURN = OPERATION OK + 077C C9 1823 RET ; + 1824 + 1825 + 1826 + 1827 + 1828 ;__ATAPI_SEND_PACKET_____________________________________________________________________________________________________________ + 1829 ; SEND PACKET POINTED TO BY HL TO ATAPI DRIVE + 1830 ; + 1831 ;________________________________________________________________________________________________________________________________ + 077D 1832 ATAPI_SEND_PACKET: + 1833 + 077D CDrCFs05 1834 CALL ATAPI_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + 0780 D0 1835 RET NC ; ERROR, RETURN + 0781 CDrECs05 1836 CALL IDE_WAIT_DRQ_ZERO ; + 1837 ; + 0784 3E 0A 1838 LD A,#0x0A ; + 0786 D3 2E 1839 OUT (IDECTRL),A ; DISABLE INT + 0788 3E 00 1840 LD A,#0 ; + 078A D3 21 1841 OUT (IDEERR),A ; + 078C 3E 00 1842 LD A,#0 ; + 078E D3 22 1843 OUT (IDESECTC),A ; + 0790 3E 00 1844 LD A,#0 ; + 0792 D3 23 1845 OUT (IDESECTN),A ; + 0794 3E 00 1846 LD A,#0 ; + 0796 D3 24 1847 OUT (IDECYLLO),A ; + 0798 3E 60 1848 LD A,#0x60 ; + 079A D3 25 1849 OUT (IDECYLHI),A ; + 079C 3Ar17s0B 1850 LD A,(IDEDEVICE) ; + 079F D3 26 1851 OUT (IDEHEAD),A ; BIT 4 SELECTS DEVICE + 07A1 3E A0 1852 LD A,#0x0A0 ; + 07A3 D3 27 1853 OUT (IDESTTS),A ; + 1854 ; + 07A5 CDrE5s05 1855 CALL IDE_WAIT_DRQ_READY ; MAKE SURE DRIVE IS READY TO PROCEED + 1856 ; + 07A8 06 06 1857 LD B,#6 ; SEND 12 BYTES (6 WORDS) + 1858 ; + 07AA 1859 ATAPI_SEND_PACKET_LOOP: + 07AA 7E 1860 LD A,(HL) ; GET BYTE + 07AB 57 1861 LD D,A ; STORE LOW BYTE IN D + 07AC 23 1862 INC HL ; INC POINTER + 07AD 7E 1863 LD A,(HL) ; GET HIGH BYTE + 07AE D3 28 1864 OUT (IDEHI),A ; STORE HIGH BYTE + 07B0 7A 1865 LD A,D ; MOVE LOW BYTE INTO A + 07B1 D3 20 1866 OUT (IDELO),A ; STORE LOW BYTE + 07B3 23 1867 INC HL ; INC POINTER + 07B4 DB 2E 1868 IN A,(IDECTRL) ; GET STATUS + 07B6 10 F2 1869 DJNZ ATAPI_SEND_PACKET_LOOP ; LOOP + 1870 ; + 07B8 CDrCFs05 1871 CALL ATAPI_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + 07BB D0 1872 RET NC ; ERROR, RETURN + 07BC DB 2E 1873 IN A,(IDECTRL) ; READ STATUS (FOR DELAY) + 1874 ; + 07BE C9 1875 RET ; + 1876 + 1877 ;__SETUPDRIVE__________________________________________________________________________________________________________________________ + 1878 ; + 1879 ; SETUP FLOPPY DRIVE SETTINGS + 1880 ;________________________________________________________________________________________________________________________________ + 1881 ; + 07BF 1882 SETUPDRIVE: + 07BF 3E 02 1883 LD A,#RESETL ; RESET SETTINGS + 0000 1884 .IF COND144FLOPPY-1 + 1885 OR MINI ; SELECT MINI FLOPPY (LOW DENS=1, HIGH DENS=0) + 1886 .ENDIF + 07C1 F6 20 1887 OR #PRECOMP ; SELECT PRECOMP + 07C3 F6 40 1888 OR #FDDENSITY ; SELECT DENSITY + 07C5 F6 80 1889 OR #FDREADY ; SELECT READY SIGNAL + 07C7 32r01s0B 1890 LD (FLATCH_STORE),A ; SAVE SETTINGS + 07CA 3E 01 1891 LD A,#1 ; + 07CC 32rEAs0A 1892 LD (UNIT),A ; SET UNIT 1 + 07CF 3E 02 1893 LD A,#2 ; DENSITY + 07D1 32rECs0A 1894 LD (DENS),A ; + 07D4 3E 09 1895 LD A,#9 ; + 0001 1896 .IF COND144FLOPPY + 07D6 87 1897 ADD A,A + 1898 .ENDIF + 07D7 32rEDs0A 1899 LD (EOTSEC),A ; LAST SECTOR OF TRACK + 07DA 3E 7F 1900 LD A,#0x7F ; + 07DC 32rF2s0A 1901 LD (SRTHUT),A ; STEP RATE AND HEAD UNLOAD TIME + 07DF 3E 05 1902 LD A,#5 ; + 07E1 32rF3s0A 1903 LD (HLT),A ; HEAD LOAD TIME + 07E4 3E 0D 1904 LD A,#0x0D ; + 07E6 32rEEs0A 1905 LD (GAP),A ; GAP + 1906 ;; LD A,#0x80 ; + 1907 ;; LD (SECSIZ),A ; SECTOR SIZE /4 + 1908 ; + 07E9 CDrE4s09 1909 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 07EC CDrE4s09 1910 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 07EF CDrE4s09 1911 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 07F2 CDrE4s09 1912 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 07F5 CDrE4s09 1913 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 07F8 CDrE4s09 1914 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 1915 ; + 07FB 21r01s0B 1916 LD HL,#FLATCH_STORE ; POINT TO FLATCH + 07FE CB 8E 1917 RES 1,(HL) ; SET MOTOR ON + 0800 CDr18s08 1918 CALL OUTFLATCH ; OUTPUT TO CONTROLLER + 0803 00 1919 NOP ; + 0804 00 1920 NOP ; + 0805 3E 00 1921 LD A,#0 ; ZERO TRACK + 0807 32r04s0B 1922 LD (PTRACK),A ; STORE TRACK + 080A CDr24s09 1923 CALL SETTRACK ; DO IT + 080D 00 1924 NOP ; + 080E 00 1925 NOP ; + 080F 21r01s0B 1926 LD HL,#FLATCH_STORE ; POINT TO FLATCH + 0812 CB CE 1927 SET 1,(HL) ; SET MOTOR OFF + 0814 CDr18s08 1928 CALL OUTFLATCH ; OUTPUT TO CONTROLLER + 0817 C9 1929 RET + 1930 ; + 1931 ;__OUTFLATCH__________________________________________________________________________________________________________________________ + 1932 ; + 1933 ; SEND SETTINGS TO FLOPPY CONTROLLER + 1934 ;________________________________________________________________________________________________________________________________ + 1935 ; + 0818 1936 OUTFLATCH: + 0818 3Ar01s0B 1937 LD A,(FLATCH_STORE) ; SET A TO SETTINGS + 081B D3 3A 1938 OUT (FLATCH),A ; OUTPUT TO CONTROLLER + 081D C9 1939 RET + 1940 + 1941 ;__FLOPPYREAD__________________________________________________________________________________________________________________________ + 1942 ; + 1943 ; READ A FLOPPY DISK SECTOR + 1944 ;________________________________________________________________________________________________________________________________ + 1945 ; + 081E 1946 FLOPPYREAD: + 0000 1947 .IF CONDUSEDSKY + 1948 CALL SEGDISPLAY ; + 1949 .ENDIF + 081E 3E 46 1950 LD A,#0x46 ; BIT 6 SETS MFM, 06H IS READ COMMAND + 0820 32rE9s0A 1951 LD (CMD),A ; + 0823 C3r2Es08 1952 JP DSKOP ; + 1953 ; + 1954 ;__FLOPPYWRITE__________________________________________________________________________________________________________________________ + 1955 ; + 1956 ; WRITE A FLOPPY DISK SECTOR + 1957 ;________________________________________________________________________________________________________________________________ + 1958 ; + 0826 1959 FLOPPYWRITE: + 0000 1960 .IF CONDUSEDSKY + 1961 CALL SEGDISPLAY ; + 1962 .ENDIF + 0826 3E 45 1963 LD A,#0x45 ; BIT 6 SETS MFM, 05H IS WRITE COMMAND + 0828 32rE9s0A 1964 LD (CMD),A ; + 082B C3r2Es08 1965 JP DSKOP ; + 1966 ; + 1967 ;__DSKOP__________________________________________________________________________________________________________________________ + 1968 ; + 1969 ; PERFORM A DISK OPERATION + 1970 ;________________________________________________________________________________________________________________________________ + 1971 ; + 082E 1972 DSKOP: + 082E 21r01s0B 1973 LD HL,#FLATCH_STORE ; POINT TO FLATCH + 0831 CB CE 1974 SET 1,(HL) ; SET MOTOR OFF + 0833 CDr18s08 1975 CALL OUTFLATCH ; OUTPUT TO CONTROLLER + 1976 ; + 0836 CDrE4s09 1977 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 0839 FE FF 1978 CP #0x0FF ; DID IT RETURN WITH ERROR CODE? + 083B CAr75s08 1979 JP Z,DSKEXIT ; IF YES, EXIT WITH ERROR CODE + 1980 ; + 083E 3ArEAs0A 1981 LD A,(UNIT) ; GET DISK UNIT NUMBER + 0841 E6 03 1982 AND #3 ; MASK FOR FOUR DRIVES + 0843 47 1983 LD B,A ; PARK IT IN B + 0844 3ArEBs0A 1984 LD A,(HEAD) ; GET HEAD SELECTION + 0847 E6 01 1985 AND #1 ; INSURE SINGLE BIT + 0849 17 1986 RLA ; + 084A 17 1987 RLA ; MOVE HEAD TO BIT 2 POSITION + 084B B0 1988 OR B ; OR HEAD TO UNIT BYTE IN COMMAND BLOCK + 084C 32rEAs0A 1989 LD (UNIT),A ; STORE IN UNIT + 1990 ; + 084F 21r01s0B 1991 LD HL,#FLATCH_STORE ; POINT TO FLATCH + 0852 CB 8E 1992 RES 1,(HL) ; SET MOTOR ON + 0854 CDr18s08 1993 CALL OUTFLATCH ; OUTPUT TO CONTROLLER + 1994 ; + 0857 3E 03 1995 LD A,#3 ; SPECIFY COMMAND + 0859 CDrC2s09 1996 CALL PFDATA ; PUSH IT + 085C 3ArF2s0A 1997 LD A,(SRTHUT) ; STEP RATE AND HEAD UNLOAD TIME + 085F CDrC2s09 1998 CALL PFDATA ; PUSH THAT + 0862 3ArF3s0A 1999 LD A,(HLT) ; + 0865 CDrC2s09 2000 CALL PFDATA ; PUSH THAT + 2001 ; + 0868 CDr24s09 2002 CALL SETTRACK ; PERFORM SEEK TO TRACK + 2003 ; + 086B C2r75s08 2004 JP NZ,DSKEXIT ; IF ERROR, EXIT + 2005 ; + 086E 3ArE9s0A 2006 LD A,(CMD) ; WHAT COMMAND IS PENDING? + 0871 B7 2007 OR A ; SET FLAGS + 0872 C3rA4s08 2008 JP DOSO4 ; NO, MUST BE READ OR WRITE COMMAND + 0875 2009 DSKEXIT: + 0875 21r01s0B 2010 LD HL,#FLATCH_STORE ; POINT TO FLATCH + 0878 CB CE 2011 SET 1,(HL) ; SET MOTOR OFF + 087A CDr18s08 2012 CALL OUTFLATCH ; OUTPUT TO CONTROLLER + 2013 ; + 087D F6 FF 2014 OR #0x0FF ; SET -1 IF ERROR + 087F C9 2015 RET + 2016 + 0880 2017 RESULT: + 0880 0E 07 2018 LD C,#7 ; LOAD C WITH NUMBER OF STATUS BYTES + 0882 21rF6s0A 2019 LD HL,#ST0 ; POINT TO STATS STORAGE + 0885 2020 RS3: + 0885 CDr30s0A 2021 CALL GFDATA ; GET FIRST BYTE + 0888 77 2022 LD (HL),A ; SAVE IT + 0889 23 2023 INC HL ; POINTER++ + 088A 0D 2024 DEC C ; CC-1 + 088B C2r85s08 2025 JP NZ,RS3 ; LOOP TIL C0 + 088E 3ArF6s0A 2026 LD A,(ST0) ; LOAD STS0 + 0891 E6 F8 2027 AND #0x0F8 ; MASK OFF DRIVE # + 0893 47 2028 LD B,A ; PARK IT + 0894 3ArF7s0A 2029 LD A,(ST1) ; LOAD STS1 + 0897 B0 2030 OR B ; ACC OR B ->ACC IF 0 THEN SUCCESS + 2031 ; + 0898 2032 RSTEXIT: + 0898 CDrE4s09 2033 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 089B 21r01s0B 2034 LD HL,#FLATCH_STORE ; POINT TO FLATCH + 089E CB CE 2035 SET 1,(HL) ; SET MOTOR OFF + 08A0 CDr18s08 2036 CALL OUTFLATCH ; OUTPUT TO CONTROLLER + 2037 ; + 0000 2038 .IF CONDUSEDSKY + 2039 CALL SEGDISPLAY ; + 2040 .ENDIF + 08A3 C9 2041 RET ; DONE RETURN TO CALLER + 2042 + 2043 + 08A4 2044 DOSO4: + 2045 ; + 0001 2046 .IF 1 ; + 0038 2047 INT_LOC = 0x038 ; IM 1 INTERRUPT CALLS GO HERE + 2048 ; SET UP FOR I/O AT INTERRUPT LEVEL + 08A4 11 38 00 2049 LD DE,#INT_LOC + 08A7 21r1Es09 2050 LD HL,#INT_RD + 08AA 01 03 00 2051 LD BC,#L_INT_RD + 08AD 3ArE9s0A 2052 LD A,(CMD) ; + 08B0 E6 01 2053 AND #0b000000001 ; WRITE IS 1 + 08B2 CArB6s08 2054 JP Z,IS_READ + 08B5 09 2055 ADD HL,BC + 08B6 2056 IS_READ: + 08B6 ED B0 2057 LDIR + 2058 .ENDIF + 2059 + 08B8 21rE2s0F 2060 LD HL,#SECTOR_BUFFER ; GET BUFFER ADDRESS TO HL + 2061 ;; LD A,(SECSIZ) ; XFERLEN + 2062 ;; LD C,A ; C WILL BE THE NUMBER OF TRANSACTIONS + 2063 ; DIVIDED BY 4 + 2064 + 08BB ED 5BrEFs0A 2065 ld de,(FSECSIZ) ; GET FULL SECTOR SIZE + 08BF 43 2066 LD B,E + 08C0 0E 37 2067 LD C,#FDATA ; GET DATA REGISTER I/O ADDRESS + 2068 + 08C2 3ArE9s0A 2069 LD A,(CMD) ; + 08C5 CDrC2s09 2070 CALL PFDATA ; PUSH COMMAND TO I8272 + 08C8 3ArEAs0A 2071 LD A,(UNIT) ; + 08CB CDrC2s09 2072 CALL PFDATA ; + 08CE 3Ar04s0B 2073 LD A,(PTRACK) ; + 08D1 CDrC2s09 2074 CALL PFDATA ; + 08D4 3ArEBs0A 2075 LD A,(HEAD) ; + 08D7 CDrC2s09 2076 CALL PFDATA ; + 08DA 3Ar0Cs0B 2077 LD A,(PSECTOR) ; + 08DD 3C 2078 INC A ; + 08DE CDrC2s09 2079 CALL PFDATA ; + 08E1 3ArECs0A 2080 LD A,(DENS) ; + 08E4 CDrC2s09 2081 CALL PFDATA ; WHAT DENSITY + 08E7 3ArEDs0A 2082 LD A,(EOTSEC) ; + 08EA CDrC2s09 2083 CALL PFDATA ; ASSUME SC (SECTOR COUNT) EOT + 08ED 3ArEEs0A 2084 LD A,(GAP) ; + 08F0 CDrC2s09 2085 CALL PFDATA ; WHAT GAP IS NEEDED + 08F3 3ArF1s0A 2086 LD A,(DTL) ; DTL, IS THE LAST COMMAND BYTE TO I8272 + 08F6 CDrAFs09 2087 CALL PFDATAS ; + 2088 ; + 2089 ; + 2090 ; PERFORM READ / WRITE + 2091 ; + 2092 + 2093 + 08F9 2094 RDD_POLL: + 2095 + 08F9 2096 FDC_RW_P0: + 08F9 FB 2097 EI + 08FA 76 2098 HALT + 08FB C2rF9s08 2099 JP NZ,FDC_RW_P0 ;10 COUNT THRU 256 BYTES + 08FE 2100 FDC_RW_P1: + 08FE FB 2101 EI + 08FF 76 2102 HALT + 0900 C2rFEs08 2103 JP NZ,FDC_RW_P1 ;10 COUNT THRU 256 BYTES + 2104 + 2105 + 2106 ; FALL THROUGH WITH INTERRUPTS DISABLED (NOT ENABLED IN INTERRUPT SERVICE) + 2107 + 2108 + 0903 2109 DSKOPEND: + 0903 21r01s0B 2110 LD HL,#FLATCH_STORE ; POINT TO FLATCH + 0906 CB C6 2111 SET 0,(HL) ; SET TC + 0908 CDr18s08 2112 CALL OUTFLATCH ; OUTPUT TO CONTROLLER + 090B 00 2113 NOP ; + 090C 00 2114 NOP ; 2 MICROSECOND DELAY + 090D CB 86 2115 RES 0,(HL) ; RESET TC + 090F CDr18s08 2116 CALL OUTFLATCH ; OUTPUT TO CONTROLLER + 0912 00 2117 NOP ; + 0913 00 2118 NOP ; 2 MICROSECOND DELAY + 0914 00 2119 NOP ; + 0915 00 2120 NOP ; 2 MICROSECOND DELAY + 0916 CB CE 2121 SET 1,(HL) ; TURN OFF MOTOR + 0918 CDr18s08 2122 CALL OUTFLATCH ; OUTPUT TO CONTROLLER + 091B C3r80s08 2123 JP RESULT ; GET STATUS BYTES + 2124 + 2125 + 2126 + 091E ED A2 2127 INT_RD: INI + 0920 C9 2128 RET + 0921 2129 IRTEMP: + 0003 2130 L_INT_RD = IRTEMP - INT_RD + 2131 + 0921 ED A3 2132 INT_WR: OUTI + 0923 C9 2133 RET + 0924 2134 IWTEMP: + 0003 2135 L_INT_WR = IWTEMP - INT_WR + 2136 + 2137 + 2138 + 2139 ;__SETTRACK__________________________________________________________________________________________________________________________ + 2140 ; + 2141 ; SEEK TO A TRACK ON GIVEN UNIT + 2142 ; A: TRACK # + 2143 ;________________________________________________________________________________________________________________________________ + 2144 ; + 0924 2145 SETTRACK: + 0924 3Ar06s0B 2146 LD A,(FTRACK) ; GET CURRENT HEAD TRACK + 0927 4F 2147 LD C,A + 0928 3Ar04s0B 2148 LD A,(PTRACK) ; GET TRACK + 092B B7 2149 OR A ; SET FLAGS + 092C CAr4As09 2150 JP Z,RECAL ; IF 0 PERFORM RECAL INSTEAD OF SEEK + 092F B9 2151 CP C ; + 0930 CAr5As09 2152 JP Z,WAINT ; ALREADY THERE, ABORT + 0933 32r06s0B 2153 LD (FTRACK),A ; STORE TRACK + 0936 3E 0F 2154 LD A,#0x0F ; SEEK COMMAND + 0938 CDrC2s09 2155 CALL PFDATA ; PUSH COMMAND + 093B 3ArEAs0A 2156 LD A,(UNIT) ; SAY WHICH UNIT + 093E CDrC2s09 2157 CALL PFDATA ; SEND THAT + 0941 3Ar04s0B 2158 LD A,(PTRACK) ; TO WHAT TRACK + 0944 CDrC2s09 2159 CALL PFDATA ; SEND THAT TOO + 0947 C3r5As09 2160 JP WAINT ; WAIT FOR INTERRUPT SAYING DONE + 094A 2161 RECAL: + 094A 3E 00 2162 LD A,#0 ; + 094C 32r06s0B 2163 LD (FTRACK),A ; STORE TRACK + 094F 3E 07 2164 LD A,#7 ; RECAL TO TRACK 0 + 0951 CDrC2s09 2165 CALL PFDATA ; SEND IT + 0954 3ArEAs0A 2166 LD A,(UNIT) ; WHICH UNIT + 0957 CDrC2s09 2167 CALL PFDATA ; SEND THAT TOO + 2168 ; + 095A 2169 WAINT: + 2170 ; + 095A CDrF6s09 2171 CALL DELAYHSEC ; DELAY TO LET HEADS SETTLE BEFORE READ + 2172 ; + 2173 ; WAIT HERE FOR INTERRPT SAYING DONE + 2174 ; LOOP TIL INTERRUPT + 095D CDrE4s09 2175 CALL CHECKINT ; CHECK INTERRUPT STATUS + 2176 ; + 0960 C9 2177 RET + 2178 + 2179 ;__CYCLEFLOPPY__________________________________________________________________________________________________________________________ + 2180 ; + 2181 ; SEEK TO TRACK 0, THEN BACK TO THE SELECTED TRACK + 2182 ; THIS CAN BE USED ON AN ERROR CONDITION TO VERIFY THAT HEAD IS ON SELECTED TRACK + 2183 ; + 2184 ;________________________________________________________________________________________________________________________________ + 2185 ; + 0961 2186 CYCLEFLOPPY: + 0961 F5 2187 PUSH AF ; STORE AF + 0962 E5 2188 PUSH HL ; STORE HL + 0963 CDrE4s09 2189 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 0966 CDrE4s09 2190 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 0969 CDrE4s09 2191 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 096C CDrE4s09 2192 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 096F CDrE4s09 2193 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 0972 CDrE4s09 2194 CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + 0975 21r01s0B 2195 LD HL,#FLATCH_STORE ; POINT TO FLATCH + 0978 CB 8E 2196 RES 1,(HL) ; SET MOTOR ON + 097A CDr18s08 2197 CALL OUTFLATCH ; OUTPUT TO CONTROLLER + 097D 00 2198 NOP ; + 097E 00 2199 NOP ; + 097F CDr4As09 2200 CALL RECAL ; + 0982 CDrF6s09 2201 CALL DELAYHSEC ; + 0985 CDrF6s09 2202 CALL DELAYHSEC ; + 0988 CDrF6s09 2203 CALL DELAYHSEC ; + 098B CDrF6s09 2204 CALL DELAYHSEC ; + 098E CDr4As09 2205 CALL RECAL ; + 0991 CDrF6s09 2206 CALL DELAYHSEC ; + 0994 CDrF6s09 2207 CALL DELAYHSEC ; + 0997 CDrF6s09 2208 CALL DELAYHSEC ; + 099A CDrF6s09 2209 CALL DELAYHSEC ; + 099D CDr24s09 2210 CALL SETTRACK ; + 09A0 CDrF6s09 2211 CALL DELAYHSEC ; + 09A3 CDrF6s09 2212 CALL DELAYHSEC ; + 09A6 CDrF6s09 2213 CALL DELAYHSEC ; + 09A9 CDrF6s09 2214 CALL DELAYHSEC ; + 09AC E1 2215 POP HL ; + 09AD F1 2216 POP AF ; RESTORE AF + 09AE C9 2217 RET + 2218 + 2219 ;__PFDATAS__________________________________________________________________________________________________________________________ + 2220 ; + 2221 ; WRITE A COMMAND OR PARAMETER SEQUENCE + 2222 ; + 2223 ; TRANSFERS ARE SYNCHONIZED BYT MSR D7 AND D6 + 2224 ; RQM DIO + 2225 ; 0 0 BUSY + 2226 ; 1 0 WRITE TO DATA REGISTER PERMITTED + 2227 ; 1 1 BYTE FOR READ BY HOST PENDING + 2228 ; 0 1 BUSY + 2229 ; + 2230 ;________________________________________________________________________________________________________________________________ + 2231 ; + 09AF 2232 PFDATAS: + 09AF F5 2233 PUSH AF ; STORE AF + 09B0 2234 PFDS1: + 09B0 DB 36 2235 IN A,(FMSR) ; READING OR WRITING IS KEYS TO D7 RQM + 09B2 E6 80 2236 AND #0x80 ; MASK OFF RQM BIT + 09B4 CArB0s09 2237 JP Z,PFDS1 ; WAIT FOR RQM TO BE TRUE + 09B7 DB 36 2238 IN A,(FMSR) ; READ STATUS + 09B9 E6 40 2239 AND #0x40 ; WAITING FOR INPUT? + 09BB C4r06s0A 2240 CALL NZ,ERRORT ; NO, SIGNAL ERROR + 09BE F1 2241 POP AF ; RESTORE AF + 09BF D3 37 2242 OUT (FDATA),A ; OUTPUT A TO CONTROLLER + 09C1 C9 2243 RET + 2244 + 2245 ;__PFDATA__________________________________________________________________________________________________________________________ + 2246 ; + 2247 ; WRITE A COMMAND OR PARAMETER SEQUENCE + 2248 ; + 2249 ; TRANSFERS ARE SYNCHONIZED BYT MSR D7 AND D6 + 2250 ; RQM DIO + 2251 ; 0 0 BUSY + 2252 ; 1 0 WRITE TO DATA REGISTER PERMITTED + 2253 ; 1 1 BYTE FOR READ BY HOST PENDING + 2254 ; 0 1 BUSY + 2255 ; + 2256 ;________________________________________________________________________________________________________________________________ + 2257 ; + 09C2 2258 PFDATA: + 09C2 F5 2259 PUSH AF ; STORE AF + 09C3 2260 PFD1: + 09C3 DB 36 2261 IN A,(FMSR) ; READING OR WRITING IS KEYS TO D7 RQM + 09C5 E6 80 2262 AND #0x80 ; MASK OFF RQM BIT + 09C7 CArC3s09 2263 JP Z,PFD1 ; WAIT FOR RQM TO BE TRUE + 09CA DB 36 2264 IN A,(FMSR) ; READ STATUS + 09CC E6 40 2265 AND #0x40 ; WAITING FOR INPUT? + 09CE C4r06s0A 2266 CALL NZ,ERRORT ; NO, SIGNAL ERROR + 09D1 F1 2267 POP AF ; RESTORE AF + 09D2 D3 37 2268 OUT (FDATA),A ; OUTPUT A TO CONTROLLER + 09D4 C3rD7s09 2269 JP DELAY24 ; DELAY 24US + 2270 + 2271 + 2272 + 2273 ;__DELAY24__________________________________________________________________________________________________________________________ + 2274 ; + 2275 ; DELAY 24US + 2276 ;________________________________________________________________________________________________________________________________ + 2277 ; + 09D7 2278 DELAY24: + 2279 ; JP= 10T + 09D7 DD E5 2280 PUSH IX ; 15T + 09D9 DD E1 2281 POP IX ; 14T + 09DB DD E5 2282 PUSH IX ; 15T + 09DD DD E1 2283 POP IX ; 14T + 09DF 2284 DELAY12: + 09DF DD E5 2285 PUSH IX ; 15T + 09E1 DD E1 2286 POP IX ; 14T + 09E3 C9 2287 RET ; 10T + 2288 + 2289 + 2290 ;__CHECKINT__________________________________________________________________________________________________________________________ + 2291 ; + 2292 ; CHECK FOR ACTIVE FDC INTERRUPTS BEFORE GIVING I8272 COMMANDS + 2293 ; POLL RQM FOR WHEN NOT BUSY AND THEN SEND FDC + 2294 ; SENSE INTERRUPT COMMAND IF IT RETURNS WITH NON ZERO + 2295 ; ERROR CODE, PASS BACK TO CALLING ROUTINE FOR HANDLING + 2296 ;________________________________________________________________________________________________________________________________ + 2297 ; + 09E4 2298 CHECKINT: + 09E4 DB 36 2299 IN A,(FMSR) ; READING OR WRITING IS KEYS TO D7 RQM + 09E6 E6 80 2300 AND #0x80 ; MASK OFF RQM BIT + 09E8 CArE4s09 2301 JP Z,CHECKINT ; WAIT FOR RQM TO BE TRUE WAIT UNTIL DONE + 09EB DB 36 2302 IN A,(FMSR) ; READ STATUS + 09ED E6 40 2303 AND #0x40 ; WAITING FOR INPUT? + 09EF C2rF5s09 2304 JP NZ,CHECKINTDONE ; NO, SIGNAL ERROR + 09F2 CDr12s0A 2305 CALL SENDINT ; SENSE INTERRUPT COMMAND + 09F5 2306 CHECKINTDONE: + 09F5 C9 2307 RET ; + 2308 + 2309 + 2310 ;__DELAYHSEC__________________________________________________________________________________________________________________________ + 2311 ; + 2312 ; DELAY FOR 1/2 SECOND + 2313 ;________________________________________________________________________________________________________________________________ + 2314 ; + 09F6 2315 DELAYHSEC: + 09F6 21 00 00 2316 LD HL,#0 ; 65536 + 09F9 2317 DELDM: + 09F9 00 2318 NOP ; (4 T) + 09FA 00 2319 NOP ; (4 T) + 09FB 00 2320 NOP ; (4 T) + 09FC 00 2321 NOP ; (4 T) + 09FD 2D 2322 DEC L ; (6 T) + 09FE C2rF9s09 2323 JP NZ,DELDM ; (10 T) 24 T 8 MICROSECONDS AT 4 MHZ + 0A01 25 2324 DEC H ; (6 T) + 0A02 C2rF9s09 2325 JP NZ,DELDM ; (10 T) (8 US * 256) * 256 524288 US 5 SECONDS + 0A05 C9 2326 RET + 2327 + 2328 ;__ERRORT__________________________________________________________________________________________________________________________ + 2329 ; + 2330 ; ERROR HANDLING + 2331 ;________________________________________________________________________________________________________________________________ + 2332 ; + 0A06 2333 ERRORT: + 0A06 DB 37 2334 IN A,(FDATA) ; CLEAR THE JUNK OUT OF DATA REGISTER + 0A08 DB 36 2335 IN A,(FMSR) ; CHECK WITH RQM + 0A0A E6 80 2336 AND #0x80 ; IF STILL NOT READY, READ OUT MORE JUNK + 0A0C CAr06s0A 2337 JP Z,ERRORT ; + 0A0F 3E FF 2338 LD A,#0x0FF ; RETURN ERROR CODE -1 + 2339 ; + 0A11 C9 2340 RET + 2341 + 2342 ;__SENDINT__________________________________________________________________________________________________________________________ + 2343 ; + 2344 ; SENSE INTERRUPT COMMAND + 2345 ;________________________________________________________________________________________________________________________________ + 2346 ; + 0A12 2347 SENDINT: + 0A12 3E 08 2348 LD A,#8 ; SENSE INTERRUPT COMMAND + 0A14 CDrC2s09 2349 CALL PFDATA ; SEND IT + 0A17 CDr30s0A 2350 CALL GFDATA ; GET RESULTS + 0A1A 32rFDs0A 2351 LD (ST0A),A ; STORE THAT + 0A1D E6 C0 2352 AND #0x0C0 ; MASK OFF INTERRUPT STATUS BITS + 0A1F FE 80 2353 CP #0x80 ; CHECK IF INVALID COMMAND + 0A21 CAr2Fs0A 2354 JP Z,ENDSENDINT ; YES, EXIT + 0A24 CDr30s0A 2355 CALL GFDATA ; GET ANOTHER (STATUS CODE 1) + 0A27 32rFEs0A 2356 LD (ST1A),A ; SAVE THAT + 0A2A 3ArFDs0A 2357 LD A,(ST0A) ; GET FIRST ONE + 0A2D E6 C0 2358 AND #0x0C0 ; MASK OFF ALL BUT INTERRUPT CODE 00 IS NORMAL + 0A2F 2359 ENDSENDINT: + 0A2F C9 2360 RET ; ANYTHING ELSE IS AN ERROR + 2361 + 2362 + 2363 ;__GFDATA__________________________________________________________________________________________________________________________ + 2364 ; + 2365 ; GET DATA FROM FLOPPY CONTROLLER + 2366 ; + 2367 ; TRANSFERS ARE SYNCHONIZED BYT MSR D7 AND D6 + 2368 ; RQM DIO + 2369 ; 0 0 BUSY + 2370 ; 1 0 WRITE TO DATA REGISTER PERMITTED + 2371 ; 1 1 BYTE FOR READ BY HOST PENDING + 2372 ; 0 1 BUSY + 2373 ; + 2374 ;________________________________________________________________________________________________________________________________ + 2375 ; + 0A30 2376 GFDATA: + 0A30 DB 36 2377 IN A,(FMSR) ; READ STATUS BYTE + 0A32 E6 80 2378 AND #0x80 ; MASK OFF RQM + 0A34 CAr30s0A 2379 JP Z,GFDATA ; LOOP WHILE BUSY + 0A37 DB 36 2380 IN A,(FMSR) ; READ STSTUS BUTE + 0A39 E6 40 2381 AND #0x40 ; MASK OFF DIO + 0A3B CCr06s0A 2382 CALL Z,ERRORT ; IF WRITE EXPECTED RUN ERRORRT + 0A3E DB 37 2383 IN A,(FDATA) ; READ DATA + 0A40 C3rD7s09 2384 JP DELAY24 ; DELAY 24US + 2385 + 2386 + 2387 + 0000 2388 .IF CONDUSEDSKY + 2389 ;__IDESEGDISPLAY________________________________________________________________________________________ + 2390 ; + 2391 ; DISPLAY CONTENTS OF IDE LOGICAL BLOCK ADDRESS ON DSKY + 2392 ;____________________________________________________________________________________________________ + 2393 IDESEGDISPLAY: + 2394 LD A, #0x82 ; + 2395 OUT (PIOCONT),A ; + 2396 ; + 2397 LD A,(IDE_LBA3) ; + 2398 AND #0x0F ; + 2399 LD (DISPLAYBUF+6),A ; + 2400 LD A,(IDE_LBA3) ; + 2401 AND #0x0F0 ; + 2402 SRL A ; + 2403 SRL A ; + 2404 SRL A ; + 2405 SRL A ; + 2406 LD (DISPLAYBUF+7),A ; + 2407 ; + 2408 LD A,(IDE_LBA2) ; + 2409 AND #0x0F ; + 2410 LD (DISPLAYBUF+4),A ; + 2411 LD A,(IDE_LBA2) ; + 2412 AND #0x0F0 ; + 2413 SRL A ; + 2414 SRL A ; + 2415 SRL A ; + 2416 SRL A ; + 2417 LD (DISPLAYBUF+5),A ; + 2418 ; + 2419 LD A,(IDE_LBA1) ; + 2420 AND #0x0F ; + 2421 LD (DISPLAYBUF+2),A ; + 2422 LD A,(IDE_LBA1) ; + 2423 AND #0x0F0 ; + 2424 SRL A ; + 2425 SRL A ; + 2426 SRL A ; + 2427 SRL A ; + 2428 LD (DISPLAYBUF+3),A ; + 2429 + 2430 LD A,(IDE_LBA0) ; + 2431 AND #0x0F ; + 2432 LD (DISPLAYBUF),A ; + 2433 LD A,(IDE_LBA0) ; + 2434 AND #0x0F0 ; + 2435 SRL A ; + 2436 SRL A ; + 2437 SRL A ; + 2438 SRL A ; + 2439 LD (DISPLAYBUF+1),A ; + 2440 JP SEGDISPLAY1 ; + 2441 + 2442 ;__ATAPISEGDISPLAY________________________________________________________________________________________ + 2443 ; + 2444 ; DISPLAY CONTENTS OF ATAPI LOGICAL BLOCK ADDRESS ON DSKY + 2445 ;____________________________________________________________________________________________________ + 2446 ATAPISEGDISPLAY: + 2447 LD A, #0x82 ; + 2448 OUT (PIOCONT),A ; + 2449 ; + 2450 LD A,(LBA_TARGET_HI+1) ; + 2451 AND #0x0F ; + 2452 LD (DISPLAYBUF+6),A ; + 2453 LD A,(LBA_TARGET_HI+1) ; + 2454 AND #0x0F0 ; + 2455 SRL A ; + 2456 SRL A ; + 2457 SRL A ; + 2458 SRL A ; + 2459 LD (DISPLAYBUF+7),A ; + 2460 ; + 2461 LD A,(LBA_TARGET_HI) ; + 2462 AND #0x0F ; + 2463 LD (DISPLAYBUF+4),A ; + 2464 LD A,(LBA_TARGET_HI) ; + 2465 AND #0x0F0 ; + 2466 SRL A ; + 2467 SRL A ; + 2468 SRL A ; + 2469 SRL A ; + 2470 LD (DISPLAYBUF+5),A ; + 2471 ; + 2472 LD A,(LBA_TARGET_LO+1) ; + 2473 AND #0x0F ; + 2474 LD (DISPLAYBUF+2),A ; + 2475 LD A,(LBA_TARGET_LO+1) ; + 2476 AND #0x0F0 ; + 2477 SRL A ; + 2478 SRL A ; + 2479 SRL A ; + 2480 SRL A ; + 2481 LD (DISPLAYBUF+3),A ; + 2482 ; + 2483 LD A,(LBA_TARGET_LO) ; + 2484 AND #0x0F ; + 2485 LD (DISPLAYBUF),A ; + 2486 LD A,(LBA_TARGET_LO) ; + 2487 AND #0x0F0 ; + 2488 SRL A ; + 2489 SRL A ; + 2490 SRL A ; + 2491 SRL A ; + 2492 LD (DISPLAYBUF+1),A ; + 2493 JP SEGDISPLAY1 ; + 2494 + 2495 ;__SEGDISPLAY________________________________________________________________________________________ + 2496 ; + 2497 ; DISPLAY CONTENTS OF TRACK, SECTOR, ST0, ST1 ON DSKY + 2498 ; + 2499 ;____________________________________________________________________________________________________ + 2500 SEGDISPLAY: + 2501 LD A, #0x82 ; + 2502 OUT (PIOCONT),A ; + 2503 LD A,(TRACK) ; + 2504 AND #0x0F ; + 2505 LD (DISPLAYBUF+6),A ; + 2506 LD A,(TRACK) ; + 2507 AND #0x0F0 ; + 2508 SRL A ; + 2509 SRL A ; + 2510 SRL A ; + 2511 SRL A ; + 2512 LD (DISPLAYBUF+7),A ; + 2513 LD A,(SECTOR) ; + 2514 AND #0x0F ; + 2515 LD (DISPLAYBUF+4),A ; + 2516 LD A,(SECTOR) ; + 2517 AND #0x0F0 ; + 2518 SRL A ; + 2519 SRL A ; + 2520 SRL A ; + 2521 SRL A ; + 2522 LD (DISPLAYBUF+5),A ; + 2523 LD A,(ST0) ; + 2524 AND #0x0F ; + 2525 LD (DISPLAYBUF+2),A ; + 2526 LD A,(ST0) ; + 2527 AND #0x0F0 ; + 2528 SRL A ; + 2529 SRL A ; + 2530 SRL A ; + 2531 SRL A ; + 2532 LD (DISPLAYBUF+3),A ; + 2533 LD A,(ST1) ; + 2534 AND #0x0F ; + 2535 LD (DISPLAYBUF),A ; + 2536 LD A,(ST1) ; + 2537 AND #0x0F0 ; + 2538 SRL A ; + 2539 SRL A ; + 2540 SRL A ; + 2541 SRL A ; + 2542 LD (DISPLAYBUF+1),A ; + 2543 SEGDISPLAY1: ; + 2544 LD HL,#DISPLAYBUF ; + 2545 LD BC,#7 ; + 2546 ADD HL,BC ; + 2547 LD B,#8 ; SET DIGIT COUNT + 2548 LD A,#0x40 ; SET CONTROL PORT 7218 TO OFF + 2549 OUT (PORTC),A ; OUTPUT + 2550 CALL DELAY12 ; WAIT + 2551 LD A,#0x0D0 ; SET CONTROL TO 1111 (DATA COMING, HEX DECODE, DECODE, NORMAL) + 2552 OUT (PORTA),A ; OUTPUT TO PORT + 2553 LD A,#0x80 ; STROBE WRITE PULSE WITH CONTROL=1 + 2554 OUT (PORTC),A ; OUTPUT TO PORT + 2555 CALL DELAY12 ; WAIT + 2556 LD A,#0x40 ; SET CONTROL PORT 7218 TO OFF + 2557 OUT (PORTC),A ; OUTPUT + 2558 CALL DELAY12 ; WAIT + 2559 SEGDISPLAY_LP: + 2560 LD A,(HL) ; GET DISPLAY DIGIT + 2561 OUT (PORTA),A ; OUT TO PORTA + 2562 LD A,#0 ; SET WRITE STROBE + 2563 OUT (PORTC),A ; OUT TO PORTC + 2564 CALL DELAY12 ; DELAY + 2565 LD A,#0x40 ; SET CONTROL PORT OFF + 2566 OUT (PORTC),A ; OUT TO PORTC + 2567 CALL DELAY12 ; WAIT + 2568 DEC HL ; INC POINTER + 2569 DJNZ SEGDISPLAY_LP ; LOOP FOR NEXT DIGIT + 2570 RET + 2571 + 2572 DISPLAYBUF: .DB 01,02,03,04,05,06,07,08 + 2573 .ENDIF + 0A43 00 00 00 00 00 00 2574 .DB 00,00,00,00,00,00,00,00 + 00 00 + 0A4B 00 00 00 00 00 00 2575 .DB 00,00,00,00,00,00,00,00 + 00 00 + 0A53 00 00 00 00 00 00 2576 .DB 00,00,00,00,00,00,00,00 + 00 00 + 0A5B 00 00 00 00 00 00 2577 .DB 00,00,00,00,00,00,00,00 + 00 00 + 2578 + 2579 + 2580 + 0A63 00 2581 FLOPPYSTACK: .DB 00 + 0A64 00 00 00 00 2582 PARKSTACK: .DB 00,00,00,00 + 2583 + 0A68 2584 READ_DISK_PACKET: + 0A68 A8 00 00 00 00 01 2585 .DB 0x0A8,00,00,00,00,01,00,00,00,01,00,00 + 00 00 00 01 00 00 + 0A74 2586 WRITE_DISK_PACKET: + 0A74 2A 00 00 00 00 11 2587 .DB 0x2A,00,00,00,00,0x11,00,00,01,00,00,00 + 00 00 01 00 00 00 + 0A80 2588 ATAPI_REQUEST_SENSE: + 0A80 03 00 00 00 11 00 2589 .DB 3,00,00,00,0x11,00,00,00,00,00,00,00 + 00 00 00 00 00 00 + 2590 + 2591 ; ******* TEXT STRINGS ******* + 2592 + 0A8C 2593 TXT_RO_ERROR: + 0A8C 0D 0A 2594 .DB CR,LF + 0A8E 45 52 52 4F 52 3A 2595 .ascii "ERROR: WRITE TO READ ONLY DISK" + 20 57 52 49 54 45 + 20 54 4F 20 52 45 + 41 44 20 4F 4E 4C + 59 20 44 49 53 4B + 0AAC FF 2596 .DB END + 2597 + 2598 + 0AAD 2599 TXT_STARTUP_MSG: + 2600 + 0001 2601 .IF CONDSHORTMSG + 0AAD 0D 0A 2602 .DB CR,LF + 0AAF 43 50 2F 4D 2D 38 2603 .ascii "CP/M-80 2.2C (JC0705-1) for " + 30 20 32 2E 32 43 + 20 28 4A 43 30 37 + 30 35 2D 31 29 20 + 66 6F 72 20 + 0ACB 4E 38 56 45 4D 20 2604 .ascii "N8VEM - W/" + 2D 20 57 2F + 0000 2605 .IF CONDUSEVDU + 2606 .ascii "VDU " + 2607 .ENDIF + 0000 2608 .IF CONDUSEDSKY + 2609 .ascii "DSKY " + 2610 .ENDIF + 0001 2611 .IF CONDIDESOFT + 0AD5 49 44 45 20 2612 .ascii "IDE " + 2613 .ENDIF + 0000 2614 .IF CONDUSEATAPI + 2615 .ascii "ATAPI " + 2616 .ENDIF + 0001 2617 .IF CONDUSEFLOPPY + 0AD9 46 4C 4F 50 50 59 2618 .ascii "FLOPPY " + 20 + 0001 2619 .IF COND144FLOPPY + 0AE0 31 2E 34 34 4D 20 2620 .ascii "1.44M " + 2621 .ENDIF + 2622 .ENDIF + 0AE6 0D 0A 2623 .DB CR,LF + 0AE8 FF 2624 .DB END + 2625 .ELSE + 2626 .ascii "CP/M V2.2C" + 2627 .DB END + 2628 .ENDIF + 2629 + 2630 ; + 2631 ; THE REMAINDER OF THE CBIOS IS RESERVED UNINITIALIZED + 2632 ; DATA AREA, AND DOES NOT NEED TO BE A PART OF THE + 2633 ; SYSTEM MEMORY IMAGE (THE SPACE MUST BE AVAILABLE, + 2634 ; HOWEVER, BETWEEN "BEGDAT" AND "ENDDAT") + 2635 ; + 2636 + 2637 ; + 2638 ; DISK COMMAND BLOCK + 2639 ; + 0AE9 00 2640 CMD: .DB 0 ; COMMAND READ OR WRITE, + 0AEA 00 2641 UNIT: .DB 0 ; PHYSICAL DRIVE 0->3 + 0AEB 00 2642 HEAD: .DB 0 ; HEAD SEL 0 OR 1 + 0AEC 02 2643 DENS: .DB 2 ; DENSITY + 0AED 09 2644 EOTSEC: .DB 09 ; LAST SECTOR OF TRACK + 0AEE 1B 2645 GAP: .DB 0x1B ; VALUE FOR IRG + 2646 ;SECSIZ: .DB 0x80 ; HOW MANY BYTES TO TRANSFER/4 + 0AEF 00 02 2647 FSECSIZ: .dw 0x0200 ; actual sector size in bytes + 0AF1 FF 2648 DTL: .DB 0x0FF ; SIZE OF SECTOR + 0AF2 7F 2649 SRTHUT: .DB 0x7F ; STEP RATE AND HEAD UNLOAD TIME + 0AF3 05 2650 HLT: .DB 5 ; HEAD LOAD TIME + 0AF4 04 2651 MIN: .DB MINI ; LATCH BIT PATTERN FOR FDC9229 MINITRUE + 0AF5 20 2652 PRE: .DB PRECOMP ; LATCH BIT PATTERN FOR FDC9229 PRECOMP125NS + 2653 ; + 2654 ; FLOPPY STATUS RESULT STORAGE + 2655 ; + 0AF6 00 2656 ST0: .DB 0 ; STORE STATUS 0 + 0AF7 00 2657 ST1: .DB 0 ; ST1 + 0AF8 00 2658 ST2: .DB 0 ; ST2 + 0AF9 00 2659 SCYL: .DB 0 ; TRACK + 0AFA 00 2660 SHEAD: .DB 0 ; HEAD 0 OR 1 + 0AFB 00 2661 SREC: .DB 0 ; SECTOR + 0AFC 00 2662 SNBIT: .DB 0 ; DENSITY + 0AFD 00 2663 ST0A: .DB 0 ; STORE STATUS 0 + 0AFE 00 2664 ST1A: .DB 0 ; ST1 + 0AFF 00 2665 RETRY: .DB 0 ; RETRIES + 0B00 00 2666 RETRY1: .DB 0 ; RETRIES + 2667 + 0B01 00 2668 FLATCH_STORE: .DB 00 ; + 2669 + 0B02 00 00 2670 TRACK: .DW 0 ; TWO BYTES FOR TRACK # (LOGICAL) + 0B04 00 00 2671 PTRACK: .DW 0 ; TWO BYTES FOR TRACK # (PHYSICAL) + 0B06 00 00 2672 FTRACK: .DW 0 ; TWO BYTES FOR TRACK # (HEAD LOCATION) + 2673 + 0B08 01 2674 PAGER: .DB 1 ; COPY OF PAGER BYTE + 0B09 FF 2675 DB_PAGER: .DB 0x0FF ; COPY OF PAGER BYTE (DEBUG) + 0B0A 00 00 2676 SECTOR: .DW 0 ; TWO BYTES FOR SECTOR # (LOGICAL) + 0B0C 00 00 2677 PSECTOR: .DW 0 ; TWO BYTES FOR SECTOR # (PHYSICAL) + 0B0E 00 00 2678 SECST: .DW 0 ; SECTOR IN ROM/RAM START ADDRESS + 0B10 00 00 2679 DMAAD: .DW 0 ; DIRECT MEMORY ADDRESS + 0B12 00 2680 DISKNO: .DB 0 ; DISK NUMBER 0-15 + 0B13 00 00 2681 LBA_TARGET_LO: .DW 0 ; IDE HD PARTITION TARGET SECTOR (LOW 16 BITS) + 0B15 00 00 2682 LBA_TARGET_HI: .DW 0 ; IDE HD PARTITION TARGET SECTOR (HI 16 BITS, 12 USED) + 0B17 00 2683 IDEDEVICE: .DB 0 ; ATAPI DEVICE SELECTION FLAG + 2684 + 0B18 00 2685 IDE_LBA0: .DB 0 ; SET LBA 0:7 + 0B19 00 2686 IDE_LBA1: .DB 0 ; SET LBA 8:15 + 0B1A 00 2687 IDE_LBA2: .DB 0 ; SET LBA 16:23 + 0B1B 00 2688 IDE_LBA3: .DB 0 ; LOWEST 4 BITS USED ONLY TO ENABLE LBA MODE + 0B1C 01 2689 SECTOR_INDEX: .DB 1 ; WHERE 128 BYTE CP/M SECTOR IS IN 512 BYTE IDE HD SECTOR + 2690 ; + 2691 ; SCRATCH RAM AREA FOR BDOS USE + 0B1D 2692 BEGDAT: + 2693 ; = $ ; BEGINNING OF DATA AREA + 0B1D 2694 DIRBF: .DS 128 ; SCRATCH DIRECTORY AREA + 0B9D 2695 ALL00: .DS 65 ; ALLOCATION VECTOR 0 (DSM/8 = 1 BIT PER BLOCK) 44 + 0BDE 2696 ALL01: .DS 33 ; ALLOCATION VECTOR 1 (225/8) + 0BFF 2697 ALL02: .DS 256 ; ALLOCATION VECTOR 2 (511/8) + 0CFF 2698 ALL03: .DS 256 ; ALLOCATION VECTOR 3 (511/8) + 0DFF 2699 ALL04: .DS 65 ; ALLOCATION VECTOR 4 (497/8) + 0E40 2700 ALL05: .DS 65 ; ALLOCATION VECTOR 4 (495/8) + 0E81 2701 ALL06: .DS 65 ; ALLOCATION VECTOR 4 (495/8) + 0EC2 2702 ALL07: .DS 135 ; ALLOCATION VECTOR 7 (495/8) + 0F49 2703 CHK00: .DS 5 ; 720K MEDIA + 0F4E 2704 CHK01: .DS 0 ; NOT USED FOR FIXED MEDIA + 0F4E 2705 CHK02: .DS 0 ; NOT USED FOR FIXED MEDIA + 0F4E 2706 CHK03: .DS 128 ; 8M MEDIA + 0FCE 2707 CHK04: .DS 0 ; NOT USED FOR FIXED MEDIA + 0FCE 2708 CHK05: .DS 0 ; NOT USED FOR FIXED MEDIA + 0FCE 2709 CHK06: .DS 0 ; NOT USED FOR FIXED MEDIA + 0FCE 2710 CHK07: .DS 15 ; 1.44M MEDIA + 2711 ; + 0FDD 2712 CUDISK: .DS 1 ; CURRENT PHYSICAL DISK ID IN BUFFER + 0FDE 01 00 2713 CUSECTOR: .DW 1 ; CURRENT PHYSICAL DISK SECTOR IN BUFFER + 0FE0 02 00 2714 CUTRACK: .DW 2 ; CURRENT PHYSICAL DISK TRACK IN BUFFER + 0FE2 2715 SECTOR_BUFFER: .DS 520 ; STORAGE FOR 512 BYTE IDE HD SECTOR + 11EA 2716 ENDDAT: + 2717 ; .EQU $ ; END OF DATA AREA + 11EA 2718 DSTEMP: + 06CD 2719 DATSIZ = DSTEMP - BEGDAT ; SIZE OF DATA AREA + 2720 + 2721 + 2722 ;dwg; .ORG 0FDFFH + 11EA 00 2723 LASTBYTE: .DB 0 + 2724 + 2725 ; .END + 2726 + 2727 + 2728 + 2729 + 2730 + 11EB 2731 _cbios_end:: + 2732 .area _CODE + 2733 .area _CABS diff --git a/doug/src/cbios.rel b/doug/src/cbios.rel new file mode 100755 index 00000000..61da9878 --- /dev/null +++ b/doug/src/cbios.rel @@ -0,0 +1,958 @@ +XL +H 8 areas 4 global symbols +M cbios +O -mz80 +S .__.ABS. Def0000 +A _CODE size 0 flags 0 addr 0 +A _DATA size 0 flags 0 addr 0 +A _OVERLAY size 0 flags 0 addr 0 +A _HOME size 0 flags 0 addr 0 +A _GSINIT size 0 flags 0 addr 0 +A _GSFINAL size 0 flags 0 addr 0 +A _CBIOS size 11EB flags 0 addr 0 +S _cbios_end Def11EB +S _cbios Def0000 +S _cbios_start Def0000 +A _CABS size 0 flags 0 addr 0 +T 00 00 +R 00 00 06 00 +T 00 00 +R 00 00 06 00 +T 00 00 C3 1B 01 C3 46 01 C3 9C 01 C3 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 0A 00 A6 01 C3 B1 01 C3 BC 01 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 13 00 C0 01 C3 C2 01 C3 DA 01 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 1C 00 C4 01 C3 DD 01 C3 E3 01 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 25 00 EC 01 C3 F2 01 C3 D7 03 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 2E 00 BE 01 C3 E9 01 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 33 00 +R 00 00 06 00 +T 33 00 00 00 00 00 00 00 00 00 1D 0B B2 00 4E 0F +R 00 00 06 00 00 0A 06 00 00 0C 06 00 00 0E 06 00 +T 41 00 DE 0B 00 00 00 00 00 00 00 00 1D 0B 0C 01 +R 00 00 06 00 00 02 06 00 00 0C 06 00 00 0E 06 00 +T 4F 00 CE 0F C2 0E 00 00 00 00 00 00 00 00 1D 0B +R 00 00 06 00 00 02 06 00 00 04 06 00 00 0E 06 00 +T 5D 00 C1 00 4E 0F FF 0B 00 00 00 00 00 00 00 00 +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 6B 00 1D 0B B2 00 4E 0F +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 71 00 DE 0B 00 00 00 00 00 00 00 00 1D 0B DF 00 +R 00 00 06 00 00 02 06 00 00 0C 06 00 00 0E 06 00 +T 7F 00 CE 0F FF 0D 00 00 00 00 00 00 00 00 1D 0B +R 00 00 06 00 00 02 06 00 00 04 06 00 00 0E 06 00 +T 8D 00 EE 00 CE 0F 40 0E 00 00 00 00 00 00 00 00 +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 9B 00 1D 0B FD 00 CE 0F +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T A1 00 81 0E +R 00 00 06 00 00 02 06 00 +T A3 00 +R 00 00 06 00 +T A3 00 24 00 04 0F 00 5E 01 7F 00 C0 00 20 00 +R 00 00 06 00 +T B0 00 04 00 +R 00 00 06 00 +T B2 00 +R 00 00 06 00 +T B2 00 00 01 04 0F 01 E1 00 FF 00 F0 00 00 00 +R 00 00 06 00 +T BF 00 01 00 +R 00 00 06 00 +T C1 00 +R 00 00 06 00 +T C1 00 00 01 05 1F 01 E1 07 FF 01 F0 00 00 00 +R 00 00 06 00 +T CE 00 F1 03 +R 00 00 06 00 +T D0 00 +R 00 00 06 00 +T D0 00 00 01 05 1F 01 E1 07 FF 01 F0 00 00 00 +R 00 00 06 00 +T DD 00 01 00 +R 00 00 06 00 +T DF 00 +R 00 00 06 00 +T DF 00 00 01 04 0F 01 F1 01 FF 00 F0 00 00 00 +R 00 00 06 00 +T EC 00 01 00 +R 00 00 06 00 +T EE 00 +R 00 00 06 00 +T EE 00 00 01 04 0F 00 FF 01 FF 00 F0 00 00 00 +R 00 00 06 00 +T FB 00 01 00 +R 00 00 06 00 +T FD 00 +R 00 00 06 00 +T FD 00 10 00 03 07 01 1F 00 1F 00 80 00 00 00 +R 00 00 06 00 +T 0A 01 0A 00 +R 00 00 06 00 +T 0C 01 +R 00 00 06 00 +T 0C 01 48 00 04 0F 00 C6 02 FF 00 F0 00 20 00 +R 00 00 06 00 +T 19 01 02 00 +R 00 00 06 00 +T 1B 01 +R 00 00 06 00 +T 1B 01 3E 80 D3 7C 3E 81 D3 78 21 00 00 01 FF 1F +R 00 00 06 00 +T 29 01 3E E5 5D 54 13 77 ED B0 3E 80 D3 7C 3E 00 +R 00 00 06 00 +T 37 01 D3 78 AF 32 03 00 32 04 00 CD C3 05 C3 +R 00 00 06 00 00 0C 06 00 +T 44 01 67 01 +R 00 00 06 00 00 02 06 00 +T 46 01 +R 00 00 06 00 +T 46 01 F3 31 80 00 ED 56 AF D3 7C AF D3 78 21 +R 00 00 06 00 +T 53 01 00 0A 11 00 D0 01 00 08 ED B0 3E 80 D3 7C +R 00 00 06 00 +T 61 01 AF D3 78 CD C3 05 +R 00 00 06 00 00 06 06 00 +T 67 01 +R 00 00 06 00 +T 67 01 3E C3 32 00 00 21 03 00 22 01 00 3E C3 32 +R 00 00 06 00 00 08 06 00 +T 75 01 38 00 21 03 00 22 01 00 32 05 00 21 06 D8 +R 00 00 06 00 00 05 06 00 +T 83 01 22 06 00 01 80 00 CD EC 01 CD BF 07 21 +R 00 00 06 00 00 09 06 00 00 0C 06 00 +T 90 01 AD 0A CD BC 04 3A 04 00 4F C3 00 D0 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 9C 01 +R 00 00 06 00 +T 9C 01 DB 6D E6 01 CA A5 01 3E FF +R 00 00 06 00 00 07 06 00 +T A5 01 +R 00 00 06 00 +T A5 01 C9 +R 00 00 06 00 +T A6 01 +R 00 00 06 00 +T A6 01 CD 9C 01 FE 00 CA A6 01 DB 68 C9 +R 00 00 06 00 00 03 06 00 00 08 06 00 +T B1 01 +R 00 00 06 00 +T B1 01 DB 6D E6 20 CA B1 01 79 D3 68 C9 +R 00 00 06 00 00 07 06 00 +T BC 01 +R 00 00 06 00 +T BC 01 79 C9 +R 00 00 06 00 +T BE 01 +R 00 00 06 00 +T BE 01 AF C9 +R 00 00 06 00 +T C0 01 +R 00 00 06 00 +T C0 01 79 C9 +R 00 00 06 00 +T C2 01 +R 00 00 06 00 +T C2 01 79 C9 21 00 00 79 FE 07 D0 32 12 0B 6F 26 +R 00 00 06 00 00 0C 06 00 +T D0 01 00 29 29 29 29 11 33 00 19 C9 +R 00 00 06 00 00 08 06 00 +T DA 01 +R 00 00 06 00 +T DA 01 01 00 00 +R 00 00 06 00 +T DD 01 +R 00 00 06 00 +T DD 01 60 69 22 02 0B C9 +R 00 00 06 00 00 05 06 00 +T E3 01 +R 00 00 06 00 +T E3 01 60 69 22 0A 0B C9 +R 00 00 06 00 00 05 06 00 +T E9 01 +R 00 00 06 00 +T E9 01 60 69 C9 +R 00 00 06 00 +T EC 01 +R 00 00 06 00 +T EC 01 69 60 22 10 0B C9 +R 00 00 06 00 00 05 06 00 +T F2 01 +R 00 00 06 00 +T F2 01 F3 3A 12 0B FE 01 CA FE 02 FE 00 CA 5A 02 +R 00 00 06 00 00 04 06 00 00 09 06 00 00 0E 06 00 +T 00 02 FE 02 CA 78 03 FE 03 CA 5A 02 FE 04 CA +R 00 00 06 00 00 05 06 00 00 0A 06 00 +T 0D 02 D6 03 FE 05 CA 5A 02 +R 00 00 06 00 00 02 06 00 00 07 06 00 +T 14 02 +R 00 00 06 00 +T 14 02 2A 02 0B 29 29 29 29 44 4D 2A 0A 0B 09 22 +R 00 00 06 00 00 03 06 00 00 0C 06 00 +T 22 02 0C 0B 2A 0C 0B 29 29 29 29 29 29 29 22 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 2F 02 0E 0B 3E 00 D3 7C 32 08 0B 21 E2 0F 5D 54 +R 00 00 06 00 00 02 06 00 00 09 06 00 00 0C 06 00 +T 3D 02 2A 0E 0B CD 10 05 CD 04 05 2A +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 47 02 10 0B 5D 54 21 E2 0F CD 10 05 3A +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T 52 02 12 0B 32 DD 0F 3E 00 C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 5A 02 +R 00 00 06 00 +T 5A 02 CD CB 04 CD D9 04 21 E2 0F 5D 54 2A +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 66 02 0E 0B CD 10 05 CD 04 05 2A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 6F 02 10 0B 5D 54 21 E2 0F CD 10 05 3A +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T 7A 02 12 0B 32 DD 0F 3E 00 C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 82 02 +R 00 00 06 00 +T 82 02 3A 02 0B E6 01 32 EB 0A 3A 02 0B CB 3F 32 +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0B 06 00 +T 90 02 04 0B 3A 0A 0B 32 1C 0B CB 3F CB 3F 32 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 9D 02 0C 0B 3A 1C 0B E6 03 32 1C 0B C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T A8 02 +R 00 00 06 00 +T A8 02 2A 10 0B 54 5D D5 21 E2 0F 3A 1C 0B 0F 0F +R 00 00 06 00 00 03 06 00 00 09 06 00 00 0C 06 00 +T B6 02 16 00 5F 19 19 D1 CD 10 05 C9 +R 00 00 06 00 00 09 06 00 +T C0 02 +R 00 00 06 00 +T C0 02 21 E2 0F 3A 1C 0B 0F 0F 16 00 5F 19 19 22 +R 00 00 06 00 00 03 06 00 00 06 06 00 +T CE 02 0E 0B 2A 0E 0B 54 5D 2A 10 0B CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T D9 02 10 05 C9 +R 00 00 06 00 00 02 06 00 +T DC 02 +R 00 00 06 00 +T DC 02 2A 0C 0B 3A DE 0F BD C0 3A DF 0F BC C0 2A +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0B 06 00 +T EA 02 04 0B 3A E0 0F BD C0 3A E1 0F BC C0 2A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T F7 02 12 0B 3A DD 0F BD C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T FE 02 +R 00 00 06 00 +T FE 02 F3 21 00 00 39 22 64 0A 31 63 0A CD 82 02 +R 00 00 06 00 00 08 06 00 00 0B 06 00 00 0E 06 00 +T 0C 03 CD 1A 03 CD A8 02 3A F7 0A +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 15 03 +R 00 00 06 00 +T 15 03 ED 7B 64 0A C9 +R 00 00 06 00 00 04 06 00 +T 1A 03 +R 00 00 06 00 +T 1A 03 3E 00 32 F7 0A CD DC 02 CA 65 03 3E 14 32 +R 00 00 06 00 00 05 06 00 00 08 06 00 00 0B 06 00 +T 28 03 FF 0A 3E 02 32 00 0B +R 00 00 06 00 00 02 06 00 00 07 06 00 +T 2F 03 +R 00 00 06 00 +T 2F 03 CD 1E 08 3A F6 0A E6 F8 47 3A F7 0A B0 CA +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0C 06 00 +T 3D 03 65 03 3A FF 0A 3D 32 FF 0A C2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T 47 03 2F 03 CD 61 09 3E 14 32 FF 0A 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T 52 03 00 0B 3D 32 00 0B C2 2F 03 21 FF FF 22 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T 5F 03 DE 0F 22 E0 0F C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 65 03 +R 00 00 06 00 +T 65 03 2A 0C 0B 22 DE 0F 2A 04 0B 22 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 6F 03 E0 0F 3A 12 0B 32 DD 0F C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 78 03 +R 00 00 06 00 +T 78 03 F3 21 00 00 39 22 64 0A 31 63 0A CD 16 05 +R 00 00 06 00 00 08 06 00 00 0B 06 00 00 0E 06 00 +T 86 03 CD 6A 05 D2 96 03 CD A8 02 ED 7B +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 91 03 64 0A 3E 00 C9 +R 00 00 06 00 00 02 06 00 +T 96 03 +R 00 00 06 00 +T 96 03 ED 7B 64 0A 3E FF C9 +R 00 00 06 00 00 04 06 00 +T 9D 03 +R 00 00 06 00 +T 9D 03 3E FF 32 FF 0A +R 00 00 06 00 00 05 06 00 +T A2 03 +R 00 00 06 00 +T A2 03 3E 10 32 17 0B F3 21 00 00 39 22 64 0A 31 +R 00 00 06 00 00 05 06 00 00 0D 06 00 +T B0 03 63 0A CD 16 05 CD DF 06 D2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T B9 03 C5 03 CD A8 02 ED 7B 64 0A 3E 00 C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T C5 03 +R 00 00 06 00 +T C5 03 3A FF 0A 3D 32 FF 0A C2 A2 03 ED 7B +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0A 06 00 +T D1 03 64 0A 3E FF C9 +R 00 00 06 00 00 02 06 00 +T D6 03 +R 00 00 06 00 +T D6 03 C9 +R 00 00 06 00 +T D7 03 +R 00 00 06 00 +T D7 03 F3 3A 12 0B FE 01 CA 25 04 FE 00 CA FD 03 +R 00 00 06 00 00 04 06 00 00 09 06 00 00 0E 06 00 +T E5 03 FE 02 CA 66 04 FE 03 CA FD 03 FE 04 CA +R 00 00 06 00 00 05 06 00 00 0A 06 00 +T F2 03 BB 04 +R 00 00 06 00 00 02 06 00 +T F4 03 +R 00 00 06 00 +T F4 03 21 8C 0A CD BC 04 3E 01 C9 +R 00 00 06 00 00 03 06 00 00 06 06 00 +T FD 03 +R 00 00 06 00 +T FD 03 21 E2 0F 5D 54 2A 10 0B CD 10 05 CD +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0B 06 00 +T 09 04 CB 04 CD D9 04 2A 0E 0B 5D 54 21 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 14 04 E2 0F CD 10 05 CD 04 05 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 1D 04 12 0B 32 DD 0F 3E 00 C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 25 04 +R 00 00 06 00 +T 25 04 F3 21 00 00 39 22 64 0A 31 63 0A CD 82 02 +R 00 00 06 00 00 08 06 00 00 0B 06 00 00 0E 06 00 +T 33 04 CD 1A 03 3A F7 0A C2 5E 04 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 3C 04 +R 00 00 06 00 +T 3C 04 CD C0 02 3E 14 32 FF 0A +R 00 00 06 00 00 03 06 00 00 08 06 00 +T 44 04 +R 00 00 06 00 +T 44 04 CD 26 08 3A F6 0A E6 F8 47 3A F7 0A B0 CA +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0C 06 00 +T 52 04 5E 04 3A FF 0A 3D 32 FF 0A C2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T 5C 04 44 04 +R 00 00 06 00 00 02 06 00 +T 5E 04 +R 00 00 06 00 +T 5E 04 ED 7B 64 0A 3A F7 0A C9 +R 00 00 06 00 00 04 06 00 00 07 06 00 +T 66 04 +R 00 00 06 00 +T 66 04 F3 21 00 00 39 22 64 0A 31 63 0A CD 16 05 +R 00 00 06 00 00 08 06 00 00 0B 06 00 00 0E 06 00 +T 74 04 CD 6A 05 D2 87 04 CD C0 02 CD +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 7E 04 9F 05 ED 7B 64 0A 3E 00 C9 +R 00 00 06 00 00 02 06 00 00 06 06 00 +T 87 04 +R 00 00 06 00 +T 87 04 ED 7B 64 0A 3E FF C9 +R 00 00 06 00 00 04 06 00 +T 8E 04 +R 00 00 06 00 +T 8E 04 3E 10 32 17 0B F3 21 00 00 39 22 64 0A 31 +R 00 00 06 00 00 05 06 00 00 0D 06 00 +T 9C 04 63 0A CD 16 05 CD DF 06 D2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T A5 04 B4 04 CD C0 02 CD 3C 07 ED 7B +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T AF 04 64 0A 3E 00 C9 +R 00 00 06 00 00 02 06 00 +T B4 04 +R 00 00 06 00 +T B4 04 ED 7B 64 0A 3E FF C9 +R 00 00 06 00 00 04 06 00 +T BB 04 +R 00 00 06 00 +T BB 04 C9 +R 00 00 06 00 +T BC 04 +R 00 00 06 00 +T BC 04 7E FE FF CA CA 04 4F CD B1 01 23 C3 BC 04 +R 00 00 06 00 00 06 06 00 00 0A 06 00 00 0E 06 00 +T CA 04 +R 00 00 06 00 +T CA 04 C9 +R 00 00 06 00 +T CB 04 +R 00 00 06 00 +T CB 04 2A 0A 0B 29 29 29 29 29 29 29 22 0E 0B C9 +R 00 00 06 00 00 03 06 00 00 0D 06 00 +T D9 04 +R 00 00 06 00 +T D9 04 2A 02 0B 3A 12 0B FE 05 CA F3 04 FE 06 CA +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0B 06 00 +T E7 04 F3 04 E6 01 0F B5 D3 78 32 08 0B C9 +R 00 00 06 00 00 02 06 00 00 0B 06 00 +T F3 04 +R 00 00 06 00 +T F3 04 3E 05 E6 01 0F B5 E6 7F D3 7C 32 08 0B 32 +R 00 00 06 00 00 0D 06 00 +T 01 05 09 0B C9 +R 00 00 06 00 00 02 06 00 +T 04 05 +R 00 00 06 00 +T 04 05 3E 80 D3 7C 3E 00 D3 78 32 08 0B C9 +R 00 00 06 00 00 0B 06 00 +T 10 05 +R 00 00 06 00 +T 10 05 01 80 00 ED B0 C9 +R 00 00 06 00 +T 16 05 +R 00 00 06 00 +T 16 05 3A 02 0B 67 3A 0A 0B 6F CD 61 05 CD +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0B 06 00 +T 22 05 61 05 3A 03 0B CB 27 CB 27 CB 27 CB 27 CB +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 30 05 27 CB 27 B4 67 3A 03 0B CB 3F CB 3F 32 +R 00 00 06 00 00 08 06 00 +T 3D 05 15 0B 7D 32 13 0B 7C 32 14 0B 3E 00 32 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0A 06 00 +T 4A 05 16 0B 2A 13 0B 22 0C 0B 2A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 53 05 15 0B 22 04 0B 3A 0A 0B E6 03 32 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 5E 05 1C 0B C9 +R 00 00 06 00 00 02 06 00 +T 61 05 +R 00 00 06 00 +T 61 05 37 3F 7C 1F 67 7D 1F 6F C9 +R 00 00 06 00 +T 6A 05 +R 00 00 06 00 +T 6A 05 CD DC 02 CA 8B 05 CD F3 05 D0 CD +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 75 05 66 06 3E 20 D3 27 +R 00 00 06 00 00 02 06 00 +T 7B 05 +R 00 00 06 00 +T 7B 05 CD F3 05 D0 CD 0F 06 D0 CD 22 06 D0 CD +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0B 06 00 +T 88 05 3C 06 37 +R 00 00 06 00 00 02 06 00 +T 8B 05 +R 00 00 06 00 +T 8B 05 2A 0C 0B 22 DE 0F 2A 04 0B 22 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 95 05 E0 0F 3A 12 0B 32 DD 0F 37 C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 9F 05 +R 00 00 06 00 +T 9F 05 CD F3 05 D0 CD 66 06 3E 30 D3 27 CD F3 05 +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0E 06 00 +T AD 05 D0 CD 0F 06 D0 CD 22 06 D0 CD 50 06 CD +R 00 00 06 00 00 04 06 00 00 08 06 00 00 0C 06 00 +T BA 05 F3 05 D0 CD 0F 06 D0 37 C9 +R 00 00 06 00 00 02 06 00 00 06 06 00 +T C3 05 +R 00 00 06 00 +T C3 05 3E 06 D3 2E 3E 02 D3 2E CD F3 05 C9 +R 00 00 06 00 00 0B 06 00 +T CF 05 +R 00 00 06 00 +T CF 05 11 00 00 +R 00 00 06 00 +T D2 05 +R 00 00 06 00 +T D2 05 06 F0 +R 00 00 06 00 +T D4 05 +R 00 00 06 00 +T D4 05 10 FE 13 7A B3 28 08 DB 27 E6 80 20 F1 37 +R 00 00 06 00 +T E2 05 C9 +R 00 00 06 00 +T E3 05 +R 00 00 06 00 +T E3 05 AF C9 +R 00 00 06 00 +T E5 05 +R 00 00 06 00 +T E5 05 DB 27 E6 08 28 FA C9 +R 00 00 06 00 +T EC 05 +R 00 00 06 00 +T EC 05 DB 27 E6 08 20 FA C9 +R 00 00 06 00 +T F3 05 +R 00 00 06 00 +T F3 05 11 00 00 +R 00 00 06 00 +T F6 05 +R 00 00 06 00 +T F6 05 06 05 +R 00 00 06 00 +T F8 05 +R 00 00 06 00 +T F8 05 05 C2 F8 05 13 7A B3 CA 0D 06 DB 27 E6 C0 +R 00 00 06 00 00 04 06 00 00 0A 06 00 +T 06 06 EE 40 C2 F6 05 37 C9 +R 00 00 06 00 00 05 06 00 +T 0D 06 +R 00 00 06 00 +T 0D 06 AF C9 +R 00 00 06 00 +T 0F 06 +R 00 00 06 00 +T 0F 06 37 DB 27 47 E6 01 37 C8 78 E6 20 37 C2 +R 00 00 06 00 +T 1C 06 20 06 DB 21 +R 00 00 06 00 00 02 06 00 +T 20 06 +R 00 00 06 00 +T 20 06 B7 C9 +R 00 00 06 00 +T 22 06 +R 00 00 06 00 +T 22 06 11 00 00 +R 00 00 06 00 +T 25 06 +R 00 00 06 00 +T 25 06 06 05 +R 00 00 06 00 +T 27 06 +R 00 00 06 00 +T 27 06 05 C2 27 06 13 7A B3 CA 3A 06 DB 27 E6 08 +R 00 00 06 00 00 04 06 00 00 0A 06 00 +T 35 06 CA 25 06 37 C9 +R 00 00 06 00 00 03 06 00 +T 3A 06 +R 00 00 06 00 +T 3A 06 AF C9 +R 00 00 06 00 +T 3C 06 +R 00 00 06 00 +T 3C 06 E5 21 E2 0F 06 00 +R 00 00 06 00 00 04 06 00 +T 42 06 +R 00 00 06 00 +T 42 06 DB 20 77 DB 28 23 77 23 05 C2 42 06 E1 C9 +R 00 00 06 00 00 0C 06 00 +T 50 06 +R 00 00 06 00 +T 50 06 E5 21 E2 0F 06 00 +R 00 00 06 00 00 04 06 00 +T 56 06 +R 00 00 06 00 +T 56 06 23 7E 2B D3 28 7E D3 20 23 23 05 C2 56 06 +R 00 00 06 00 00 0E 06 00 +T 64 06 E1 C9 +R 00 00 06 00 +T 66 06 +R 00 00 06 00 +T 66 06 3A 13 0B 32 18 0B 3A 14 0B 32 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 70 06 19 0B 3A 15 0B 32 1A 0B 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 79 06 16 0B E6 0F C6 E0 32 1B 0B 3E 01 D3 22 3A +R 00 00 06 00 00 02 06 00 00 09 06 00 +T 87 06 18 0B D3 23 3A 19 0B D3 24 3A 1A 0B D3 25 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0C 06 00 +T 95 06 3A 1B 0B E6 0F F6 E0 D3 26 C9 +R 00 00 06 00 00 03 06 00 +T 9F 06 +R 00 00 06 00 +T 9F 06 3E 0E D3 2E CD D7 09 3E 0A D3 2E CD CF 05 +R 00 00 06 00 00 07 06 00 00 0E 06 00 +T AD 06 D0 CD D7 06 CD D7 09 CD B8 06 C9 +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T B8 06 +R 00 00 06 00 +T B8 06 21 80 0A CD 7D 07 CD CF 05 D0 06 00 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T C4 06 +R 00 00 06 00 +T C4 06 DB 20 DD 23 DB 28 DD 23 10 F6 ED 67 DB 27 +R 00 00 06 00 +T D2 06 E6 01 20 E2 C9 +R 00 00 06 00 +T D7 06 +R 00 00 06 00 +T D7 06 3A 17 0B F6 A0 D3 26 C9 +R 00 00 06 00 00 03 06 00 +T DF 06 +R 00 00 06 00 +T DF 06 CD DC 02 CA 28 07 3A 13 0B 32 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T E9 06 6D 0A 3A 14 0B 32 6C 0A 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T F2 06 15 0B 32 6B 0A 3A 16 0B 32 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T FB 06 6A 0A CD B8 06 21 68 0A CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 04 07 7D 07 CD CF 05 D0 06 00 DD 21 E2 0F DB 27 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0C 06 00 +T 12 07 E6 08 FE 08 20 10 +R 00 00 06 00 +T 18 07 +R 00 00 06 00 +T 18 07 DB 20 DD 77 00 DD 23 DB 28 DD 77 00 DD 23 +R 00 00 06 00 +T 26 07 10 F0 +R 00 00 06 00 +T 28 07 +R 00 00 06 00 +T 28 07 2A 0C 0B 22 DE 0F 2A 04 0B 22 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 32 07 E0 0F 3A 12 0B 32 DD 0F 37 C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 3C 07 +R 00 00 06 00 +T 3C 07 3A 13 0B 32 79 0A 3A 14 0B 32 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 46 07 78 0A 3A 15 0B 32 77 0A 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 4F 07 16 0B 32 76 0A CD B8 06 21 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 58 07 74 0A CD 7D 07 CD CF 05 D0 06 00 DD 21 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 65 07 E2 0F +R 00 00 06 00 00 02 06 00 +T 67 07 +R 00 00 06 00 +T 67 07 DB 27 DD 7E 00 F5 DD 23 DD 7E 00 D3 28 F1 +R 00 00 06 00 +T 75 07 D3 20 DD 23 10 EC 37 C9 +R 00 00 06 00 +T 7D 07 +R 00 00 06 00 +T 7D 07 CD CF 05 D0 CD EC 05 3E 0A D3 2E 3E 00 D3 +R 00 00 06 00 00 03 06 00 00 07 06 00 +T 8B 07 21 3E 00 D3 22 3E 00 D3 23 3E 00 D3 24 3E +R 00 00 06 00 +T 99 07 60 D3 25 3A 17 0B D3 26 3E A0 D3 27 CD +R 00 00 06 00 00 06 06 00 +T A6 07 E5 05 06 06 +R 00 00 06 00 00 02 06 00 +T AA 07 +R 00 00 06 00 +T AA 07 7E 57 23 7E D3 28 7A D3 20 23 DB 2E 10 F2 +R 00 00 06 00 +T B8 07 CD CF 05 D0 DB 2E C9 +R 00 00 06 00 00 03 06 00 +T BF 07 +R 00 00 06 00 +T BF 07 3E 02 F6 20 F6 40 F6 80 32 01 0B 3E 01 32 +R 00 00 06 00 00 0B 06 00 +T CD 07 EA 0A 3E 02 32 EC 0A 3E 09 87 32 ED 0A 3E +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0D 06 00 +T DB 07 7F 32 F2 0A 3E 05 32 F3 0A 3E 0D 32 EE 0A +R 00 00 06 00 00 04 06 00 00 09 06 00 00 0E 06 00 +T E9 07 CD E4 09 CD E4 09 CD E4 09 CD +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T F3 07 E4 09 CD E4 09 CD E4 09 21 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T FC 07 01 0B CB 8E CD 18 08 00 00 3E 00 32 04 0B +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0E 06 00 +T 0A 08 CD 24 09 00 00 21 01 0B CB CE CD 18 08 C9 +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0D 06 00 +T 18 08 +R 00 00 06 00 +T 18 08 3A 01 0B D3 3A C9 +R 00 00 06 00 00 03 06 00 +T 1E 08 +R 00 00 06 00 +T 1E 08 3E 46 32 E9 0A C3 2E 08 +R 00 00 06 00 00 05 06 00 00 08 06 00 +T 26 08 +R 00 00 06 00 +T 26 08 3E 45 32 E9 0A C3 2E 08 +R 00 00 06 00 00 05 06 00 00 08 06 00 +T 2E 08 +R 00 00 06 00 +T 2E 08 21 01 0B CB CE CD 18 08 CD E4 09 FE FF CA +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0B 06 00 +T 3C 08 75 08 3A EA 0A E6 03 47 3A EB 0A E6 01 17 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0B 06 00 +T 4A 08 17 B0 32 EA 0A 21 01 0B CB 8E CD 18 08 3E +R 00 00 06 00 00 05 06 00 00 08 06 00 00 0D 06 00 +T 58 08 03 CD C2 09 3A F2 0A CD C2 09 3A +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T 63 08 F3 0A CD C2 09 CD 24 09 C2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 6C 08 75 08 3A E9 0A B7 C3 A4 08 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T 75 08 +R 00 00 06 00 +T 75 08 21 01 0B CB CE CD 18 08 F6 FF C9 +R 00 00 06 00 00 03 06 00 00 08 06 00 +T 80 08 +R 00 00 06 00 +T 80 08 0E 07 21 F6 0A +R 00 00 06 00 00 05 06 00 +T 85 08 +R 00 00 06 00 +T 85 08 CD 30 0A 77 23 0D C2 85 08 3A F6 0A E6 F8 +R 00 00 06 00 00 03 06 00 00 09 06 00 00 0C 06 00 +T 93 08 47 3A F7 0A B0 +R 00 00 06 00 00 04 06 00 +T 98 08 +R 00 00 06 00 +T 98 08 CD E4 09 21 01 0B CB CE CD 18 08 C9 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0B 06 00 +T A4 08 +R 00 00 06 00 +T A4 08 11 38 00 21 1E 09 01 03 00 3A E9 0A E6 01 +R 00 00 06 00 00 06 06 00 00 0C 06 00 +T B2 08 CA B6 08 09 +R 00 00 06 00 00 03 06 00 +T B6 08 +R 00 00 06 00 +T B6 08 ED B0 21 E2 0F ED 5B EF 0A 43 0E 37 3A +R 00 00 06 00 00 05 06 00 00 09 06 00 +T C3 08 E9 0A CD C2 09 3A EA 0A CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T CC 08 C2 09 3A 04 0B CD C2 09 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T D5 08 EB 0A CD C2 09 3A 0C 0B 3C CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T DF 08 C2 09 3A EC 0A CD C2 09 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T E8 08 ED 0A CD C2 09 3A EE 0A CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T F1 08 C2 09 3A F1 0A CD AF 09 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T F9 08 +R 00 00 06 00 +T F9 08 +R 00 00 06 00 +T F9 08 FB 76 C2 F9 08 +R 00 00 06 00 00 05 06 00 +T FE 08 +R 00 00 06 00 +T FE 08 FB 76 C2 FE 08 +R 00 00 06 00 00 05 06 00 +T 03 09 +R 00 00 06 00 +T 03 09 21 01 0B CB C6 CD 18 08 00 00 CB 86 CD +R 00 00 06 00 00 03 06 00 00 08 06 00 +T 10 09 18 08 00 00 00 00 CB CE CD 18 08 C3 80 08 +R 00 00 06 00 00 02 06 00 00 0B 06 00 00 0E 06 00 +T 1E 09 ED A2 C9 +R 00 00 06 00 +T 21 09 +R 00 00 06 00 +T 21 09 ED A3 C9 +R 00 00 06 00 +T 24 09 +R 00 00 06 00 +T 24 09 +R 00 00 06 00 +T 24 09 3A 06 0B 4F 3A 04 0B B7 CA 4A 09 B9 CA +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0B 06 00 +T 31 09 5A 09 32 06 0B 3E 0F CD C2 09 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T 3C 09 EA 0A CD C2 09 3A 04 0B CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 45 09 C2 09 C3 5A 09 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 4A 09 +R 00 00 06 00 +T 4A 09 3E 00 32 06 0B 3E 07 CD C2 09 3A EA 0A CD +R 00 00 06 00 00 05 06 00 00 0A 06 00 00 0D 06 00 +T 58 09 C2 09 +R 00 00 06 00 00 02 06 00 +T 5A 09 +R 00 00 06 00 +T 5A 09 CD F6 09 CD E4 09 C9 +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 61 09 +R 00 00 06 00 +T 61 09 F5 E5 CD E4 09 CD E4 09 CD E4 09 CD +R 00 00 06 00 00 05 06 00 00 08 06 00 00 0B 06 00 +T 6D 09 E4 09 CD E4 09 CD E4 09 21 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 76 09 01 0B CB 8E CD 18 08 00 00 CD 4A 09 CD +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0C 06 00 +T 83 09 F6 09 CD F6 09 CD F6 09 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 8C 09 F6 09 CD 4A 09 CD F6 09 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 95 09 F6 09 CD F6 09 CD F6 09 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 9E 09 24 09 CD F6 09 CD F6 09 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T A7 09 F6 09 CD F6 09 E1 F1 C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T AF 09 +R 00 00 06 00 +T AF 09 F5 +R 00 00 06 00 +T B0 09 +R 00 00 06 00 +T B0 09 DB 36 E6 80 CA B0 09 DB 36 E6 40 C4 06 0A +R 00 00 06 00 00 07 06 00 00 0E 06 00 +T BE 09 F1 D3 37 C9 +R 00 00 06 00 +T C2 09 +R 00 00 06 00 +T C2 09 F5 +R 00 00 06 00 +T C3 09 +R 00 00 06 00 +T C3 09 DB 36 E6 80 CA C3 09 DB 36 E6 40 C4 06 0A +R 00 00 06 00 00 07 06 00 00 0E 06 00 +T D1 09 F1 D3 37 C3 D7 09 +R 00 00 06 00 00 06 06 00 +T D7 09 +R 00 00 06 00 +T D7 09 DD E5 DD E1 DD E5 DD E1 +R 00 00 06 00 +T DF 09 +R 00 00 06 00 +T DF 09 DD E5 DD E1 C9 +R 00 00 06 00 +T E4 09 +R 00 00 06 00 +T E4 09 DB 36 E6 80 CA E4 09 DB 36 E6 40 C2 F5 09 +R 00 00 06 00 00 07 06 00 00 0E 06 00 +T F2 09 CD 12 0A +R 00 00 06 00 00 03 06 00 +T F5 09 +R 00 00 06 00 +T F5 09 C9 +R 00 00 06 00 +T F6 09 +R 00 00 06 00 +T F6 09 21 00 00 +R 00 00 06 00 +T F9 09 +R 00 00 06 00 +T F9 09 00 00 00 00 2D C2 F9 09 25 C2 F9 09 C9 +R 00 00 06 00 00 08 06 00 00 0C 06 00 +T 06 0A +R 00 00 06 00 +T 06 0A DB 37 DB 36 E6 80 CA 06 0A 3E FF C9 +R 00 00 06 00 00 09 06 00 +T 12 0A +R 00 00 06 00 +T 12 0A 3E 08 CD C2 09 CD 30 0A 32 FD 0A E6 C0 FE +R 00 00 06 00 00 05 06 00 00 08 06 00 00 0B 06 00 +T 20 0A 80 CA 2F 0A CD 30 0A 32 FE 0A 3A +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T 2B 0A FD 0A E6 C0 +R 00 00 06 00 00 02 06 00 +T 2F 0A +R 00 00 06 00 +T 2F 0A C9 +R 00 00 06 00 +T 30 0A +R 00 00 06 00 +T 30 0A DB 36 E6 80 CA 30 0A DB 36 E6 40 CC 06 0A +R 00 00 06 00 00 07 06 00 00 0E 06 00 +T 3E 0A DB 37 C3 D7 09 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 00 05 06 00 +T 4C 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 5A 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 68 0A +R 00 00 06 00 +T 68 0A A8 00 00 00 00 01 00 00 00 01 00 00 +R 00 00 06 00 +T 74 0A +R 00 00 06 00 +T 74 0A 2A 00 00 00 00 11 00 00 01 00 00 00 +R 00 00 06 00 +T 80 0A +R 00 00 06 00 +T 80 0A 03 00 00 00 11 00 00 00 00 00 00 00 +R 00 00 06 00 +T 8C 0A +R 00 00 06 00 +T 8C 0A 0D 0A 45 52 52 4F 52 3A 20 57 52 49 54 45 +R 00 00 06 00 +T 9A 0A 20 54 4F 20 52 45 41 44 20 4F 4E 4C 59 20 +R 00 00 06 00 +T A8 0A 44 49 53 4B FF +R 00 00 06 00 +T AD 0A +R 00 00 06 00 +T AD 0A 0D 0A 43 50 2F 4D 2D 38 30 20 32 2E 32 43 +R 00 00 06 00 +T BB 0A 20 28 4A 43 30 37 30 35 2D 31 29 20 66 6F +R 00 00 06 00 +T C9 0A 72 20 4E 38 56 45 4D 20 2D 20 57 2F 49 44 +R 00 00 06 00 +T D7 0A 45 20 46 4C 4F 50 50 59 20 31 2E 34 34 4D +R 00 00 06 00 +T E5 0A 20 0D 0A FF 00 00 00 02 09 1B 00 02 FF 7F +R 00 00 06 00 +T F3 0A 05 04 20 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 01 0B 00 00 00 00 00 00 00 01 FF 00 00 00 00 +R 00 00 06 00 +T 0E 0B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 1C 0B 01 +R 00 00 06 00 +T 1D 0B +R 00 00 06 00 +T 1D 0B +R 00 00 06 00 +T 9D 0B +R 00 00 06 00 +T DE 0B +R 00 00 06 00 +T FF 0B +R 00 00 06 00 +T FF 0C +R 00 00 06 00 +T FF 0D +R 00 00 06 00 +T 40 0E +R 00 00 06 00 +T 81 0E +R 00 00 06 00 +T C2 0E +R 00 00 06 00 +T 49 0F +R 00 00 06 00 +T 4E 0F +R 00 00 06 00 +T 4E 0F +R 00 00 06 00 +T 4E 0F +R 00 00 06 00 +T CE 0F +R 00 00 06 00 +T CE 0F +R 00 00 06 00 +T CE 0F +R 00 00 06 00 +T CE 0F +R 00 00 06 00 +T DD 0F +R 00 00 06 00 +T DE 0F 01 00 02 00 +R 00 00 06 00 +T E2 0F +R 00 00 06 00 +T EA 11 +R 00 00 06 00 +T EA 11 +R 00 00 06 00 +T EA 11 00 +R 00 00 06 00 +T EB 11 +R 00 00 06 00 diff --git a/doug/src/cbios.s b/doug/src/cbios.s new file mode 100755 index 00000000..57c8725c --- /dev/null +++ b/doug/src/cbios.s @@ -0,0 +1,2733 @@ + .title cbios.s derived from cbios.asm + .sbttl by Douglas Goodall for N8VEM use '11 + + .module cbios + .optsdcc -mz80 + +;-------------------------------------------------------- +; Public variables in this module +;-------------------------------------------------------- + .globl _cbios +;-------------------------------------------------------- +; special function registers +;-------------------------------------------------------- +;-------------------------------------------------------- +; ram data +;-------------------------------------------------------- + .area _DATA +;-------------------------------------------------------- +; overlayable items in ram +;-------------------------------------------------------- + .area _OVERLAY +;-------------------------------------------------------- +; external initialized ram data +;-------------------------------------------------------- +;-------------------------------------------------------- +; global & static initialisations +;-------------------------------------------------------- + .area _HOME + .area _GSINIT + .area _GSFINAL + .area _GSINIT +;-------------------------------------------------------- +; Home +;-------------------------------------------------------- + .area _HOME + .area _HOME +;-------------------------------------------------------- +; code +;-------------------------------------------------------- + +; .area _CODE + .area _CBIOS + +_cbios_start:: +_cbios: + +; CBIOS FOR N8VEM +; +; Supports: Floppy, IDE HDD, ATAPI ZIP, RAM & ROM DRIVES, on board 16550, DSKY & VDU CARD +; +; BY ANDREW LYNCH, WITH INPUT FROM MANY SOURCES +; +; DATA CONSTANTS +;__________________________________________________________________________________________________ +FALSE = 0 +TRUE = 1 + +; LIST OF CONDITIONAL ASSEMBLY INSTRUCTIONS + +CONDIDESOFT = TRUE ; IF NO IDE DRIVE, HAS A SIGNIFICANT DELAY ON SOFT BOOT (TRUE) OR QUICK (FALSE) +CONDSHORTMSG = TRUE ; TRUE FOR ORIGINAL WARM BOOT SIGNON, FALSE FOR SHORTER ONE WITH LESS +CONDSUPERSUB = TRUE ; TRUE FOR NO SUPERSUB AUTOEXEC, FALSE TO RUN SUPERSUB AUTOEXEC +CONDABONLY = TRUE ; TRUE FOR ORIGINAL, FALSE TO ONLY HAVE DRIVE A AND B + +CONDUSEVDU = FALSE ; TRUE FOR USE VDU CARD, FALSE TO USE SERIAL PORT (FOR CONSOLE) +CONDUSEFLOPPY = TRUE ; TRUE FOR USE FLOPPY, FALSE FOR NO FLOPPY DRIVE +COND144FLOPPY = TRUE ; TRUE FOR 1.44Mb FLOPPY ON DRIVE G: +CONDUSEATAPI = FALSE ; TRUE FOR USE ZIP DISK, FALSE FOR NO ZIP DISK +CONDUSEDSKY = FALSE ; TRUE FOR USE DSKY, FALSE FOR NO DSKY + +; POINTERS TO VDU ROUTINES IN HIGH ROM BANK (NOT NEEDED IF NOT USING VDU CARD) + +VDU_INIT = 0x0100 ; VECTOR TO VDU INIT CODE +IS_KBHIT = 0x0395 ; VECTOR TO KB HIT CODE +GET_KEY = 0x039C ; VECTOR TO GET KEY CODE +CHARIN = 0x011B ; VECTOR TO CHARIN CODE +PR_OUTCHAR = 0x0CD6 ; VECTOR TO PRINTER CODE + +; +MSIZE = 59 ;CP/M VERSION MEMORY SIZE IN KILOBYTES +; +; "BIAS" IS ADDRESS OFFSET FROM 3400H FOR MEMORY SYSTEMS +; THAN 16K (REFERRED TO AS "B" THROUGHOUT THE TEXT) +; +BIAS = (MSIZE-20)*1024 ; +CCP = 0x3400+BIAS ; BASE OF CCP +BDOS = CCP+0x806 ; BASE OF BDOS +BIOS = CCP+0x1600 ; BASE OF BIOS +CDISK = 4 ; CURRENT DISK NUMBER 0=A,...,15=P +IOBYTE = 3 ; I/O DEFINITION BYTE. + +END = 0x0FF +CR = 0x0D +LF = 0x0A + +; TEST PROTOTYPE SPECIFIC HARDWARE IO PORT ADDRESSES AND MEMORY LOCATIONS + +UART = 0x68 ; BASE IO ADDRESS OF UART +MPCL_RAM = 0x78 ; BASE IO ADDRESS OF RAM MEMORY PAGER CONFIGURATION LATCH +MPCL_ROM = 0x7C ; BASE IO ADDRESS OF ROM MEMORY PAGER CONFIGURATION LATCH + +ROMSTART_CPM= 0x00A00 ; WHERE THE CCP+BDOS+BIOS IS STORED IN ROM +RAMTARG_CPM= 0x0D000 ; WHERE THE CCP+BDOS+BIOS STARTS IN RAM (ENTRY POINT) +MOVSIZ_CPM= 0x02BFF ; CCP, BDOS +CCPSIZ_CPM= 0x00800 ; CCP 0800h BYTES IN LENGTH + +; IDE REGISTER IO PORT ; FUNCTION +IDELO = 0x20 ; DATA PORT (LOW BYTE) +IDEERR = 0x21 ; READ: ERROR REGISTER; WRITE: PRECOMP +IDESECTC = 0x22 ; SECTOR COUNT +IDESECTN = 0x23 ; SECTOR NUMBER +IDECYLLO = 0x24 ; CYLINDER LOW +IDECYLHI = 0x25 ; CYLINDER HIGH +IDEHEAD = 0x26 ; DRIVE/HEAD +IDESTTS = 0x27 ; READ: STATUS; WRITE: COMMAND +IDEHI = 0x28 ; DATA PORT (HIGH BYTE) +IDECTRL = 0x2E ; READ: ALTERNATIVE STATUS; WRITE; DEVICE CONTROL +IDEADDR = 0x2F ; DRIVE ADDRESS (READ ONLY) +FMSR = 0x36 ; ADDRESS OF MAIN STATUS REGISTER +FDATA = 0x37 ; FLOPPY DATA REGISTER +FLATCH = 0x3A ; FLOPPY CONFIGURATION LATCH +FDMA = 0x3C ; PSEUDO DMA ADDRESS +; +; FDC CONFIGURATION LATCH OUTPUT BIT PATTERNS +MOTOR = 0b00000000 ; BIT PATTERN IN LATCH FOR MOTOR CONTROL (ON) +TERMCN = 0b00000001 ; BIT PATTERN IN LATCH TO WRITE A TC STROBE +RESETL = 0b00000010 ; BIT PATTERN IN LATCH TO RESET ALL BITS +MINI = 0b00000100 ; BIT PATTERN IN LATCH TO SET MINI MODE FDC9229 LOW DENS=1, HIGH DENS=0 +PRECOMP = 0b00100000 ; BIT PATTERN IN LATCH TO SET WRITE PRECOMP 125 NS: +FDDENSITY = 0b01000000 ; BIT PATTERN IN LATCH TO FLOPPY LOW DENSITY (HIGH IS 0) +FDREADY = 0b10000000 ; BIT PATTERN IN LATCH TO FLOPPY READY (P-34): +; +; PIO 82C55 I/O IS DECODED TO PORT 60-67 +PORTA = 0x60 ; PORT A +PORTB = 0x61 ; PORT B +PORTC = 0x62 ; PORT C +PIOCONT = 0x63 ; PIO CONTROL PORT + + +;dwg; .ORG BIOS + +;__________________________________________________________________________________________________ +; +; CP/M JUMP VECTOR TABLE FOR INDIVIDUAL SUBROUTINES +;__________________________________________________________________________________________________ +; + JP BOOT ; COLD START +WBOOTE: JP WBOOT ; WARM START + JP CONST ; CONSOLE STATUS + JP CONIN ; CONSOLE CHARACTER IN + JP CONOUT ; CONSOLE CHARACTER OUT + JP LIST ; LIST CHARACTER OUT (NULL ROUTINE) + JP PUNCH ; PUNCH CHARACTER OUT (NULL ROUTINE) + JP READER ; READER CHARACTER OUT (NULL ROUTINE) + JP HOME ; MOVE HEAD TO HOME POSITION + JP SELDSK ; SELECT DISK + JP SETTRK ; SET TRACK NUMBER + JP SETSEC ; SET SECTOR NUMBER + JP SETDMA ; SET DMA ADDRESS + JP READ ; READ DISK + JP WRITE ; WRITE DISK + JP LISTST ; RETURN LIST STATUS (NULL ROUTINE) + JP SECTRN ; SECTOR TRANSLATE + +;__________________________________________________________________________________________________ +; +; FIXED DATA TABLES FOR ALL DRIVES +; 0= FLOPPY DISK OR RAM DISK, 1=RAM DISK, 2=IDE, 3=ATAPI OR RAM DISK, 4=HDPART4 +; 5= 1MB ROM DISK,6=32K ROM DISK +; +; NOTE: The RAM disk area is used as a substitute if the Floppy and/or ZIP drives are not enabled +; in the sustem. This RAM disk is the same "disk" as drive B. +; +;__________________________________________________________________________________________________ + +; DISK PARAMETER HEADER FOR DISK 00 +DPBASE: + .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPBLK1 + .DW CHK01,ALL01 + +; DISK PARAMETER HEADER FOR DISK 01 +.IF CONDUSEFLOPPY + .IF COND144FLOPPY + .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPBLK7 ; FOR 1.44M FLOPPIES + .DW CHK07,ALL07 + .ELSE + .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPBLK0 + .DW CHK00,ALL00 + .ENDIF +.ELSE + .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPBLK1 + .DW CHK01,ALL01 +.ENDIF +; DISK PARAMETER HEADER FOR DISK 02 + .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPBLK2 + .DW CHK02,ALL02 + + .IF CONDUSEATAPI +; DISK PARAMETER HEADER FOR DISK 03 + .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPBLK3 + .DW CHK03,ALL03 + .ELSE + .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPBLK1 + .DW CHK01,ALL01 + .ENDIF + +; DISK PARAMETER HEADER FOR DISK 04 + .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPBLK4 + .DW CHK04,ALL04 + +; DISK PARAMETER HEADER FOR DISK 05 + .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPBLK5 + .DW CHK05,ALL05 + +; DISK PARAMETER HEADER FOR DISK 06 + .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPBLK6 + .DW CHK06,ALL06 +; + +DPBLK0: ; DISK PARAMETER BLOCK (FLOPPY DISK 720KB) +SPT_0: .DW 36 ; 36 SECTORS OF 128 BYTES PER 4.5K TRACK +BSH_0: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_0: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_0: .DB 0 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_0: .DW 350 ; BLOCKSIZE [2048] * NUMBER OF BLOCKS + 1 = DRIVE SIZE +DRM_0: .DW 127 ; NUMBER OF DIRECTORY ENTRIES +AL0_0: .DB 0b11000000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_0: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_0: .DW 32 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_0: .DW 4 ; FIRST 4 TRACKS TRACKS RESERVED (18K FOR SYSTEM) + ; +DPBLK1: ; DISK PARAMETER BLOCK (RAMDISK 512K, 448K USABLE) +SPT_1: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK +BSH_1: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_1: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_1: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_1: .DW 225 ; BLOCKSIZE [2048] * NUMBER OF BLOCKS + 1 = DRIVE SIZE +DRM_1: .DW 255 ; NUMBER OF DIRECTORY ENTRIES +AL0_1: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_1: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_1: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_1: .DW 1 ; 1 TRACK RESERVED [FIRST 32K OF RAM] + ; +DPBLK2: ; DISK PARAMETER BLOCK (IDE HARD DISK 8MB) +SPT_2: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK +BSH_2: .DB 5 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_2: .DB 31 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_2: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_2: .DW 2017 ; BLOCKSIZE [4096] * NUMBER OF BLOCKS + 1 = DRIVE SIZE +DRM_2: .DW 511 ; NUMBER OF DIRECTORY ENTRIES +AL0_2: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_2: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_2: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_2: .DW 0x03F1 ; TRACKS (32K) RESERVED FOR SYSTEM AND OTHER PARTITIONS + ; +DPBLK3: ; DISK PARAMETER BLOCK (ATAPI DRIVE 8MB) +SPT_3: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK +BSH_3: .DB 5 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_3: .DB 31 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_3: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_3: .DW 2017 ; BLOCKSIZE [4096] * NUMBER OF BLOCKS + 1 = DRIVE SIZE +DRM_3: .DW 511 ; NUMBER OF DIRECTORY ENTRIES +AL0_3: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_3: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_3: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_3: .DW 1 ; 1 TRACK (32K) RESERVED FOR SYSTEM + ; +DPBLK4: ; DISK PARAMETER BLOCK (IDE HARD DISK 1024K) +SPT_4: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK +BSH_4: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_4: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_4: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_4: .DW 497 ; BLOCKSIZE [2048] * NUMBER OF BLOCKS + 1 = DRIVE SIZE +DRM_4: .DW 255 ; NUMBER OF DIRECTORY ENTRIES +AL0_4: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_4: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_4: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_4: .DW 1 ; 1 TRACK RESERVED [FIRST 32K OF PARTITION] + ; +DPBLK5: ; DISK PARAMETER BLOCK (ROMDISK 1MB) +SPT_5: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK +BSH_5: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_5: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_5: .DB 0 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_5: .DW 511 ; BLOCKSIZE [2048] * NUMBER OF BLOCKS +1 =DRIVE SIZE +DRM_5: .DW 255 ; NUMBER OF DIRECTORY ENTRIES +AL0_5: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_5: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_5: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_5: .DW 1 ; 1 TRACK RESERVED [FIRST 32K OF ROM] + ; +DPBLK6: ; DISK PARAMETER BLOCK (ROMDISK 32KB) +SPT_6: .DW 16 ; 16 SECTORS OF 128 BYTES PER 2K TRACK +BSH_6: .DB 3 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_6: .DB 7 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_6: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_6: .DW 31 ; BLOCKSIZE [1024] * NUMBER OF BLOCKS + 1 = DRIVE SIZE +DRM_6: .DW 31 ; NUMBER OF DIRECTORY ENTRIES +AL0_6: .DB 0b10000000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_6: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_6: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_6: .DW 10 ; FIRST 10 TRACKS TRACKS RESERVED (20K FOR SYSTEM) + ; SYSTEM IS ROM LOADER, CCP, BDOS, CBIOS, AND MONITOR +DPBLK7: ; DISK PARAMETER BLOCK FLOPPY 1.44M +SPT_7: .DW 72 ; 16 SECTORS OF 128 BYTES PER 2K TRACK +BSH_7: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_7: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_7: .DB 0 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_7: .DW 710 ; BLOCKSIZE [1024] * NUMBER OF BLOCKS + 1 = DRIVE SIZE +DRM_7: .DW 255 ; NUMBER OF DIRECTORY ENTRIES +AL0_7: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_7: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + +CKS_7: .DW 32 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_7: .DW 2 ; FIRST 10 TRACKS TRACKS RESERVED (20K FOR SYSTEM) + ; SYSTEM IS ROM LOADER, CCP, BDOS, CBIOS, AND MONITOR + ; + ; IMPORTANT NOTE: TRACKS 00h - 0AH OF 2K BYTES + ; EACH ARE MARKED WITH THE OFF_6 SET TO 5 AS + ; SYSTEM TRACKS USABLE ROM DRIVE SPACE + ; STARTING AFTER THE TENTH TRACK (IE, TRACK 0AH) + ; MOST LIKELY FIX TO THIS IS PLACING A DUMMY + ; FIRST 20K ROM CONTAINS THE ROM LOADER, MONITOR, + ; CCP, BDOS, BIOS, ETC (10 TRACKS * 2K EACH) +;__________________________________________________________________________________________________ +; +; END OF FIXED CP/M TABLES +; +; INDIVIDUAL SUBROUTINES TO PERFORM EACH FUNCTION +;__________________________________________________________________________________________________ + + +;___BOOT___________________________________________________________________________________________ +BOOT: ; SIMPLEST CASE IS TO JUST PERFORM PARAMETER INITIALIZATION + ; + LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + OUT (MPCL_ROM),A ; SWITCH OUT ROM, BRING IN LOWER 32K RAM PAGE + ; + ; + LD A,#0b10000001 ; SWITCH IN FIRST 32K LOWER PAGE (FIRST TRACK) + OUT (MPCL_RAM),A ; + ; FORMATTING THE RAM IS SIMPLE AS CLEARING THE DIRECTORY AREA + ; TO A VALUE OF E5H (THE FIRST 8K OF TRACK 1 OR THE RAMDISK) + LD HL,#0000 ; STARTING MEMORY ADDRESS OF TRACK 1, SECTOR 0 IN HL + LD BC,#0x1FFF ; 8K OF DIRECTORY SECTORS RESERVED (LENGTH IN BC) + LD A,#0x0E5 ; INITIALIZING VALUE IN A + LD E,L ; + LD D,H ; + INC DE ; + LD (HL),A ; + LDIR ; + ; + LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + OUT (MPCL_ROM),A ; SWITCH OUT ROM, BRING IN LOWER 32K RAM PAGE + ; + LD A,#0 ; ENSURE LOWEST RAM PAGE SELECTED + OUT (MPCL_RAM),A ; BRING IN LOWEST 32K RAM PAGE + ; + XOR A ; ZERO IN THE ACCUM + LD (IOBYTE),A ; CLEAR THE IOBYTE + LD (CDISK),A ; SELECT DISK 0 + ; + CALL IDE_SOFT_RESET ; RESET THE IDE HARD DISK + ; + ; + JP GOCPM ; INITIALIZE AND GO TO CP/M + ; +; +;___WBOOT__________________________________________________________________________________________ +WBOOT: ; SIMPLEST CASE IS TO READ THE DISK UNTIL ALL SECTORS LOADED + ; WITH A ROMDISK WE SELECT THE ROM AND THE CORRECT PAGE [0] + ; THEN COPY THE CP/M IMAGE (CCP, BDOS, BIOS, MONITOR) TO HIGH RAM + ; LOAD ADDRESS + ; FOR Z80 IT LOOKS LIKE THIS . USING 8080 NEMONICS + ; + DI ; DISABLE INTERRUPT + LD SP,#0x80 ; USE SPACE BELOW BUFFER FOR STACK + IM 1 ; SET INTERRUPT MODE 1 + ; + XOR A ; CHEAP ZERO IN ACC + OUT (MPCL_ROM),A ; SEND 0 TO ROM MAP PORT (SWITCH IN LOWER 32K ROM PAGE) + ; + XOR A ; CHEAP ZERO IN ACC + OUT (MPCL_RAM),A ; SEND 0 TO RAM MAP PORT (SELECT LOWEST RAM PAGE) + ; + LD HL,#ROMSTART_CPM ; WHERE IN ROM CP/M IS STORED (FIRST BYTE) + LD DE,#RAMTARG_CPM ; WHERE IN RAM TO MOVE MONITOR TO (FIRST BYTE) + LD BC,#CCPSIZ_CPM ; NUMBER OF BYTES TO MOVE FROM ROM TO RAM + LDIR ; + ; + ; +;;;;; EI ; ENABLE INTERRUPTS + LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + OUT (MPCL_ROM),A ; SWITCH OUT ROM, BRING IN LOWER 32K RAM PAGE + ; + XOR A ; CHEAP ZERO IN ACC + OUT (MPCL_RAM),A ; SEND 0 TO RAM MAP PORT (SELECT LOWEST RAM PAGE) + ; + CALL IDE_SOFT_RESET ; RESET THE IDE HARD DISK + ; + .IF CONDSUPERSUB ; + ; DO NOTHING FOR ORIGINAL CODE + .ELSE ; + ; CLEAR THE AUTOSUB BUFFER, DO ON A WARM BOOT + XOR A ; + LD (INBUFF+1),A ; SECOND BYTE IS ACTUAL LENGTH + .ENDIF ; + ; FALL THROUGH TO GOCPM ROUTINE +; +; END OF LOAD OPERATION, SET PARAMETERS AND GO TO CP/M +; +;___GOCPM__________________________________________________________________________________________ +GOCPM: + ; CPU RESET HANDLER + LD A,#0x0C3 ; C3 IS A JMP INSTRUCTION + LD (0),A ; FOR JMP TO WBOOT + LD HL,#WBOOTE ; WBOOT ENTRY POINT + LD (1),HL ; SET ADDRESS FIELD FOR JMP AT 0 + ; + ; CPU INTERRUPT HANDLER + LD A,#0x0C3 ; C3 IS A JMP INSTRUCTION + LD (0x0038),A ; FOR JMP TO WBOOT + LD HL,#WBOOTE ; WBOOT ENTRY POINT + LD (1),HL ; SET ADDRESS FIELD FOR JMP AT 0 + ; + LD (5),A ; FOR JMP TO BDOS + LD HL,#BDOS ; BDOS ENTRY POINT + LD (6),HL ; ADDRESS FIELD OF JUMP AT 5 TO BDOS + ; + LD BC,#0x80 ; DEFAULT DMA ADDRESS IS 80H + CALL SETDMA ; + ; + .IF CONDUSEFLOPPY ; + CALL SETUPDRIVE ; SETUP FLOPPY PARAMETERS + .ENDIF ; + ; + .IF CONDUSEVDU ; + DI ; DISABLE INTERRUPTS + LD A,#0x1F ; SET HIGH ROM PAGE + OUT (MPCL_ROM),A ; SEND TO ROM PORT MAPPER + LD HL,#0 ; + ADD HL,SP ; GET STACK POINTER INTO HL + LD (PARKSTACK),HL ; SAVE STACK POINTER + LD SP,#FLOPPYSTACK ; + CALL VDU_INIT ; + LD SP,(PARKSTACK) ; RESTORE STACK + LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + OUT (MPCL_ROM),A ; + LD A,#0 ; CHOOSE HIGHEST RAM PAGE + OUT (MPCL_RAM),A ; SEND 19H TO RAM MAP PORT (SELECT HIGHEST RAM PAGE) +;;;;; EI ; ENABLE INTERRUPTS + .ENDIF ; + LD HL,#TXT_STARTUP_MSG ; PRINT STARTUP MESSAGE + CALL PRTMSG ; + ; + LD A,(CDISK) ; GET CURRENT DISK NUMBER + LD C,A ; SEND TO THE CCP + JP CCP ; GO TO CP/M FOR FURTHER PROCESSING + ; +;__________________________________________________________________________________________________ +; +; ** CONSOLE & PRINTER I/O -- VDU CARD DRIVER INTERFACE +; +;__________________________________________________________________________________________________ + .IF CONDUSEVDU +CONST: + PUSH HL ; STORE HL + DI ; DISABLE INTERRUPTS + LD A,#1FH ; SET HIGH ROM PAGE + OUT (MPCL_ROM),A ; SEND TO ROM PORT MAPPER + LD HL,#0 ; + ADD HL,SP ; GET STACK POINTER INTO HL + LD (PARKSTACK),HL ; SAVE STACK POINTER + LD SP,#FLOPPYSTACK ; + CALL IS_KBHIT ; CHECK FOR KB HIT + LD C,A ; STORE RESULT + LD SP,(PARKSTACK) ; RESTORE STACK + LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + OUT (MPCL_ROM),A ; + LD A,#0 ; CHOOSE HIGHEST RAM PAGE + OUT (MPCL_RAM),A ; SEND 19H TO RAM MAP PORT (SELECT HIGHEST RAM PAGE) + LD A,C ; RESTORE RESULT +;;;;; EI ; ENABLE INTERRUPTS + POP HL ; RESTORE HL + RET + +CONIN: + PUSH HL ; STORE HL + DI ; DISABLE INTERRUPTS + LD A,#0x1F ; SET HIGH ROM PAGE + OUT (MPCL_ROM),A ; SEND TO ROM PORT MAPPER + LD HL,#0 ; + ADD HL,SP ; GET STACK POINTER INTO HL + LD (PARKSTACK),HL ; SAVE STACK POINTER + LD SP,#FLOPPYSTACK ; + CALL GET_KEY ; GET KEY FROM KEYBOARD + LD C,A ; STORE RESULT + LD SP,(PARKSTACK) ; RESTORE STACK + LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + OUT (MPCL_ROM),A ; + LD A,#0x00 ; CHOOSE HIGHEST RAM PAGE + OUT (MPCL_RAM),A ; SEND 19H TO RAM MAP PORT (SELECT HIGHEST RAM PAGE) + LD A,C ; RESTORE RESULT +;;;;; EI ; ENABLE INTERRUPTS + POP HL ; RESTORE HL + RET + +CONOUT: + PUSH HL ; STORE HL + DI ; DISABLE INTERRUPTS + LD A,#0x1F ; SET HIGH ROM PAGE + OUT (MPCL_ROM),A ; SEND TO ROM PORT MAPPER + LD HL,#0 ; + ADD HL,SP ; GET STACK POINTER INTO HL + LD (PARKSTACK),HL ; SAVE STACK POINTER + LD SP,#FLOPPYSTACK ; + LD A,C ; RESTORE CHARACTER + CALL CHARIN ; DISPLAY CHARACTER + LD SP,(PARKSTACK) ; RESTORE STACK + LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + OUT (MPCL_ROM),A ; + LD A,#0x00 ; CHOOSE HIGHEST RAM PAGE + OUT (MPCL_RAM),A ; SEND 19H TO RAM MAP PORT (SELECT HIGHEST RAM PAGE) +;;;;; EI ; ENABLE INTERRUPTS + POP HL ; RESTORE HL + RET +LIST: + PUSH HL ; STORE HL + DI ; DISABLE INTERRUPTS + LD A,#0x1F ; SET HIGH ROM PAGE + OUT (MPCL_ROM),A ; SEND TO ROM PORT MAPPER + LD HL,#0 ; + ADD HL,SP ; GET STACK POINTER INTO HL + LD (PARKSTACK),HL ; SAVE STACK POINTER + LD SP,#FLOPPYSTACK ; + LD A,C ; RESTORE CHARACTER + CALL PR_OUTCHAR ; + LD SP,(PARKSTACK) ; RESTORE STACK + LD A,#0x80 ; LOAD VALUE TO SWITCH OUT ROM + OUT (MPCL_ROM),A ; + LD A,#0x00 ; CHOOSE HIGHEST RAM PAGE + OUT (MPCL_RAM),A ; SEND 19H TO RAM MAP PORT (SELECT HIGHEST RAM PAGE) +;;;;; EI ; ENABLE INTERRUPTS + POP HL ; RESTORE HL + RET + +;__________________________________________________________________________________________________ +; +; ** CONSOLE I/O -- ON-BOARD 16550 SERIAL INTERFACE +; +;__________________________________________________________________________________________________ + .ELSE +CONST: ; CONSOLE STATUS, RETURN 0FFH IF CHARACTER READY, 00H IF NOT + IN A,(UART + 5) ; READ LINE STATUS REGISTER (UART5 = 068h + $05) + AND #0x01 ; TEST IF DATA IN RECEIVE BUFFER + ; IS THERE A CHAR READY? 0=NO, 1=YES + JP Z,NOT_READY ; + LD A,#0x0FF ; YES, PUT 0FFh IN A AND RETURN +NOT_READY: ; + ; NO, LEAVE 000h IN A AND RETURN + RET ; +CONIN: ; CONSOLE CHARACTER INTO REGISTER A + ; + CALL CONST ; IS A CHAR READY TO BE READ FROM UART? + CP #0 ; + JP Z,CONIN ; NO? TRY AGAIN + IN A,(UART) ; YES? READ THE CHAR FROM THE UART (UART0 = 068h + $00) + ; REGISTER AND PASS BACK TO USER + RET ; + ; +CONOUT: ; CONSOLE CHARACTER OUTPUT FROM REGISTER C + IN A,(UART + 5) ; READ LINE STATUS REGISTER + AND #0x20 ; TEST IF UART IS READY TO SEND + JP Z,CONOUT ; IF NOT REPEAT + ; + LD A,C ; GET TO ACCUMULATOR + OUT (UART),A ; THEN WRITE THE CHAR TO UART (UART0 = 068h + $00) + RET ; + ; +LIST: ;LIST CHARACTER FROM REGISTER C + LD A,C ;CHARACTER TO REGISTER A + RET ;NULL SUBROUTINE + .ENDIF + ; +LISTST: ;RETURN LIST STATUS (0 IF NOT READY, 1 IF READY) + XOR A ;0 IS ALWAYS OK TO RETURN + RET ; + ; + ; +;__________________________________________________________________________________________________ +; +; ** PUNCH & READER I/O -- STUB +; +;__________________________________________________________________________________________________ +PUNCH: ;PUNCH CHARACTER FROM REGISTER C + LD A,C ;CHARACTER TO REGISTER A + RET ;NULL SUBROUTINE + ; +READER: ;READ CHARACTER INTO REGISTER A FROM READER DEVICE + LD A,C ;CHARACTER TO REGISTER A + RET + + +;__________________________________________________________________________________________________ +; +; ** DISK STORAGE I/O +; +;__________________________________________________________________________________________________ +; +; SELECT DISK GIVEN BY REGISTER C +;__________________________________________________________________________________________________ + +SELDSK: LD HL,#0x0000 ; ERROR RETURN CODE + LD A,C ; + .IF CONDABONLY ; + CP #7 ; MUST BE BETWEEN 0 AND 6 + .ELSE ; + CP #2 ; IF NO IDE THEN ONLY DRIVE A AND B FOR THE MINI N8VEM SO 0 OR 1 ONLY + .ENDIF ; + RET NC ; RETURN IF OUT OF RANGE + LD (DISKNO),A ; + ; DISK NUMBER IS IN THE PROPER RANGE + ; COMPUTE PROPER DISK PARAMETER HEADER ADDRESS + LD L,A ; L=DISK NUMBER 0,1,2,3,4 + LD H,#0 ; HIGH ORDER ZERO + ADD HL,HL ; *2 + ADD HL,HL ; *4 + ADD HL,HL ; *8 + ADD HL,HL ; *16 (SIZE OF EACH HEADER) + LD DE,#DPBASE ; + ADD HL,DE ; HL= DPBASE(DISKNO*16) + RET +;__________________________________________________________________________________________________ +HOME: ; MOVE TO THE TRACK 00 POSITION OF CURRENT DRIVE + ; TRANSLATE THIS CALL INTO A SETTRK CALL WITH PARAMETER 00 + LD BC,#0 ; SELECT TRACK 0000 +;__________________________________________________________________________________________________ +SETTRK: ; SET TRACK GIVEN BY REGISTER BC + LD H,B ; + LD L,C ; + LD (TRACK),HL ; + RET +;__________________________________________________________________________________________________ +SETSEC: ; SET SECTOR GIVEN BY REGISTER BC + LD H,B ; + LD L,C ; + LD (SECTOR),HL ; + RET ; +;__________________________________________________________________________________________________ +; +; TRANSLATE THE SECTOR GIVEN BY BC USING THE +; TRANSLATE TABLE GIVEN BY DE +; ONLY USED FOR FLOPPIES! FOR ROMDISK/RAMDISK/IDE/ATAPI IT'S 1:1 +; DO THE NEXT ROUTINE IS A NULL (RETURNS THE SAME) +;__________________________________________________________________________________________________ +SECTRN: + LD H,B ; + LD L,C ; + RET ; +;__________________________________________________________________________________________________ +SETDMA: ; SET DMA ADDRESS GIVEN BY REGISTERS B AND C + LD L,C ; LOW ORDER ADDRESS + LD H,B ; HIGH ORDER ADDRESS + LD (DMAAD),HL ; SAVE THE ADDRESS + RET +;________________________________________________________________________________________________________ +; DISK DRIVERS . +; +; DRIVER NEEDS TO DO SEVERAL THINGS FOR ROM AND RAM DISKS +; - INTERRUPTS ARE NOT ALLOWED DURING LOW RAM/ROM ACCESS (DISABLE!) +; -TRANSLATE TRACK AND SECTOR INTO A POINTER TO WHERE THE 128 BYTE +; SECTOR BEGINS IN THE RAM/ROM +; -TRANSLATE THE DRIVE INTO A RAM/ROM SELECT, COMBINE WITH TRACK ADDRESS +; AND SEND TO THE MAP PORT +; -COPY 128 BYTE FROM OR TO THE ROM/RAMDISK AND MEMORY POINTED TO BY THE DMA +; ADDRESS PREVIOUSLY STORED +; -RESTORE MAP PORT TO PRIOR CONDITION BEFOR READ/WRITE +; +; - FIRST TRICK IS THAT WE MADE SECTORS 256 AS 256*128=32768 SO WE COPY +; THE LOW SECTOR ADDRESS TO THE LOW BYTE OF THE HL REGISTER AND THEN +; MULTIPLY BY 128 THIS RESULTS IN THE STARTING ADDRESS IN THE RAM OR ROM +; (0000 -> 7F80H) 32K PAGE +; +; - TRICK TWO IS THE TRACK ADDRESS EQUALS THE 32K PAGE ADDRESS AND IS A +; DIRECT SELECT THAT CAN BE COPIED TO THE MAP PORT D0 THROUGH D5 D7 +; SELECTS THE DRIVE (ROM OR RAM) +; THAT MEANS THE LOW BYTE OF TRACK CONTAINS THE D0-D5 VALUE AND +; DISKNO HAS THE DRIVE SELECTED WE FIRST COPY DISKNO TO ACC +; AND RIGHTSHIFT IT TO PLACE THAT IN BIT 7, WE THEN ADD THE LOW BYTE OF +; TRACK TO ACC AND THEN SEND THAT TO THE MAP PORT +; +; NOTE 1: A WRITE TO ROM SHOULD BE FLAGGED AS AN ERROR +; NOTE 2: RAM MUST START AS A "FORMATTED DISK" IF BATTERY BACKED UP +; IT'S A DO ONCE AT COLD COLD START IF NOT BATTERY BACKED U +; IT WILL HAVE TO BE DONE EVERY TIME THE SYSTEM IS POWERED +; FORMATTING THE RAM IS SIMPLE AS CLEARING THE DIRECTORY AREA +; TO A VALUE OF E5H (THE FIRST 8K OF TRACK 1 OR THE RAMDISK) +; IT COULD BE DONE AS A SIMPLE UTILITY PROGRAM STORED IN ROMD +; OR ANYTIME COLBOOT IS CALLED(LESS DESIREABLE) +; +; -WE NOW CAN COPY TO OR FROM AS CORRECT FOR THE DEVICE 128 BYTES (SECTOR) +; TO OR FROM THE DMA ADDRESS ALMOST! SINCE ROM OR RAM IS BEING PAGED +; WE HAVE TO COPY ANYTHING DETINED FOR BELOW 8000H TO A TEMP BUFFER THEN +; HANDLE THE PAGING +; +; +; - LAST STEP IS TO RESTORE THE MAP PORT TO POINT TO THE RAM (TRACK 0) SO T +; MEMORY MAP IS ALL RAM AGAIN AND NOT POINTING INTO THE DATA AREAS OR THE +; SINCE THE RAM 0TH PAGE IS NOMINALLY THE LOW 32K OF RAM IN THE SYSTEM WE +; SEND A SIMPLE MVI A,80H ; OUT MPCL_ROM ; MVI A,00H ; OUT MPCL_RAM +; +; - THE READ OR WRITE OPERATION IS DONE +; +; READ DISK +; USES DE,DL, BC, ACC FLAGS +; Z80 COULD USE BLOCK MOVE [LDIR] BUT WRITTEN IN 8080 +;________________________________________________________________________________________________________ + +;__READ__________________________________________________________________________________________________ +; +; PERFORM CP/M SECTOR READ +;________________________________________________________________________________________________________ +READ: + DI ; DISABLE INTERRUPTS + LD A,(DISKNO) ; GET DRIVE + CP #0x01 ; "B" + .IF CONDUSEFLOPPY + JP Z,READ_FLPY_DSK ; READ FLOPPY + .ELSE + JP Z,READ_RAM_DISK ; READ FROM 448K RAM DISK + .ENDIF + CP #0 ; "B" + JP Z,READ_RAM_DISK ; READ FROM 448K RAM DISK + CP #2 ; "C" + JP Z,READ_IDE ; READ FROM 8 MB IDE HARD DISK + CP #3 ; "D" + .IF CONDUSEATAPI + JP Z,READ_ATAPI ; READ FROM 8 MB ATAPI + .ELSE + JP Z,READ_RAM_DISK ; READ FROM 448K RAM DISK + .ENDIF + + CP #4 ; "E" + JP Z,READ_HDPART4 ; READ FROM 1 MB IDE HARD DISK, PARTITION 4 ** future use + CP #5 ; "F" + JP Z,READ_RAM_DISK ; READ FROM 1M ROM DISK (UTILIZES SAME + ; ROUTINES AS RAM_DISK + ; "G" + ; READ FROM 22K EEPROM DISK , SO FALL THROUGH + +;___READ_EEPROM_DISK_____________________________________________________________________________________ +; +; READ EEPROM DISK +;________________________________________________________________________________________________________ +READ_EEPROM_DISK: + ; + ; IF ROM, MAP TRACK/SECTOR TO VIRTUAL TRACK/SECTOR + ; HANDLE READING FROM ROM HERE + ; + ; PURPOSE OF THIS ROUTINE IS TO MAP 32K ROM PART + ; TRACK/SECTOR MAP (2K TRACK SIZE MADE OF 16 128 + ; BYTE SECTORS EACH) ONTO WHAT THE RAM/ROM SECTOR + ; READ ROUTINES ARE EXPECTING (32K TRACK SIZE MADE + ; OF 256 128 BYTE SECTORS EACH) THE ROUTINE + ; CONVERTS 4 BIT TRACK # AND 4 BIT SECTOR # + ; INTO A VIRTUAL 1 TRACK, 256 SECTOR ACCESS + LD HL,(TRACK) ; TRACK # IS UPPER 4 BITS OF SECTOR ADDRESS + ADD HL,HL ; SHIFT BITS LEFT 1 (*2) + ADD HL,HL ; SHIFT BITS LEFT 1 (*4) + ADD HL,HL ; SHIFT BITS LEFT 1 (*8) + ADD HL,HL ; SHIFT BITS LEFT 1 (*16) + LD B,H ; PUT UPPER 4 BITS OF SECTOR ADDRESS IN BC + LD C,L ; (B IS UPPER BYTE AND C IS LOWER BYTE) + ; BC NOW CONTAINS THE UPDATED TRACK # + LD HL,(SECTOR) ; SECTOR # IS LOWER 4 BITS OF SECTOR ADDRESS + ADD HL,BC ; VIRTUAL SECTOR = (UPDATED TRACK #) + SECTOR # + LD (PSECTOR),HL ; STORE VIRTUAL SECTOR # + ; NOW CONTINUE READING ROM WITH REGULAR RAM + ; SETUP FOR READ OF RAM OR ROM DISK + LD HL,(PSECTOR) ; + ADD HL,HL ; SHIFT BITS LEFT 1 (*2) + ADD HL,HL ; SHIFT BITS LEFT 1 (*4) + ADD HL,HL ; SHIFT BITS LEFT 1 (*8) + ADD HL,HL ; SHIFT BITS LEFT 1 (*16) + ADD HL,HL ; SHIFT BITS LEFT 1 (*32) + ADD HL,HL ; SHIFT BITS LEFT 1 (*64) + ADD HL,HL ; SHIFT BITS LEFT 1 (*128) + LD (SECST),HL ; SAVE SECTOR STARTING ADDRESS + ; SET PAGER WITH DRIVE (0) AND TRACK (0) + LD A,#0 ; SWITCH IN ROM PAGE + OUT (MPCL_ROM),A ; SEND TO PORT MAPPER + LD (PAGER),A ; SAVE COPY (JUST BECAUSE) + LD HL,#SECTOR_BUFFER ; LOAD HL WITH TEMP BUF ADDRESS + LD E,L ; + LD D,H ; GET IT INTO DE + LD HL,(SECST) ; GET ROM/RAM ADDRESS + CALL COPY_CPM_SECTOR ; + CALL RPAGE ; SET PAGE TO CP/M RAM + LD HL,(DMAAD) ; LOAD HL WITH DMA ADDRESS + LD E,L ; + LD D,H ; GET IT INTO DE + LD HL,#SECTOR_BUFFER ; GET ROM/RAM ADDRESS + CALL COPY_CPM_SECTOR ; + LD A,(DISKNO) ; STORE CURRENT DRIVE IN BUFFER + LD (CUDISK),A ; + LD A,#0 ; +;;;;; EI ; RE-ENABLE INTERRUPTS + RET +;___READ_RAM_DISK_________________________________________________________________________________________ +; +; READ RAM DISK +;________________________________________________________________________________________________________ +READ_RAM_DISK: ; + ; IF RAM, PROCEED WITH NORMAL TRACK/SECTOR READ + CALL SECPAGE ; SETUP FOR READ OF RAM OR ROM DISK + CALL PAGERB ; SET PAGER WITH DRIVE AND TRACK + LD HL,#SECTOR_BUFFER ; LOAD HL WITH TEMP BUF ADDRESS + LD E,L ; + LD D,H ; GET IT INTO DE + LD HL,(SECST) ; GET ROM/RAM ADDRESS + CALL COPY_CPM_SECTOR ; MOVE SECTOR TO SECTOR_BUFFER + CALL RPAGE ; SET PAGE TO CP/M RAM + LD HL,(DMAAD) ; LOAD HL WITH DMA ADDRESS ; + LD E,L ; + LD D,H ; GET IT INTO DE + LD HL,#SECTOR_BUFFER ; GET ROM/RAM ADDRESS + CALL COPY_CPM_SECTOR ; MOVE SECTOR FROM SECTOR_BUFFER TO DMA AREA + LD A,(DISKNO) ; STORE CURRENT DRIVE IN BUFFER + LD (CUDISK),A ; + LD A,#0 ; +;;;;; EI ; RE-ENABLE INTERRUPTS + RET + +;___TRFLSEC______________________________________________________________________________________________ +; +; TRANSLATE LOGICAL FLOPPY DISK SECTOR TO PHYSICAL SECTOR +; IN: TRACK,SECTOR +; OUT: PTRACK,PSECTOR,SECTOR_INDEX +;________________________________________________________________________________________________________ +TRFLSEC: + LD A,(TRACK) ; LOAD TRACK # (LOW BYTE) + AND #1 ; FILTER OUT HEAD + LD (HEAD),A ; STORE HEAD + LD A,(TRACK) ; SAVE TRACK IN A + SRL A ; REMOVE HEAD BIT + LD (PTRACK),A ; STORE IN TRACK + LD A,(SECTOR) ; LOAD SECTOR # (LOW BYTE) + LD (SECTOR_INDEX),A ; STORE SECTOR IN SECTOR INDEX + SRL A ; + SRL A ; DIVIDE BY 4 (FOR BLOCKING) + LD (PSECTOR),A ; STORE IN SECTOR + LD A,(SECTOR_INDEX) ; FILTER OUT UNWANTED BITS + AND #3 ; + LD (SECTOR_INDEX),A ; + RET + +;___DEBSEC_______________________________________________________________________________________________ +; +; DEBLOCK 512 BYTE SECTOR FOR CP/M +; +;________________________________________________________________________________________________________ +DEBSEC: + LD HL,(DMAAD) ; LOAD HL WITH DMA ADDRESS + LD D,H ; TRANSFER HL REGISTERS TO DE + LD E,L ; + PUSH DE ; STORE DE + ; COMPUTE STARTING ADDRESS OF CP/M SECTOR IN READ SECTOR BUFFER + LD HL,#SECTOR_BUFFER ; LOAD HL WITH SECTOR BUFFER ADDRESS + LD A,(SECTOR_INDEX) ; GET THE SECTOR INDEX (CP/M SECTOR OFFSET IN BUFFER) + RRCA ; MOVE BIT 0 TO BIT 7 + RRCA ; DO AGAIN - IN EFFECT MULTIPLY BY 4 + LD D,#0 ; PUT RESULT AS 16 VALUE IN DE, UPPER BYTE IN D IS 000h + LD E,A ; PUT ADDRESS OFFSET IN E + ADD HL,DE ; MULTIPLY BY 2, TOTAL MULTIPLICATION IS X 128 + ADD HL,DE ; CP/M SECTOR STARTING ADDRESS IN IDE HD SECTOR BUFFER + ; COPY CP/M SECTOR TO BDOS DMA ADDRESS BUFFER + POP DE ; RESTORE DE + CALL COPY_CPM_SECTOR ; + RET + +;___BLKSEC_______________________________________________________________________________________________ +; +; BLOCK 512 BYTE SECTOR FOR CP/M +; +;________________________________________________________________________________________________________ +BLKSEC: + ; COMPUTE STARTING ADDRESS OF CP/M SECTOR IN READ SECTOR BUFFER + LD HL,#SECTOR_BUFFER ; LOAD HL WITH SECTOR BUFFER ADDRESS + LD A,(SECTOR_INDEX) ; GET THE SECTOR INDEX (CP/M SECTOR OFFSET IN BUFFER) + RRCA ; MOVE BIT 0 TO BIT 7 + RRCA ; DO AGAIN - IN EFFECT MULTIPLY BY 64 + LD D,#0 ; PUT RESULT AS 16 VALUE IN DE, UPPER BYTE IN D IS 000h + LD E,A ; PUT ADDRESS OFFSET IN E + ADD HL,DE ; CP/M SECTOR STARTING ADDRESS IN IDE HD SECTOR BUFFER + ADD HL,DE ; MULTIPLY BY 2, TOTAL MULTIPLICATION IS X 128 + LD (SECST),HL ; KEEP CP/M SECTOR ADDRESS FOR LATER USE + ; COPY CP/M SECTOR FROM BDOS DMA ADDRESS BUFFER + LD HL,(SECST) ; LOAD CP/M SECTOR ADDRESS (WHERE THE DATA IS TO BE WRITTEN) + LD D,H ; TRANSFER HL REGISTERS TO DE + LD E,L ; + LD HL,(DMAAD) ; LOAD HL WITH DMA ADDRESS (WHERE THE DATA TO BE WRITTEN IS) + CALL COPY_CPM_SECTOR ; + RET + +;___ISCUR_______________________________________________________________________________________________ +; +; IS CURRENT SECTOR IN BUFFER? +; +;________________________________________________________________________________________________________ +ISCUR: + LD HL,(PSECTOR) ; COMPARE REQUESTED SECTOR WITH SECTOR IN BUFFER + LD A,(CUSECTOR) ; + CP L ; + RET NZ ; LOW BYTE NOT EQUAL + LD A,(CUSECTOR+1) ; + CP H ; + RET NZ ; HIGH BYTE NOT EQUAL + LD HL,(PTRACK) ; COMPARE REQUESTED TRACK WITH TRACK IN BUFFER + LD A,(CUTRACK) ; + CP L ; LOW BYTE NOT EQUAL + RET NZ ; + LD A,(CUTRACK+1) ; + CP H ; + RET NZ ; HIGH BYTE NOT EQUAL + LD HL,(DISKNO) ; COMPARE REQUESTED DRIVE WITH DRIVE IN BUFFER + LD A,(CUDISK) ; + CP L ; + RET ; EXIT WITH RESULT + +;___READ_FLPY_DSK________________________________________________________________________________________ +; +; READ FLOPPY DISK +; +;________________________________________________________________________________________________________ + +READ_FLPY_DSK: + DI ; DISABLE INTERRUPTS + LD HL,#0 ; + ADD HL,SP ; GET STACK POINTER INTO HL + LD (PARKSTACK),HL ; SAVE STACK POINTER + LD SP,#FLOPPYSTACK ; + CALL TRFLSEC ; TRANSLATE SECTOR INFORMATION + CALL READ_FLPY_SEC ; + CALL DEBSEC ; DEBLOCK SECTOR + LD A,(ST1) ; LOAD RESULT CODE INTO A +READ_FLPY_DSK_EXIT: ; + LD SP,(PARKSTACK) ; RETURN STACK +;;;;; EI ; RE-ENABLE INTERRUPTS + RET + + +;___READ_FLPY_SEC________________________________________________________________________________________ +; +; READ A SECTOR FROM A FLOPPY DISK +; +;________________________________________________________________________________________________________ +READ_FLPY_SEC: + LD A,#0 ; RESET STATUS FLAG 1 + LD (ST1),A ; + CALL ISCUR ; IS CURRENT SECTOR ALREADY IN BUFFER + JP Z,READ_FLPY_SEC_OK + LD A,#20 ; 20 RETRIES + LD (RETRY),A ; + LD A,#2 ; 2 ITERATIONS OF RETRIES + LD (RETRY1),A ; +READ_FLPY_SEC_RETRY: ; + CALL FLOPPYREAD ; READ THE FLOPPY DISK SECTOR + LD A,(ST0) ; GET STATUS FLAG 0 + AND #0x0F8 ; MASK OF DRIVE AND HEAD SELECTION + LD B,A ; MOVE STATUS FLAG 0 TO B + LD A,(ST1) ; GET STATUS FLAG 1 + OR B ; IF ZERO READ WAS OK + JP Z,READ_FLPY_SEC_OK + LD A,(RETRY) ; READ NOT OK, DEC RETRY COUNTER + DEC A ; + LD (RETRY),A ; STORE NEW RETRY COUNTER + JP NZ,READ_FLPY_SEC_RETRY + CALL CYCLEFLOPPY ; CYCLE FLOPPY HEAD + LD A,#20 ; RESET TO 20 RETRIES + LD (RETRY),A ; STORE RETRY COUNTER + LD A,(RETRY1) ; DEC RETRY ITERATION COUNTER + DEC A ; + LD (RETRY1),A ; + JP NZ,READ_FLPY_SEC_RETRY + LD HL,#0x0FFFF ; SET INVALID CONDITION, BUFFER IS INVALID + LD (CUSECTOR),HL ; CURRENT PHYSICAL DISK SECTOR IN BUFFER + LD (CUTRACK),HL ; CURRENT PHYSICAL DISK TRACK IN BUFFER + RET ; +READ_FLPY_SEC_OK: ; + LD HL,(PSECTOR) ; STORE PHYSICAL SECTOR IN BUFFER + LD (CUSECTOR),HL ; + LD HL,(PTRACK) ; STORE PHYSICAL DISK TRACK IN BUFFER + LD (CUTRACK),HL ; + LD A,(DISKNO) ; STORE CURRENT DRIVE IN BUFFER + LD (CUDISK),A ; + RET + +;___READ_IDE_____________________________________________________________________________________________ +; +; READ FROM IDE HARD DISK +;________________________________________________________________________________________________________ + +READ_IDE: + DI ; DISABLE INTERRUPTS + LD HL,#0 ; + ADD HL,SP ; GET STACK POINTER INTO HL + LD (PARKSTACK),HL ; SAVE STACK POINTER + LD SP,#FLOPPYSTACK ; + ; DISABLE INTERRUPTS + CALL CONVERT_IDE_SECTOR_CPM + CALL IDE_READ_SECTOR ; READ THE IDE HARD DISK SECTOR + JP NC,READ_IDE_ERROR + CALL DEBSEC ; + LD SP,(PARKSTACK) ; RETURN STACK +;;;;; EI ; RE-ENABLE INTERRUPTS + LD A,#0 ; RETURN ERROR CODE READ SUCCESSFUL A=0 + RET ; +READ_IDE_ERROR: ; + LD SP,(PARKSTACK) ; RETURN STACK +;;;;; EI ; RE-ENABLE INTERRUPTS + LD A,#0x0FF ; RETURN ERROR CODE READ ERROR A=FF + RET + +;___READ_ATAPI_________________________________________________________________________________________ +; +; READ FROM ATAPI DEVICE +;________________________________________________________________________________________________________ +READ_ATAPI: + LD A,#0x0FF ; 255 RETRIES + LD (RETRY),A ; +READ_ATAPI_RETRY: + LD A,#0x10 ; SET TO SECONDARY DEVICE + LD (IDEDEVICE),A ; + DI ; DISABLE INTERRUPTS + LD HL,#0 ; + ADD HL,SP ; GET STACK POINTER INTO HL + LD (PARKSTACK),HL ; SAVE STACK POINTER + LD SP,#FLOPPYSTACK ; + CALL CONVERT_IDE_SECTOR_CPM + CALL ATAPI_READ_SECTOR + JP NC,READ_ATAPI_ERROR + CALL DEBSEC ; + LD SP,(PARKSTACK) ; RETURN STACK +;;;;; EI ; RE-ENABLE INTERRUPTS + LD A,#0 ; RETURN ERROR CODE READ SUCCESSFUL A=0 + RET ; +READ_ATAPI_ERROR: + LD A,(RETRY) ; READ NOT OK, DEC RETRY COUNTER + DEC A ; + LD (RETRY),A ; STORE NEW RETRY COUNTER + JP NZ,READ_ATAPI_RETRY + LD SP,(PARKSTACK) ; RETURN STACK +;;;;; EI ; RE-ENABLE INTERRUPTS + LD A,#0x0FF ; RETURN ERROR CODE READ ERROR A=FF + RET ; + +READ_HDPART4: + ; STUB + RET + +;___WRITE______________________________________________________________________________________________ +; +; HANDLE CP/M WRITE CALL +; +;________________________________________________________________________________________________________ +WRITE: + DI ; DISABLE INTERRUPTS + LD A,(DISKNO) ; GET DRIVE + CP #1 ; FIND OUT WHICH DRIVE IS BEING REQUESTED + .IF CONDUSEFLOPPY + JP Z,WRITE_FLP_DSK ; + .ELSE + JP Z,WRITE_RAM_DISK ; WRITE TO 448K RAM DISK + .ENDIF + CP #0 ; + JP Z,WRITE_RAM_DISK ; WRITE TO 448K RAM DISK + CP #2 ; + JP Z,WRITE_IDE ; WRITE TO 8 MB IDE HARD DISK, PARTITION 2 + CP #3 ; + .IF CONDUSEATAPI + JP Z,WRITE_ATAPI ; WRITE TO 8 MB IDE HARD DISK, PARTITION 3 + .ELSE + JP Z,WRITE_RAM_DISK ; WRITE TO 448K RAM DISK + .ENDIF + CP #4 ; + JP Z,WRITE_HDPART4 ; WRITE TO 1 MB IDE HARD DISK, PARTITION 4 + + +;___RDONLY______________________________________________________________________________________________ +; +; HANDLE WRITE TO READ ONLY +; +; SENDS A MESSAGE TO TERMINAL THAT ROM DRIVE IS NOT WRITEABLE +; DOES A PAUSE THEN RETURNS TO CPM WITH ERROR FLAGGED THIS IS +; DONE TO ALLOW A POSSIBLE GRACEFUL EXIT (SOME APPS MAY PUKE) +;________________________________________________________________________________________________________ +RDONLY: + LD HL,#TXT_RO_ERROR ; SET HL TO START OF ERROR MESSAGE + CALL PRTMSG ; PRINT ERROR MESSAGE + LD A,#1 ; SEND BAD SECTOR ERROR BACK + ; BDOS WILL ALSO PRINT ITS OWN ERROR MESSAGE + RET + +;___WRITE_RAM_DISK_____________________________________________________________________________________ +; +; WRITE RAM DISK +;________________________________________________________________________________________________________ +WRITE_RAM_DISK: + LD HL,#SECTOR_BUFFER ; LOAD HL WITH TEMP BUF ADDRESS + LD E,L ; + LD D,H ; GET IT INTO DE + LD HL,(DMAAD) ; GET DMA ADDRESS + CALL COPY_CPM_SECTOR ; + CALL SECPAGE ; GET RAM PAGE WRITE ADDRESS + CALL PAGERB ; SET PAGER WITH DRIVE AND TRACK + LD HL,(SECST) ; LOAD HL WITH DMA ADDRESS (WHERE TO WRITE TO) + LD E,L ; + LD D,H ; GET IT INTO DE + LD HL,#SECTOR_BUFFER ; GET TEMP BUFFER ADDRESS + CALL COPY_CPM_SECTOR ; + CALL RPAGE ; SET BACK TO RAM + LD A,(DISKNO) ; STORE CURRENT DRIVE IN BUFFER + LD (CUDISK),A ; + LD A,#0 ; +;;;;; EI ; RE-ENABLE INTERRUPTS + RET + +;___WRITE_FLP_DSK_____________________________________________________________________________________ +; +; WRITE FLOPPY DISK +;________________________________________________________________________________________________________ +WRITE_FLP_DSK: + DI ; DISABLE INTERRUPTS + LD HL,#0 ; + ADD HL,SP ; MOVE STACK POINTER TO HL + LD (PARKSTACK),HL ; SAVE STACK POINTER + LD SP,#FLOPPYSTACK ; + CALL TRFLSEC ; TRANSLATE SECTOR INFORMATION + CALL READ_FLPY_SEC ; + LD A,(ST1) ; GET STATUS CODE + JP NZ,WRITE_FLP_DSK_OK +WRITE_READ_FLPY_DSK_OK: ; + CALL BLKSEC ; BLOCK SECTOR + ; IDE HD SECTOR IS NOW UPDATED WITH CURRENT CP/M SECTOR DATA SO WRITE TO DISK + LD A,#20 ; 20 RETRIES + LD (RETRY),A ; +WRITE_FLP_DSK_RETRY: ; + CALL FLOPPYWRITE ; WRITE THE FLOPPY DISK SECTOR + LD A,(ST0) ; GET STATUS CODE 0 + AND #0x0F8 ; MASK OF DRIVE AND HEAD SELECTION + LD B,A ; MOVE STATUS CODE 0 TO B + LD A,(ST1) ; GET STATUS CODE 1 + OR B ; IF ZERO WRITE WAS OK + JP Z,WRITE_FLP_DSK_OK ; + LD A,(RETRY) ; BAD WRITE, DEC RETRY COUNTER + DEC A ; + LD (RETRY),A ; STORE NEW RETRY COUNTER + JP NZ,WRITE_FLP_DSK_RETRY ; +WRITE_FLP_DSK_OK: ; + LD SP,(PARKSTACK) ; RESTORE STACK + LD A,(ST1) ; GET STATUS CODE 1 +;;;;; EI ; RE-ENABLE INTERRUPTS + RET + + + +;___WRITE_IDE____________________________________________________________________________________________ +; +; WRITE TO IDE DEVICE +;________________________________________________________________________________________________________ +WRITE_IDE: + DI ; DISABLE INTERRUPTS + LD HL,#0 ; + ADD HL,SP ; GET STACK POINTER INTO HL + LD (PARKSTACK),HL ; SAVE STACK POINTER + LD SP,#FLOPPYSTACK ; + CALL CONVERT_IDE_SECTOR_CPM ; + CALL IDE_READ_SECTOR ; READ THE IDE HARD DISK SECTOR + JP NC,WRITE_IDE_ERROR ; + CALL BLKSEC ; DEBLOCK SECTOR + CALL IDE_WRITE_SECTOR ; WRITE THE UPDATED IDE HARD DISK SECTOR + LD SP,(PARKSTACK) ; RESTORE STACK +;;;;; EI ; RE-ENABLE INTERRUPTS + LD A,#0 ; RETURN ERROR CODE WRITE SUCCESSFUL A=0 + RET ; +WRITE_IDE_ERROR: ; + LD SP,(PARKSTACK) ; RESTORE STACK +;;;;; EI ; RE-ENABLE INTERRUPTS + LD A,#0x0FF ; RETURN ERROR CODE WRITE ERROR A=FF + RET + +;___WRITE_ATAPI__________________________________________________________________________________________ +; +; WRITE TO ATAPI DEVICE +;________________________________________________________________________________________________________ +WRITE_ATAPI: + LD A,#0x10 ; SET TO SECONDARY DEVICE + LD (IDEDEVICE),A ; + DI ; DISABLE INTERRUPTS + LD HL,#0 ; + ADD HL,SP ; GET STACK POINTER INTO HL + LD (PARKSTACK),HL ; SAVE STACK POINTER + LD SP,#FLOPPYSTACK ; + ; + CALL CONVERT_IDE_SECTOR_CPM ; + ; + CALL ATAPI_READ_SECTOR ; + JP NC,WRITE_ATAPI_ERROR ; + CALL BLKSEC ; DEBLOCK SECTOR + CALL ATAPI_WRITE_SECTOR ; + ; + LD SP,(PARKSTACK) ; RESTORE STACK +;;;;; EI ; RE-ENABLE INTERRUPTS + LD A,#0 ; RETURN ERROR CODE WRITE SUCCESSFUL A=0 + RET ; +WRITE_ATAPI_ERROR: ; + LD SP,(PARKSTACK) ; RESTORE STACK +;;;;; EI ; RE-ENABLE INTERRUPTS + LD A,#0x0FF ; RETURN ERROR CODE WRITE ERROR A=FF + RET ; + +WRITE_HDPART4: + ; STUB + RET + + +;___PRTMSG_______________________________________________________________________________________________ +; +; PRINT MESSAGE POINTED TO BY HL ON CONSOLE DEVICE +;________________________________________________________________________________________________________ +PRTMSG: + LD A,(HL) ; GET CHARACTER TO A + CP #END ; TEST FOR END BYTE + JP Z,PRTMSG1 ; JUMP IF END BYTE IS FOUND + LD C,A ; PUT CHAR TO PRINT VALUE IN REG C FOR CONOUT + CALL CONOUT ; SEND CHARACTER TO CONSOLE FROM REG C + INC HL ; INC POINTER, TO NEXT CHAR + JP PRTMSG ; TRANSMIT LOOP +PRTMSG1: + RET + + +;___SECPAGE_______________________________________________________________________________________________ +; +; UTILITY ROUTINE FOR SECTOR TO PAGE ADDRESS +;________________________________________________________________________________________________________ +SECPAGE: + LD HL,(SECTOR) ; GET SECTOR INTO HL + ADD HL,HL ; SHIFT BITS 1 TO LEFT (*2) + ADD HL,HL ; SHIFT BITS 1 TO LEFT (*4) + ADD HL,HL ; SHIFT BITS 1 TO LEFT (*8) + ADD HL,HL ; SHIFT BITS 1 TO LEFT (*16) + ADD HL,HL ; SHIFT BITS 1 TO LEFT (*32) + ADD HL,HL ; SHIFT BITS 1 TO LEFT (*64) + ADD HL,HL ; SHIFT BITS 1 TO LEFT (*128) + LD (SECST),HL ; SAVE SECTOR STARTING ADDRESS + RET + +;___PAGERB_______________________________________________________________________________________________ +; +; PAGER BYTE CREATION +; ASSEMBLES DRIVE AND TRACK AND SENDS IT TO PAGER PORT +;________________________________________________________________________________________________________ +PAGERB: + LD HL,(TRACK) ; LOAD TRACK INTO HL + LD A,(DISKNO) ; LOAD DISK INTO A + CP #5 ; IS ROM? + JP Z,ROMD ; READ FROM 1M ROM DISK + CP #6 ; IS ROM? + JP Z,ROMD ; READ FROM 22K ROM DISK + AND #1 ; MASK FOR 1 BIT OF DRIVE SELECT + RRCA ; MOVE BIT 0 TO BIT 7 + OR L ; OR L WITH ACC TO COMBINE TRACK AND DRIVE + OUT (MPCL_RAM),A ; SEND TO RAM PORT MAPPER + LD (PAGER),A ; SAVE COPY (JUST BECAUSE) + RET ; +ROMD: ; + LD A,#5 ; + AND #1 ; MASK FOR 1 BIT OF DRIVE SELECT + RRCA ; MOVE BIT 0 TO BIT 7 + OR L ; OR L WITH ACC TO COMBINE TRACK AND DRIVE + AND #0x7F ; STRIP OFF BIT 7 (ROM_ENABLE BIT) + OUT (MPCL_ROM),A ; SEND TO ROM PORT MAPPER + LD (PAGER),A ; SAVE COPY (JUST BECAUSE) + LD (DB_PAGER),A ; SAVE COPY (JUST BECAUSE) (DEBUG) + RET + +;___RPAGE_______________________________________________________________________________________________ +; +; RESET PAGER BACK TO RAM +;________________________________________________________________________________________________________ +RPAGE: + LD A,#0x80 ; DESELECT ROM PAGE + OUT (MPCL_ROM),A ; SELECT RAM + LD A,#0 ; SET TO RAM, TRACK 0 + OUT (MPCL_RAM),A ; SELECT RAM + LD (PAGER),A ; SAVE COPY OF PAGER BYTE + RET + +;___COPY_CPM_SECTOR______________________________________________________________________________________ +; +; COPIES ONE CPM SECTOR FROM ONE MEMORY ADDRESS TO ANOTHER +; INPUT +; DE SOURCE ADDRESS +; HL TARGET ADDRESS +; USES C REGISTER +;________________________________________________________________________________________________________ +COPY_CPM_SECTOR: + LD BC,#128 ; BC IS COUNTER FOR FIXED SIZE TRANSFER (128 BYTES) + LDIR ; TRANSFER + RET + +;___CONVERT_IDE_SECTOR_CPM________________________________________________________________________________ +; +; COMPUTES WHERE THE CP/M SECTOR IS IN THE LBA PARTITION +; LBA HD SECTORS ARE 512 BYTES EACH, CP/M SECTORS ARE 128 BYTES EACH +; MAXIMUM SIZE OF CP/M DISK IS 8 MB = 65536 (16 BITS) X 128 BYTES PER SECTOR +; LBA HD PARTITION CAN HAVE AT MOST 16777215 IDE SECTORS -> 67108860 CP/M SECTORS +; EACH IDE HD SECTOR CONTAINS 4 ADJACENT CP/M SECTORS +; +; +; INPUT: +; - CP/M TRACK AND SECTOR 16 BIT WORDS +; +; OUTPUT: +; IDE TARGET SECTOR (SENT TO IDE HD CONTROLLER FOR READ OPERATION) +; - LOWER 16 BITS STORED IN LBA_TARGET_LO +; - UPPER 16 BITS STORED IN LBA_TARGET_HI +; CP/M TO IDE HD SECTOR MAPPING PARAMETER STORED IN SECTOR_INDEX +; - 8 BIT VALUE WITH 4 LEGAL STATES (00, 01, 02, 04) WHICH IS +; TO BE USED TO COMPUTE STARTING ADDRESS OF 128 BYTE CP/M SECTOR ONCE +; 512 BYTE IDE HD SECTOR READ INTO MEMORY BUFFER +; LBA ADDRESS FORMAT = 00TTTTSS +; +; ROTATE WITH CARRY 16 BIT TRACK,SECTOR VALUE IN HL TO GET 14 BIT IDE HD +; TARGET SECTOR IN PARTITION +; KEEP LAST TWO BITS IN B FOR IDE HD SECTOR TO CP/M SECTOR TRANSLATION +; COMPUTE SECTOR_INDEX +;________________________________________________________________________________________________________ +CONVERT_IDE_SECTOR_CPM: + + LD A,(TRACK) ; LOAD TRACK # (LOW BYTE) + LD H,A ; + LD A,(SECTOR) ; LOAD SECTOR# (LOW BYTE) + LD L,A ; + CALL RRA16 ; ROTATE 'HL' RIGHT (DIVIDE BY 2) + CALL RRA16 ; ROTATE 'HL' RIGHT (DIVIDE BY 2) + LD A,(TRACK+1) ; GET HIGH BYTE OF TRACK INTO A + SLA A ; + SLA A ; + SLA A ; + SLA A ; + SLA A ; + SLA A ; + OR H ; + LD H,A ; + LD A,(TRACK+1) ; GET HIGH BYTE OF TRACK INTO A + SRL A ; + SRL A ; + LD (LBA_TARGET_HI),A ; + LD A,L ; + LD (LBA_TARGET_LO),A ; LBA REGISTER IS 00TTTTSS / 4 + LD A,H ; + LD (LBA_TARGET_LO+1),A ; + LD A,#0 ; + LD (LBA_TARGET_HI+1),A ; + ; + LD HL,(LBA_TARGET_LO) ; STORE PHYSICAL SECTOR + LD (PSECTOR),HL ; + LD HL,(LBA_TARGET_HI) ; STORE PHYSICAL TRACK + LD (PTRACK),HL ; + LD A,(SECTOR) ; LOAD SECTOR # + AND #0b000000011 ; + LD (SECTOR_INDEX),A ; LOCATES WHERE THE 128 BYTE CP/M SECTOR + ; IS WITHIN THE 512 BYTE IDE HD SECTOR + ; COMPUTE WHICH IDE HD SECTOR TO READ TO WITHIN 4 CP/M SECTORS + ; SHIFTS 16 BIT PARTITION OFFSET TO THE RIGHT 2 BITS AND ADDS RESULT TO + ; IDE HD PARTITION STARTING SECTOR + ; SHIFT PARTITION OFFSET RIGHT 1 BIT + RET +RRA16: + SCF ; + CCF ; CLEAR CARRY FLAG + LD A,H ; 16 BIT ROTATE HL WITH CARRY + RRA ; + LD H,A ; ROTATE HL RIGHT 1 BIT (DIVIDE BY 2) + LD A,L ; + RRA ; + LD L,A ; + RET + + +;___IDE_READ_SECTOR______________________________________________________________________________________ +; +; READ IDE SECTOR +;________________________________________________________________________________________________________ +IDE_READ_SECTOR: + CALL ISCUR ; IS CURRENT SECTOR IN BUFFER? + JP Z,IDE_READ_SECTOR_OK ; + CALL IDE_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + RET NC ; ERROR, RETURN + CALL IDE_SETUP_LBA ; TELL DRIVE WHAT SECTOR IS REQUIRED + LD A,#0x20 ; + OUT (IDESTTS),A ; 020h = IDE 'READ SECTOR' COMMAND +IDE_SREX: ; + CALL IDE_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + RET NC ; ERROR, RETURN + CALL IDE_TEST_ERROR ; ENSURE NO ERROR WAS REPORTED + RET NC ; ERROR, RETURN + CALL IDE_WAIT_BUFFER ; WAIT FOR FULL BUFFER SIGNAL FROM DRIVE + RET NC ; ERROR, RETURN + CALL IDE_READ_BUFFER ; GRAB THE 256 WORDS FROM THE BUFFER + SCF ; CARRY = 1 ON RETURN = OPERATION OK +IDE_READ_SECTOR_OK: ; + LD HL,(PSECTOR) ; STORE PHYSICAL SECTOR IN BUFFER + LD (CUSECTOR),HL ; + LD HL,(PTRACK) ; STORE PHYSICAL DISK TRACK IN BUFFER + LD (CUTRACK),HL ; + LD A,(DISKNO) ; STORE CURRENT DRIVE IN BUFFER + LD (CUDISK),A ; + SCF ; CARRY = 1 ON RETURN = OPERATION OK + RET + +;___IDE_WRITE_SECTOR_____________________________________________________________________________________ +; +; WRITE IDE SECTOR +;________________________________________________________________________________________________________ +IDE_WRITE_SECTOR: + CALL IDE_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + RET NC ; ERROR, RETURN + CALL IDE_SETUP_LBA ; TELL DRIVE WHAT SECTOR IS REQUIRED + LD A,#0x30 ; + OUT (IDESTTS),A ; 030h = IDE 'WRITE SECTOR' COMMAND + CALL IDE_WAIT_BUSY_READY ; + RET NC ; ERROR, RETURN + CALL IDE_TEST_ERROR ; ENSURE NO ERROR WAS REPORTED + RET NC ; ERROR, RETURN + CALL IDE_WAIT_BUFFER ; WAIT FOR BUFFER READY SIGNAL FROM DRIVE + RET NC ; ERROR, RETURN + CALL IDE_WRITE_BUFFER ; SEND 256 WORDS TO DRIVE'S BUFFER + CALL IDE_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + RET NC ; ERROR, RETURN + CALL IDE_TEST_ERROR ; ENSURE NO ERROR WAS REPORTED + RET NC ; ERROR, RETURN + SCF ; CARRY = 1 ON RETURN = OPERATION OK + RET + +;___IDE_SOFT_RESET_______________________________________________________________________________________ +; +; RESET IDE CHANNEL +;________________________________________________________________________________________________________ +IDE_SOFT_RESET: + .IF CONDIDESOFT ; + LD A,#0b000000110 ; NO INTERRUPTS, RESET DRIVE = 1 + OUT (IDECTRL),A ; + LD A,#0b000000010 ; NO INTERRUPTS, RESET DRIVE = 0 + OUT (IDECTRL),A ; + CALL IDE_WAIT_BUSY_READY ;THIS TAKES A COUPLE OF SECONDS + RET + .ELSE + ; SKIP THIS IF NO IDE DRIVE WHICH SPEEDS UP REBOOTS AND STARTUPS + RET + .ENDIF + +;___ATAPI_WAIT_BUSY_READY________________________________________________________________________________ +; +; WAIT FOR ATAPI CHANNEL TO BE READY +;________________________________________________________________________________________________________ +ATAPI_WAIT_BUSY_READY: + LD DE,#0 ; CLEAR OUT DE +ATAPI_WBSY: ; + LD B,#0x0F0 ; SETUP TIMEOUT +ATAPI_DLP: ; + DJNZ ATAPI_DLP ; + INC DE ; + LD A,D ; + OR E ; + JR Z,ATAPI_TO ; + IN A,(IDESTTS) ; READ ERROR REG + AND #0b010000000 ; MASK OFF BUSY BIT + JR NZ,ATAPI_WBSY ; WE WANT BUSY(7) TO BE 0 + SCF ; CARRY 1 = OK + RET ; +ATAPI_TO: ; + XOR A ; CARRY 0 = TIMED OUT + RET ; + +;___IDE_WAIT_DRQ_READY___________________________________________________________________________________ +; +; WAIT FOR IDE CHANNEL TO BE READY +;________________________________________________________________________________________________________ +IDE_WAIT_DRQ_READY: + IN A,(IDESTTS) ; READ ERROR REG + AND #0b000001000 ; MASK OFF RDY BIT + JR Z,IDE_WAIT_DRQ_READY ; WE WANT DRQ(3) TO BE 1 + RET + +;___IDE_WAIT_DRQ_ZERO____________________________________________________________________________________ +; +; WAIT FOR IDE DRQ TO BE ZERO +;________________________________________________________________________________________________________ +IDE_WAIT_DRQ_ZERO: + IN A,(IDESTTS) ; READ ERROR REG + AND #0b000001000 ; MASK OFF RDY BIT + JR NZ,IDE_WAIT_DRQ_ZERO ; WE WANT DRQ(3) TO BE 0 + RET + +;___IDE_WAIT_BUSY_READY___________________________________________________________________________________ +; +; WAIT FOR IDE CHANNEL TO BE READY +;________________________________________________________________________________________________________ +IDE_WAIT_BUSY_READY: + LD DE,#0 ; CLEAR DE +IDE_WBSY: ; + LD B,#5 ; SETUP TIMEOUT +IDE_DLP: ; + DEC B ; + JP NZ,IDE_DLP ; + INC DE ; + LD A,D ; + OR E ; + JP Z,IDE_TO ; + IN A,(IDESTTS) ; READ ERROR REG + AND #0b011000000 ; MASK OFF BUSY AND RDY BITS + XOR #0b001000000 ; WE WANT BUSY(7) TO BE 0 AND RDY(6) TO BE 1 + JP NZ,IDE_WBSY ; + SCF ; CARRY 1 = OK + RET +IDE_TO: + XOR A ; CARRY 0 = TIMED OUT + RET + +;___IDE_TEST_ERROR_______________________________________________________________________________________ +; +; CHECK FOR IDE ERROR CONDITION +;________________________________________________________________________________________________________ +IDE_TEST_ERROR: + SCF ; + IN A,(IDESTTS) ; + LD B,A ; + AND #0b000000001 ; TEST ERROR BIT + SCF ; + RET Z ; + LD A,B ; + AND #0b000100000 ; + SCF ; + JP NZ,IDE_ERR ; TEST WRITE ERROR BIT + IN A,(IDEERR) ; READ ERROR FLAGS +IDE_ERR: + OR A ; CARRY 0 = ERROR + RET ; IF A = 0, IDE BUSY TIMED OUT + +;___IDE_WAIT_BUFFER_______________________________________________________________________________________ +; +; WAIT FOR DATA BUFFER READY +;________________________________________________________________________________________________________ +IDE_WAIT_BUFFER: + LD DE,#0 ; +IDE_WDRQ: ; + LD B,#5 ; +IDE_BLP: ; + DEC B ; + JP NZ,IDE_BLP ; + INC DE ; + LD A,D ; + OR E ; + JP Z,IDE_TO2 ; + IN A,(IDESTTS) ; WAIT FOR DRIVE'S 512 BYTE READ BUFFER + AND #0b000001000 ; TO FILL (OR READY TO FILL) + JP Z,IDE_WDRQ ; + SCF ; CARRY 1 = OK + RET ; +IDE_TO2: ; + XOR A ; CARRY 0 = TIMED OUT + RET ; + +;___IDE_READ_BUFFER_______________________________________________________________________________________ +; +; READ IDE BUFFER +;________________________________________________________________________________________________________ +IDE_READ_BUFFER: + PUSH HL ; + LD HL,#SECTOR_BUFFER ; + LD B,#0 ; 256 WORDS (512 BYTES PER SECTOR) +IDEBUFRD: ; + IN A,(IDELO) ; LOW BYTE OF WORD FIRST + LD (HL),A ; + IN A,(IDEHI) ; THEN HIGH BYTE OF WORD + INC HL ; + LD (HL),A ; + INC HL ; + DEC B ; + JP NZ,IDEBUFRD ; + POP HL ; + RET + +;___IDE_WRITE_BUFFER_______________________________________________________________________________________ +; +; WRITE TO IDE BUFFER +;________________________________________________________________________________________________________ +IDE_WRITE_BUFFER: + PUSH HL ; + LD HL,#SECTOR_BUFFER ; + LD B,#0 ; 256 WORDS (512 BYTES PER SECTOR) +IDEBUFWT: + INC HL ; + LD A,(HL) ; + DEC HL ; + OUT (IDEHI),A ; SET UP HIGH LATCHED BYTE BEFORE + LD A,(HL) ; + OUT (IDELO),A ; WRITING WORD WITH WRITE TO LOW BYTE + INC HL ; + INC HL ; + DEC B ; + JP NZ,IDEBUFWT ; + POP HL ; + RET + +;___IDE_SETUP_LDA________________________________________________________________________________________ +; +; SETUP IDE DRIVE FOR LDA OPERATION +;________________________________________________________________________________________________________ +IDE_SETUP_LBA: + LD A,(LBA_TARGET_LO) ; LOAD LBA REGISTER 0 WITH SECTOR ADDRESS TO READ + LD (IDE_LBA0),A ; + LD A,(LBA_TARGET_LO+1) ; LOAD LBA REGISTER 1 WITH SECTOR ADDRESS TO READ + LD (IDE_LBA1),A ; + LD A,(LBA_TARGET_HI) ; LOAD LBA REGISTER 2 WITH SECTOR ADDRESS TO READ + LD (IDE_LBA2),A ; + LD A,(LBA_TARGET_HI+1) ; LOAD LBA REGISTER 3 WITH SECTOR ADDRESS TO READ + AND #0b000001111 ; ONLY LOWER FOUR BITS ARE VALID + ADD A,#0b011100000 ; ENABLE LBA BITS 5:7=111 IN IDE_LBA3 + LD (IDE_LBA3),A ; + ; READ IDE HD SECTOR + LD A,#1 ; + OUT (IDESECTC),A ; SET SECTOR COUNT = 1 + ; + LD A,(IDE_LBA0) ; + OUT (IDESECTN),A ; SET LBA 0:7 + ; + LD A,(IDE_LBA1) ; + OUT (IDECYLLO),A ; SET LBA 8:15 + ; + LD A,(IDE_LBA2) ; + OUT (IDECYLHI),A ; SET LBA 16:23 + ; + LD A,(IDE_LBA3) ; + AND #0b000001111 ; LOWEST 4 BITS USED ONLY + OR #0b011100000 ; TO ENABLE LBA MODE + OUT (IDEHEAD),A ; SET LBA 24:27 + BITS 5:7=111 + .IF CONDUSEDSKY + CALL IDESEGDISPLAY ; + .ENDIF + RET + +;___ATAPI_SOFT_RESET_____________________________________________________________________________________ +; +; RESET ATAPI BUS +;________________________________________________________________________________________________________ +ATAPI_SOFT_RESET: + LD A,#0b000001110 ;NO INTERRUPTS, RESET DRIVE = 1 + OUT (IDECTRL),A ; + CALL DELAY24 ; + LD A,#0b000001010 ;NO INTERRUPTS, RESET DRIVE = 0 + OUT (IDECTRL),A ; + CALL ATAPI_WAIT_BUSY_READY ; + RET NC ; ERROR, RETURN + CALL ATAPI_DEVICE_SELECTION ; + CALL DELAY24 ; + CALL REQUEST_SENSE_LOOP ; + RET + +;___REQUEST_SENSE_LOOP____________________________________________________________________________________ +; +; ATAPI_REQUEST SENSE DATA +;_________________________________________________________________________________________________________ +REQUEST_SENSE_LOOP: + LD HL,#ATAPI_REQUEST_SENSE ; + CALL ATAPI_SEND_PACKET ; + CALL ATAPI_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + RET NC ; ERROR, RETURN + LD B,#0 ; 256 WORDS (512 BYTES PER SECTOR) +REQUEST_SENSE_LOOP1: ; + IN A,(IDELO) ; + INC IX ; + IN A,(IDEHI) ; + INC IX ; + DJNZ REQUEST_SENSE_LOOP1 ; + RRD ; DELAY ONLY + IN A,(IDESTTS) ;READ ERROR REG + AND #0b000000001 ;MASK OFF BIT + JR NZ,REQUEST_SENSE_LOOP ; + RET + +;___ATAPI_DEVICE_SELECTION________________________________________________________________________________ +; +; ATAPI DEVICE SELECTION +;_________________________________________________________________________________________________________ +ATAPI_DEVICE_SELECTION: + + LD A,(IDEDEVICE) ; SELECTS DEVICE + OR #0x0A0 ; + OUT (IDEHEAD),A ; + RET ; + + + +;__ATAPI_READ_SECTOR_____________________________________________________________________________________________________________ +; READ ATAPI SECTOR +; +; D E H L = SECTOR (DOUBLE WORD) TO READ +;________________________________________________________________________________________________________________________________ +ATAPI_READ_SECTOR: + CALL ISCUR ; + JP Z,ATAPI_READ_DATA_EXIT ; + LD A,(LBA_TARGET_LO) ; LOAD LBA REGISTER 0 WITH SECTOR ADDRESS TO READ + LD (READ_DISK_PACKET+5),A ; + LD A,(LBA_TARGET_LO+1) ; LOAD LBA REGISTER 1 WITH SECTOR ADDRESS TO READ + LD (READ_DISK_PACKET+4),A ; + LD A,(LBA_TARGET_HI) ; LOAD LBA REGISTER 2 WITH SECTOR ADDRESS TO READ + LD (READ_DISK_PACKET+3),A ; + LD A,(LBA_TARGET_HI+1) ; LOAD LBA REGISTER 3 WITH SECTOR ADDRESS TO READ + LD (READ_DISK_PACKET+2),A ; + .IF CONDUSEDSKY + CALL ATAPISEGDISPLAY ; + .ENDIF + CALL REQUEST_SENSE_LOOP ; GET ATAPI SENSE CODES TO CLEAR ERRORS + LD HL,#READ_DISK_PACKET ; SET POINTER TO READ SECTOR PACKET + CALL ATAPI_SEND_PACKET ; SEND PACKET COMMAND + CALL ATAPI_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + RET NC ; ERROR, RETURN + LD B,#0 ; 256 WORDS (512 BYTES PER SECTOR) + LD IX,#SECTOR_BUFFER ; + IN A,(IDESTTS) ; READ REG + AND #0b000001000 ; MASK OFF BIT + CP #8 ; IS DATA WAITING? + JR NZ,ATAPI_READ_DATA_EXIT ; NO, EXIT +ATAPI_READ_DATA_LOOP: + IN A,(IDELO) ; + + LD (IX),A ; + + INC IX ; + IN A,(IDEHI) ; + + LD (IX),A ; + + INC IX ; + DJNZ ATAPI_READ_DATA_LOOP ; +ATAPI_READ_DATA_EXIT: ; + LD HL,(PSECTOR) ; STORE PHYSICAL SECTOR IN BUFFER + LD (CUSECTOR),HL ; + LD HL,(PTRACK) ; STORE PHYSICAL DISK TRACK IN BUFFER + LD (CUTRACK),HL ; + LD A,(DISKNO) ; STORE CURRENT DRIVE IN BUFFER + LD (CUDISK),A ; + SCF ; CARRY = 1 ON RETURN = OPERATION OK + RET ; + + + +;__ATAPI_WRITE_SECTOR_____________________________________________________________________________________________________________ +; WRITE ATAPI SECTOR +; +; D E H L = SECTOR (DOUBLE WORD) TO WRITE +;________________________________________________________________________________________________________________________________ +ATAPI_WRITE_SECTOR: + + LD A,(LBA_TARGET_LO) ; LOAD LBA REGISTER 0 WITH SECTOR ADDRESS TO READ + LD (WRITE_DISK_PACKET+5),A ; + LD A,(LBA_TARGET_LO+1) ; LOAD LBA REGISTER 1 WITH SECTOR ADDRESS TO READ + LD (WRITE_DISK_PACKET+4),A ; + LD A,(LBA_TARGET_HI) ; LOAD LBA REGISTER 2 WITH SECTOR ADDRESS TO READ + LD (WRITE_DISK_PACKET+3),A ; + LD A,(LBA_TARGET_HI+1) ; LOAD LBA REGISTER 3 WITH SECTOR ADDRESS TO READ + LD (WRITE_DISK_PACKET+2),A ; + .IF CONDUSEDSKY + CALL ATAPISEGDISPLAY ; + .ENDIF + CALL REQUEST_SENSE_LOOP ; + LD HL,#WRITE_DISK_PACKET ; SET POINTER TO WRITE PACKET COMMAND + CALL ATAPI_SEND_PACKET ; SEND THE PACKET COMMAND + CALL ATAPI_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + RET NC ; ERROR, RETURN + LD B,#0 ; 256 WORDS (512 BYTES PER SECTOR) + LD IX,#SECTOR_BUFFER ; +ATAPI_WRITE_DATA_LOOP: + IN A,(IDESTTS) ; READ REG + + LD A,(IX) ; + + PUSH AF ; + INC IX ; + + LD A,(IX) ; + + OUT (IDEHI),A ; + POP AF ; + OUT (IDELO),A ; + INC IX ; + DJNZ ATAPI_WRITE_DATA_LOOP ; + SCF ; CARRY = 1 ON RETURN = OPERATION OK + RET ; + + + + +;__ATAPI_SEND_PACKET_____________________________________________________________________________________________________________ +; SEND PACKET POINTED TO BY HL TO ATAPI DRIVE +; +;________________________________________________________________________________________________________________________________ +ATAPI_SEND_PACKET: + + CALL ATAPI_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + RET NC ; ERROR, RETURN + CALL IDE_WAIT_DRQ_ZERO ; + ; + LD A,#0x0A ; + OUT (IDECTRL),A ; DISABLE INT + LD A,#0 ; + OUT (IDEERR),A ; + LD A,#0 ; + OUT (IDESECTC),A ; + LD A,#0 ; + OUT (IDESECTN),A ; + LD A,#0 ; + OUT (IDECYLLO),A ; + LD A,#0x60 ; + OUT (IDECYLHI),A ; + LD A,(IDEDEVICE) ; + OUT (IDEHEAD),A ; BIT 4 SELECTS DEVICE + LD A,#0x0A0 ; + OUT (IDESTTS),A ; + ; + CALL IDE_WAIT_DRQ_READY ; MAKE SURE DRIVE IS READY TO PROCEED + ; + LD B,#6 ; SEND 12 BYTES (6 WORDS) + ; +ATAPI_SEND_PACKET_LOOP: + LD A,(HL) ; GET BYTE + LD D,A ; STORE LOW BYTE IN D + INC HL ; INC POINTER + LD A,(HL) ; GET HIGH BYTE + OUT (IDEHI),A ; STORE HIGH BYTE + LD A,D ; MOVE LOW BYTE INTO A + OUT (IDELO),A ; STORE LOW BYTE + INC HL ; INC POINTER + IN A,(IDECTRL) ; GET STATUS + DJNZ ATAPI_SEND_PACKET_LOOP ; LOOP + ; + CALL ATAPI_WAIT_BUSY_READY ; MAKE SURE DRIVE IS READY TO PROCEED + RET NC ; ERROR, RETURN + IN A,(IDECTRL) ; READ STATUS (FOR DELAY) + ; + RET ; + +;__SETUPDRIVE__________________________________________________________________________________________________________________________ +; +; SETUP FLOPPY DRIVE SETTINGS +;________________________________________________________________________________________________________________________________ +; +SETUPDRIVE: + LD A,#RESETL ; RESET SETTINGS +.IF COND144FLOPPY-1 + OR MINI ; SELECT MINI FLOPPY (LOW DENS=1, HIGH DENS=0) +.ENDIF + OR #PRECOMP ; SELECT PRECOMP + OR #FDDENSITY ; SELECT DENSITY + OR #FDREADY ; SELECT READY SIGNAL + LD (FLATCH_STORE),A ; SAVE SETTINGS + LD A,#1 ; + LD (UNIT),A ; SET UNIT 1 + LD A,#2 ; DENSITY + LD (DENS),A ; + LD A,#9 ; +.IF COND144FLOPPY + ADD A,A +.ENDIF + LD (EOTSEC),A ; LAST SECTOR OF TRACK + LD A,#0x7F ; + LD (SRTHUT),A ; STEP RATE AND HEAD UNLOAD TIME + LD A,#5 ; + LD (HLT),A ; HEAD LOAD TIME + LD A,#0x0D ; + LD (GAP),A ; GAP +;; LD A,#0x80 ; +;; LD (SECSIZ),A ; SECTOR SIZE /4 + ; + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + ; + LD HL,#FLATCH_STORE ; POINT TO FLATCH + RES 1,(HL) ; SET MOTOR ON + CALL OUTFLATCH ; OUTPUT TO CONTROLLER + NOP ; + NOP ; + LD A,#0 ; ZERO TRACK + LD (PTRACK),A ; STORE TRACK + CALL SETTRACK ; DO IT + NOP ; + NOP ; + LD HL,#FLATCH_STORE ; POINT TO FLATCH + SET 1,(HL) ; SET MOTOR OFF + CALL OUTFLATCH ; OUTPUT TO CONTROLLER + RET +; +;__OUTFLATCH__________________________________________________________________________________________________________________________ +; +; SEND SETTINGS TO FLOPPY CONTROLLER +;________________________________________________________________________________________________________________________________ +; +OUTFLATCH: + LD A,(FLATCH_STORE) ; SET A TO SETTINGS + OUT (FLATCH),A ; OUTPUT TO CONTROLLER + RET + +;__FLOPPYREAD__________________________________________________________________________________________________________________________ +; +; READ A FLOPPY DISK SECTOR +;________________________________________________________________________________________________________________________________ +; +FLOPPYREAD: + .IF CONDUSEDSKY + CALL SEGDISPLAY ; + .ENDIF + LD A,#0x46 ; BIT 6 SETS MFM, 06H IS READ COMMAND + LD (CMD),A ; + JP DSKOP ; +; +;__FLOPPYWRITE__________________________________________________________________________________________________________________________ +; +; WRITE A FLOPPY DISK SECTOR +;________________________________________________________________________________________________________________________________ +; +FLOPPYWRITE: + .IF CONDUSEDSKY + CALL SEGDISPLAY ; + .ENDIF + LD A,#0x45 ; BIT 6 SETS MFM, 05H IS WRITE COMMAND + LD (CMD),A ; + JP DSKOP ; +; +;__DSKOP__________________________________________________________________________________________________________________________ +; +; PERFORM A DISK OPERATION +;________________________________________________________________________________________________________________________________ +; +DSKOP: + LD HL,#FLATCH_STORE ; POINT TO FLATCH + SET 1,(HL) ; SET MOTOR OFF + CALL OUTFLATCH ; OUTPUT TO CONTROLLER + ; + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + CP #0x0FF ; DID IT RETURN WITH ERROR CODE? + JP Z,DSKEXIT ; IF YES, EXIT WITH ERROR CODE + ; + LD A,(UNIT) ; GET DISK UNIT NUMBER + AND #3 ; MASK FOR FOUR DRIVES + LD B,A ; PARK IT IN B + LD A,(HEAD) ; GET HEAD SELECTION + AND #1 ; INSURE SINGLE BIT + RLA ; + RLA ; MOVE HEAD TO BIT 2 POSITION + OR B ; OR HEAD TO UNIT BYTE IN COMMAND BLOCK + LD (UNIT),A ; STORE IN UNIT + ; + LD HL,#FLATCH_STORE ; POINT TO FLATCH + RES 1,(HL) ; SET MOTOR ON + CALL OUTFLATCH ; OUTPUT TO CONTROLLER + ; + LD A,#3 ; SPECIFY COMMAND + CALL PFDATA ; PUSH IT + LD A,(SRTHUT) ; STEP RATE AND HEAD UNLOAD TIME + CALL PFDATA ; PUSH THAT + LD A,(HLT) ; + CALL PFDATA ; PUSH THAT + ; + CALL SETTRACK ; PERFORM SEEK TO TRACK + ; + JP NZ,DSKEXIT ; IF ERROR, EXIT + ; + LD A,(CMD) ; WHAT COMMAND IS PENDING? + OR A ; SET FLAGS + JP DOSO4 ; NO, MUST BE READ OR WRITE COMMAND +DSKEXIT: + LD HL,#FLATCH_STORE ; POINT TO FLATCH + SET 1,(HL) ; SET MOTOR OFF + CALL OUTFLATCH ; OUTPUT TO CONTROLLER + ; + OR #0x0FF ; SET -1 IF ERROR + RET + +RESULT: + LD C,#7 ; LOAD C WITH NUMBER OF STATUS BYTES + LD HL,#ST0 ; POINT TO STATS STORAGE +RS3: + CALL GFDATA ; GET FIRST BYTE + LD (HL),A ; SAVE IT + INC HL ; POINTER++ + DEC C ; CC-1 + JP NZ,RS3 ; LOOP TIL C0 + LD A,(ST0) ; LOAD STS0 + AND #0x0F8 ; MASK OFF DRIVE # + LD B,A ; PARK IT + LD A,(ST1) ; LOAD STS1 + OR B ; ACC OR B ->ACC IF 0 THEN SUCCESS + ; +RSTEXIT: + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + LD HL,#FLATCH_STORE ; POINT TO FLATCH + SET 1,(HL) ; SET MOTOR OFF + CALL OUTFLATCH ; OUTPUT TO CONTROLLER + ; + .IF CONDUSEDSKY + CALL SEGDISPLAY ; + .ENDIF + RET ; DONE RETURN TO CALLER + + +DOSO4: + ; +.IF 1 ; +INT_LOC = 0x038 ; IM 1 INTERRUPT CALLS GO HERE +; SET UP FOR I/O AT INTERRUPT LEVEL + LD DE,#INT_LOC + LD HL,#INT_RD + LD BC,#L_INT_RD + LD A,(CMD) ; + AND #0b000000001 ; WRITE IS 1 + JP Z,IS_READ + ADD HL,BC +IS_READ: + LDIR +.ENDIF + + LD HL,#SECTOR_BUFFER ; GET BUFFER ADDRESS TO HL +;; LD A,(SECSIZ) ; XFERLEN +;; LD C,A ; C WILL BE THE NUMBER OF TRANSACTIONS + ; DIVIDED BY 4 + + ld de,(FSECSIZ) ; GET FULL SECTOR SIZE + LD B,E + LD C,#FDATA ; GET DATA REGISTER I/O ADDRESS + + LD A,(CMD) ; + CALL PFDATA ; PUSH COMMAND TO I8272 + LD A,(UNIT) ; + CALL PFDATA ; + LD A,(PTRACK) ; + CALL PFDATA ; + LD A,(HEAD) ; + CALL PFDATA ; + LD A,(PSECTOR) ; + INC A ; + CALL PFDATA ; + LD A,(DENS) ; + CALL PFDATA ; WHAT DENSITY + LD A,(EOTSEC) ; + CALL PFDATA ; ASSUME SC (SECTOR COUNT) EOT + LD A,(GAP) ; + CALL PFDATA ; WHAT GAP IS NEEDED + LD A,(DTL) ; DTL, IS THE LAST COMMAND BYTE TO I8272 + CALL PFDATAS ; +; +; +; PERFORM READ / WRITE +; + + +RDD_POLL: + +FDC_RW_P0: + EI + HALT + JP NZ,FDC_RW_P0 ;10 COUNT THRU 256 BYTES +FDC_RW_P1: + EI + HALT + JP NZ,FDC_RW_P1 ;10 COUNT THRU 256 BYTES + + +; FALL THROUGH WITH INTERRUPTS DISABLED (NOT ENABLED IN INTERRUPT SERVICE) + + +DSKOPEND: + LD HL,#FLATCH_STORE ; POINT TO FLATCH + SET 0,(HL) ; SET TC + CALL OUTFLATCH ; OUTPUT TO CONTROLLER + NOP ; + NOP ; 2 MICROSECOND DELAY + RES 0,(HL) ; RESET TC + CALL OUTFLATCH ; OUTPUT TO CONTROLLER + NOP ; + NOP ; 2 MICROSECOND DELAY + NOP ; + NOP ; 2 MICROSECOND DELAY + SET 1,(HL) ; TURN OFF MOTOR + CALL OUTFLATCH ; OUTPUT TO CONTROLLER + JP RESULT ; GET STATUS BYTES + + + +INT_RD: INI + RET +IRTEMP: +L_INT_RD = IRTEMP - INT_RD + +INT_WR: OUTI + RET +IWTEMP: +L_INT_WR = IWTEMP - INT_WR + + + +;__SETTRACK__________________________________________________________________________________________________________________________ +; +; SEEK TO A TRACK ON GIVEN UNIT +; A: TRACK # +;________________________________________________________________________________________________________________________________ +; +SETTRACK: + LD A,(FTRACK) ; GET CURRENT HEAD TRACK + LD C,A + LD A,(PTRACK) ; GET TRACK + OR A ; SET FLAGS + JP Z,RECAL ; IF 0 PERFORM RECAL INSTEAD OF SEEK + CP C ; + JP Z,WAINT ; ALREADY THERE, ABORT + LD (FTRACK),A ; STORE TRACK + LD A,#0x0F ; SEEK COMMAND + CALL PFDATA ; PUSH COMMAND + LD A,(UNIT) ; SAY WHICH UNIT + CALL PFDATA ; SEND THAT + LD A,(PTRACK) ; TO WHAT TRACK + CALL PFDATA ; SEND THAT TOO + JP WAINT ; WAIT FOR INTERRUPT SAYING DONE +RECAL: + LD A,#0 ; + LD (FTRACK),A ; STORE TRACK + LD A,#7 ; RECAL TO TRACK 0 + CALL PFDATA ; SEND IT + LD A,(UNIT) ; WHICH UNIT + CALL PFDATA ; SEND THAT TOO + ; +WAINT: + ; + CALL DELAYHSEC ; DELAY TO LET HEADS SETTLE BEFORE READ + ; + ; WAIT HERE FOR INTERRPT SAYING DONE + ; LOOP TIL INTERRUPT + CALL CHECKINT ; CHECK INTERRUPT STATUS + ; + RET + +;__CYCLEFLOPPY__________________________________________________________________________________________________________________________ +; +; SEEK TO TRACK 0, THEN BACK TO THE SELECTED TRACK +; THIS CAN BE USED ON AN ERROR CONDITION TO VERIFY THAT HEAD IS ON SELECTED TRACK +; +;________________________________________________________________________________________________________________________________ +; +CYCLEFLOPPY: + PUSH AF ; STORE AF + PUSH HL ; STORE HL + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + CALL CHECKINT ; CHECK INTERRUPT STATUS, MAKE SURE IT IS CLEAR + LD HL,#FLATCH_STORE ; POINT TO FLATCH + RES 1,(HL) ; SET MOTOR ON + CALL OUTFLATCH ; OUTPUT TO CONTROLLER + NOP ; + NOP ; + CALL RECAL ; + CALL DELAYHSEC ; + CALL DELAYHSEC ; + CALL DELAYHSEC ; + CALL DELAYHSEC ; + CALL RECAL ; + CALL DELAYHSEC ; + CALL DELAYHSEC ; + CALL DELAYHSEC ; + CALL DELAYHSEC ; + CALL SETTRACK ; + CALL DELAYHSEC ; + CALL DELAYHSEC ; + CALL DELAYHSEC ; + CALL DELAYHSEC ; + POP HL ; + POP AF ; RESTORE AF + RET + +;__PFDATAS__________________________________________________________________________________________________________________________ +; +; WRITE A COMMAND OR PARAMETER SEQUENCE +; +; TRANSFERS ARE SYNCHONIZED BYT MSR D7 AND D6 +; RQM DIO +; 0 0 BUSY +; 1 0 WRITE TO DATA REGISTER PERMITTED +; 1 1 BYTE FOR READ BY HOST PENDING +; 0 1 BUSY +; +;________________________________________________________________________________________________________________________________ +; +PFDATAS: + PUSH AF ; STORE AF +PFDS1: + IN A,(FMSR) ; READING OR WRITING IS KEYS TO D7 RQM + AND #0x80 ; MASK OFF RQM BIT + JP Z,PFDS1 ; WAIT FOR RQM TO BE TRUE + IN A,(FMSR) ; READ STATUS + AND #0x40 ; WAITING FOR INPUT? + CALL NZ,ERRORT ; NO, SIGNAL ERROR + POP AF ; RESTORE AF + OUT (FDATA),A ; OUTPUT A TO CONTROLLER + RET + +;__PFDATA__________________________________________________________________________________________________________________________ +; +; WRITE A COMMAND OR PARAMETER SEQUENCE +; +; TRANSFERS ARE SYNCHONIZED BYT MSR D7 AND D6 +; RQM DIO +; 0 0 BUSY +; 1 0 WRITE TO DATA REGISTER PERMITTED +; 1 1 BYTE FOR READ BY HOST PENDING +; 0 1 BUSY +; +;________________________________________________________________________________________________________________________________ +; +PFDATA: + PUSH AF ; STORE AF +PFD1: + IN A,(FMSR) ; READING OR WRITING IS KEYS TO D7 RQM + AND #0x80 ; MASK OFF RQM BIT + JP Z,PFD1 ; WAIT FOR RQM TO BE TRUE + IN A,(FMSR) ; READ STATUS + AND #0x40 ; WAITING FOR INPUT? + CALL NZ,ERRORT ; NO, SIGNAL ERROR + POP AF ; RESTORE AF + OUT (FDATA),A ; OUTPUT A TO CONTROLLER + JP DELAY24 ; DELAY 24US + + + +;__DELAY24__________________________________________________________________________________________________________________________ +; +; DELAY 24US +;________________________________________________________________________________________________________________________________ +; +DELAY24: + ; JP= 10T + PUSH IX ; 15T + POP IX ; 14T + PUSH IX ; 15T + POP IX ; 14T +DELAY12: + PUSH IX ; 15T + POP IX ; 14T + RET ; 10T + + +;__CHECKINT__________________________________________________________________________________________________________________________ +; +; CHECK FOR ACTIVE FDC INTERRUPTS BEFORE GIVING I8272 COMMANDS +; POLL RQM FOR WHEN NOT BUSY AND THEN SEND FDC +; SENSE INTERRUPT COMMAND IF IT RETURNS WITH NON ZERO +; ERROR CODE, PASS BACK TO CALLING ROUTINE FOR HANDLING +;________________________________________________________________________________________________________________________________ +; +CHECKINT: + IN A,(FMSR) ; READING OR WRITING IS KEYS TO D7 RQM + AND #0x80 ; MASK OFF RQM BIT + JP Z,CHECKINT ; WAIT FOR RQM TO BE TRUE WAIT UNTIL DONE + IN A,(FMSR) ; READ STATUS + AND #0x40 ; WAITING FOR INPUT? + JP NZ,CHECKINTDONE ; NO, SIGNAL ERROR + CALL SENDINT ; SENSE INTERRUPT COMMAND +CHECKINTDONE: + RET ; + + +;__DELAYHSEC__________________________________________________________________________________________________________________________ +; +; DELAY FOR 1/2 SECOND +;________________________________________________________________________________________________________________________________ +; +DELAYHSEC: + LD HL,#0 ; 65536 +DELDM: + NOP ; (4 T) + NOP ; (4 T) + NOP ; (4 T) + NOP ; (4 T) + DEC L ; (6 T) + JP NZ,DELDM ; (10 T) 24 T 8 MICROSECONDS AT 4 MHZ + DEC H ; (6 T) + JP NZ,DELDM ; (10 T) (8 US * 256) * 256 524288 US 5 SECONDS + RET + +;__ERRORT__________________________________________________________________________________________________________________________ +; +; ERROR HANDLING +;________________________________________________________________________________________________________________________________ +; +ERRORT: + IN A,(FDATA) ; CLEAR THE JUNK OUT OF DATA REGISTER + IN A,(FMSR) ; CHECK WITH RQM + AND #0x80 ; IF STILL NOT READY, READ OUT MORE JUNK + JP Z,ERRORT ; + LD A,#0x0FF ; RETURN ERROR CODE -1 + ; + RET + +;__SENDINT__________________________________________________________________________________________________________________________ +; +; SENSE INTERRUPT COMMAND +;________________________________________________________________________________________________________________________________ +; +SENDINT: + LD A,#8 ; SENSE INTERRUPT COMMAND + CALL PFDATA ; SEND IT + CALL GFDATA ; GET RESULTS + LD (ST0A),A ; STORE THAT + AND #0x0C0 ; MASK OFF INTERRUPT STATUS BITS + CP #0x80 ; CHECK IF INVALID COMMAND + JP Z,ENDSENDINT ; YES, EXIT + CALL GFDATA ; GET ANOTHER (STATUS CODE 1) + LD (ST1A),A ; SAVE THAT + LD A,(ST0A) ; GET FIRST ONE + AND #0x0C0 ; MASK OFF ALL BUT INTERRUPT CODE 00 IS NORMAL +ENDSENDINT: + RET ; ANYTHING ELSE IS AN ERROR + + +;__GFDATA__________________________________________________________________________________________________________________________ +; +; GET DATA FROM FLOPPY CONTROLLER +; +; TRANSFERS ARE SYNCHONIZED BYT MSR D7 AND D6 +; RQM DIO +; 0 0 BUSY +; 1 0 WRITE TO DATA REGISTER PERMITTED +; 1 1 BYTE FOR READ BY HOST PENDING +; 0 1 BUSY +; +;________________________________________________________________________________________________________________________________ +; +GFDATA: + IN A,(FMSR) ; READ STATUS BYTE + AND #0x80 ; MASK OFF RQM + JP Z,GFDATA ; LOOP WHILE BUSY + IN A,(FMSR) ; READ STSTUS BUTE + AND #0x40 ; MASK OFF DIO + CALL Z,ERRORT ; IF WRITE EXPECTED RUN ERRORRT + IN A,(FDATA) ; READ DATA + JP DELAY24 ; DELAY 24US + + + + .IF CONDUSEDSKY +;__IDESEGDISPLAY________________________________________________________________________________________ +; +; DISPLAY CONTENTS OF IDE LOGICAL BLOCK ADDRESS ON DSKY +;____________________________________________________________________________________________________ +IDESEGDISPLAY: + LD A, #0x82 ; + OUT (PIOCONT),A ; + ; + LD A,(IDE_LBA3) ; + AND #0x0F ; + LD (DISPLAYBUF+6),A ; + LD A,(IDE_LBA3) ; + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+7),A ; + ; + LD A,(IDE_LBA2) ; + AND #0x0F ; + LD (DISPLAYBUF+4),A ; + LD A,(IDE_LBA2) ; + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+5),A ; + ; + LD A,(IDE_LBA1) ; + AND #0x0F ; + LD (DISPLAYBUF+2),A ; + LD A,(IDE_LBA1) ; + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+3),A ; + + LD A,(IDE_LBA0) ; + AND #0x0F ; + LD (DISPLAYBUF),A ; + LD A,(IDE_LBA0) ; + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+1),A ; + JP SEGDISPLAY1 ; + +;__ATAPISEGDISPLAY________________________________________________________________________________________ +; +; DISPLAY CONTENTS OF ATAPI LOGICAL BLOCK ADDRESS ON DSKY +;____________________________________________________________________________________________________ +ATAPISEGDISPLAY: + LD A, #0x82 ; + OUT (PIOCONT),A ; + ; + LD A,(LBA_TARGET_HI+1) ; + AND #0x0F ; + LD (DISPLAYBUF+6),A ; + LD A,(LBA_TARGET_HI+1) ; + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+7),A ; + ; + LD A,(LBA_TARGET_HI) ; + AND #0x0F ; + LD (DISPLAYBUF+4),A ; + LD A,(LBA_TARGET_HI) ; + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+5),A ; + ; + LD A,(LBA_TARGET_LO+1) ; + AND #0x0F ; + LD (DISPLAYBUF+2),A ; + LD A,(LBA_TARGET_LO+1) ; + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+3),A ; + ; + LD A,(LBA_TARGET_LO) ; + AND #0x0F ; + LD (DISPLAYBUF),A ; + LD A,(LBA_TARGET_LO) ; + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+1),A ; + JP SEGDISPLAY1 ; + +;__SEGDISPLAY________________________________________________________________________________________ +; +; DISPLAY CONTENTS OF TRACK, SECTOR, ST0, ST1 ON DSKY +; +;____________________________________________________________________________________________________ +SEGDISPLAY: + LD A, #0x82 ; + OUT (PIOCONT),A ; + LD A,(TRACK) ; + AND #0x0F ; + LD (DISPLAYBUF+6),A ; + LD A,(TRACK) ; + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+7),A ; + LD A,(SECTOR) ; + AND #0x0F ; + LD (DISPLAYBUF+4),A ; + LD A,(SECTOR) ; + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+5),A ; + LD A,(ST0) ; + AND #0x0F ; + LD (DISPLAYBUF+2),A ; + LD A,(ST0) ; + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+3),A ; + LD A,(ST1) ; + AND #0x0F ; + LD (DISPLAYBUF),A ; + LD A,(ST1) ; + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+1),A ; +SEGDISPLAY1: ; + LD HL,#DISPLAYBUF ; + LD BC,#7 ; + ADD HL,BC ; + LD B,#8 ; SET DIGIT COUNT + LD A,#0x40 ; SET CONTROL PORT 7218 TO OFF + OUT (PORTC),A ; OUTPUT + CALL DELAY12 ; WAIT + LD A,#0x0D0 ; SET CONTROL TO 1111 (DATA COMING, HEX DECODE, DECODE, NORMAL) + OUT (PORTA),A ; OUTPUT TO PORT + LD A,#0x80 ; STROBE WRITE PULSE WITH CONTROL=1 + OUT (PORTC),A ; OUTPUT TO PORT + CALL DELAY12 ; WAIT + LD A,#0x40 ; SET CONTROL PORT 7218 TO OFF + OUT (PORTC),A ; OUTPUT + CALL DELAY12 ; WAIT +SEGDISPLAY_LP: + LD A,(HL) ; GET DISPLAY DIGIT + OUT (PORTA),A ; OUT TO PORTA + LD A,#0 ; SET WRITE STROBE + OUT (PORTC),A ; OUT TO PORTC + CALL DELAY12 ; DELAY + LD A,#0x40 ; SET CONTROL PORT OFF + OUT (PORTC),A ; OUT TO PORTC + CALL DELAY12 ; WAIT + DEC HL ; INC POINTER + DJNZ SEGDISPLAY_LP ; LOOP FOR NEXT DIGIT + RET + +DISPLAYBUF: .DB 01,02,03,04,05,06,07,08 + .ENDIF + .DB 00,00,00,00,00,00,00,00 + .DB 00,00,00,00,00,00,00,00 + .DB 00,00,00,00,00,00,00,00 + .DB 00,00,00,00,00,00,00,00 + + + +FLOPPYSTACK: .DB 00 +PARKSTACK: .DB 00,00,00,00 + +READ_DISK_PACKET: + .DB 0x0A8,00,00,00,00,01,00,00,00,01,00,00 +WRITE_DISK_PACKET: + .DB 0x2A,00,00,00,00,0x11,00,00,01,00,00,00 +ATAPI_REQUEST_SENSE: + .DB 3,00,00,00,0x11,00,00,00,00,00,00,00 + +; ******* TEXT STRINGS ******* + +TXT_RO_ERROR: + .DB CR,LF + .ascii "ERROR: WRITE TO READ ONLY DISK" + .DB END + + +TXT_STARTUP_MSG: + + .IF CONDSHORTMSG + .DB CR,LF + .ascii "CP/M-80 2.2C (JC0705-1) for " + .ascii "N8VEM - W/" + .IF CONDUSEVDU + .ascii "VDU " + .ENDIF + .IF CONDUSEDSKY + .ascii "DSKY " + .ENDIF + .IF CONDIDESOFT + .ascii "IDE " + .ENDIF + .IF CONDUSEATAPI + .ascii "ATAPI " + .ENDIF + .IF CONDUSEFLOPPY + .ascii "FLOPPY " + .IF COND144FLOPPY + .ascii "1.44M " + .ENDIF + .ENDIF + .DB CR,LF + .DB END + .ELSE + .ascii "CP/M V2.2C" + .DB END + .ENDIF + +; +; THE REMAINDER OF THE CBIOS IS RESERVED UNINITIALIZED +; DATA AREA, AND DOES NOT NEED TO BE A PART OF THE +; SYSTEM MEMORY IMAGE (THE SPACE MUST BE AVAILABLE, +; HOWEVER, BETWEEN "BEGDAT" AND "ENDDAT") +; + +; +; DISK COMMAND BLOCK +; +CMD: .DB 0 ; COMMAND READ OR WRITE, +UNIT: .DB 0 ; PHYSICAL DRIVE 0->3 +HEAD: .DB 0 ; HEAD SEL 0 OR 1 +DENS: .DB 2 ; DENSITY +EOTSEC: .DB 09 ; LAST SECTOR OF TRACK +GAP: .DB 0x1B ; VALUE FOR IRG +;SECSIZ: .DB 0x80 ; HOW MANY BYTES TO TRANSFER/4 +FSECSIZ: .dw 0x0200 ; actual sector size in bytes +DTL: .DB 0x0FF ; SIZE OF SECTOR +SRTHUT: .DB 0x7F ; STEP RATE AND HEAD UNLOAD TIME +HLT: .DB 5 ; HEAD LOAD TIME +MIN: .DB MINI ; LATCH BIT PATTERN FOR FDC9229 MINITRUE +PRE: .DB PRECOMP ; LATCH BIT PATTERN FOR FDC9229 PRECOMP125NS +; +; FLOPPY STATUS RESULT STORAGE +; +ST0: .DB 0 ; STORE STATUS 0 +ST1: .DB 0 ; ST1 +ST2: .DB 0 ; ST2 +SCYL: .DB 0 ; TRACK +SHEAD: .DB 0 ; HEAD 0 OR 1 +SREC: .DB 0 ; SECTOR +SNBIT: .DB 0 ; DENSITY +ST0A: .DB 0 ; STORE STATUS 0 +ST1A: .DB 0 ; ST1 +RETRY: .DB 0 ; RETRIES +RETRY1: .DB 0 ; RETRIES + +FLATCH_STORE: .DB 00 ; + +TRACK: .DW 0 ; TWO BYTES FOR TRACK # (LOGICAL) +PTRACK: .DW 0 ; TWO BYTES FOR TRACK # (PHYSICAL) +FTRACK: .DW 0 ; TWO BYTES FOR TRACK # (HEAD LOCATION) + +PAGER: .DB 1 ; COPY OF PAGER BYTE +DB_PAGER: .DB 0x0FF ; COPY OF PAGER BYTE (DEBUG) +SECTOR: .DW 0 ; TWO BYTES FOR SECTOR # (LOGICAL) +PSECTOR: .DW 0 ; TWO BYTES FOR SECTOR # (PHYSICAL) +SECST: .DW 0 ; SECTOR IN ROM/RAM START ADDRESS +DMAAD: .DW 0 ; DIRECT MEMORY ADDRESS +DISKNO: .DB 0 ; DISK NUMBER 0-15 +LBA_TARGET_LO: .DW 0 ; IDE HD PARTITION TARGET SECTOR (LOW 16 BITS) +LBA_TARGET_HI: .DW 0 ; IDE HD PARTITION TARGET SECTOR (HI 16 BITS, 12 USED) +IDEDEVICE: .DB 0 ; ATAPI DEVICE SELECTION FLAG + +IDE_LBA0: .DB 0 ; SET LBA 0:7 +IDE_LBA1: .DB 0 ; SET LBA 8:15 +IDE_LBA2: .DB 0 ; SET LBA 16:23 +IDE_LBA3: .DB 0 ; LOWEST 4 BITS USED ONLY TO ENABLE LBA MODE +SECTOR_INDEX: .DB 1 ; WHERE 128 BYTE CP/M SECTOR IS IN 512 BYTE IDE HD SECTOR +; +; SCRATCH RAM AREA FOR BDOS USE +BEGDAT: +; = $ ; BEGINNING OF DATA AREA +DIRBF: .DS 128 ; SCRATCH DIRECTORY AREA +ALL00: .DS 65 ; ALLOCATION VECTOR 0 (DSM/8 = 1 BIT PER BLOCK) 44 +ALL01: .DS 33 ; ALLOCATION VECTOR 1 (225/8) +ALL02: .DS 256 ; ALLOCATION VECTOR 2 (511/8) +ALL03: .DS 256 ; ALLOCATION VECTOR 3 (511/8) +ALL04: .DS 65 ; ALLOCATION VECTOR 4 (497/8) +ALL05: .DS 65 ; ALLOCATION VECTOR 4 (495/8) +ALL06: .DS 65 ; ALLOCATION VECTOR 4 (495/8) +ALL07: .DS 135 ; ALLOCATION VECTOR 7 (495/8) +CHK00: .DS 5 ; 720K MEDIA +CHK01: .DS 0 ; NOT USED FOR FIXED MEDIA +CHK02: .DS 0 ; NOT USED FOR FIXED MEDIA +CHK03: .DS 128 ; 8M MEDIA +CHK04: .DS 0 ; NOT USED FOR FIXED MEDIA +CHK05: .DS 0 ; NOT USED FOR FIXED MEDIA +CHK06: .DS 0 ; NOT USED FOR FIXED MEDIA +CHK07: .DS 15 ; 1.44M MEDIA +; +CUDISK: .DS 1 ; CURRENT PHYSICAL DISK ID IN BUFFER +CUSECTOR: .DW 1 ; CURRENT PHYSICAL DISK SECTOR IN BUFFER +CUTRACK: .DW 2 ; CURRENT PHYSICAL DISK TRACK IN BUFFER +SECTOR_BUFFER: .DS 520 ; STORAGE FOR 512 BYTE IDE HD SECTOR +ENDDAT: +; .EQU $ ; END OF DATA AREA +DSTEMP: +DATSIZ = DSTEMP - BEGDAT ; SIZE OF DATA AREA + + +;dwg; .ORG 0FDFFH +LASTBYTE: .DB 0 + +; .END + + + + + +_cbios_end:: + .area _CODE + .area _CABS diff --git a/doug/src/cbios.sym b/doug/src/cbios.sym new file mode 100755 index 00000000..dd03f558 --- /dev/null +++ b/doug/src/cbios.sym @@ -0,0 +1,137 @@ + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 1. +cbios.s derived from cbios.asm +Symbol Table + + .__.ABS.= 0000 G | 6 AL0_0 00AC R | 6 AL0_1 00BB R + 6 AL0_2 00CA R | 6 AL0_3 00D9 R | 6 AL0_4 00E8 R + 6 AL0_5 00F7 R | 6 AL0_6 0106 R | 6 AL0_7 0115 R + 6 AL1_0 00AD R | 6 AL1_1 00BC R | 6 AL1_2 00CB R + 6 AL1_3 00DA R | 6 AL1_4 00E9 R | 6 AL1_5 00F8 R + 6 AL1_6 0107 R | 6 AL1_7 0116 R | 6 ALL00 0B9D R + 6 ALL01 0BDE R | 6 ALL02 0BFF R | 6 ALL03 0CFF R + 6 ALL04 0DFF R | 6 ALL05 0E40 R | 6 ALL06 0E81 R + 6 ALL07 0EC2 R | 6 ATAPI_DE 06D7 R | 6 ATAPI_DL 05D4 R + 6 ATAPI_RE 0728 R | 6 ATAPI_RE 0718 R | 6 ATAPI_RE 06DF R + 6 ATAPI_RE 0A80 R | 6 ATAPI_SE 077D R | 6 ATAPI_SE 07AA R + 6 ATAPI_SO 069F R | 6 ATAPI_TO 05E3 R | 6 ATAPI_WA 05CF R + 6 ATAPI_WB 05D2 R | 6 ATAPI_WR 0767 R | 6 ATAPI_WR 073C R + BDOS = D806 | 6 BEGDAT 0B1D R | BIAS = 9C00 + BIOS = E600 | 6 BLKSEC 02C0 R | 6 BLM_0 00A6 R + 6 BLM_1 00B5 R | 6 BLM_2 00C4 R | 6 BLM_3 00D3 R + 6 BLM_4 00E2 R | 6 BLM_5 00F1 R | 6 BLM_6 0100 R + 6 BLM_7 010F R | 6 BOOT 011B R | 6 BSH_0 00A5 R + 6 BSH_1 00B4 R | 6 BSH_2 00C3 R | 6 BSH_3 00D2 R + 6 BSH_4 00E1 R | 6 BSH_5 00F0 R | 6 BSH_6 00FF R + 6 BSH_7 010E R | CCP = D000 | CCPSIZ_C= 0800 + CDISK = 0004 | CHARIN = 011B | 6 CHECKINT 09E4 R + 6 CHECKINT 09F5 R | 6 CHK00 0F49 R | 6 CHK01 0F4E R + 6 CHK02 0F4E R | 6 CHK03 0F4E R | 6 CHK04 0FCE R + 6 CHK05 0FCE R | 6 CHK06 0FCE R | 6 CHK07 0FCE R + 6 CKS_0 00AE R | 6 CKS_1 00BD R | 6 CKS_2 00CC R + 6 CKS_3 00DB R | 6 CKS_4 00EA R | 6 CKS_5 00F9 R + 6 CKS_6 0108 R | 6 CKS_7 0117 R | 6 CMD 0AE9 R + COND144F= 0001 | CONDABON= 0001 | CONDIDES= 0001 + CONDSHOR= 0001 | CONDSUPE= 0001 | CONDUSEA= 0000 + CONDUSED= 0000 | CONDUSEF= 0001 | CONDUSEV= 0000 + 6 CONIN 01A6 R | 6 CONOUT 01B1 R | 6 CONST 019C R + 6 CONVERT_ 0516 R | 6 COPY_CPM 0510 R | CR = 000D + 6 CUDISK 0FDD R | 6 CUSECTOR 0FDE R | 6 CUTRACK 0FE0 R + 6 CYCLEFLO 0961 R | DATSIZ = 06CD | 6 DB_PAGER 0B09 R + 6 DEBSEC 02A8 R | 6 DELAY12 09DF R | 6 DELAY24 09D7 R + 6 DELAYHSE 09F6 R | 6 DELDM 09F9 R | 6 DENS 0AEC R + 6 DIRBF 0B1D R | 6 DISKNO 0B12 R | 6 DMAAD 0B10 R + 6 DOSO4 08A4 R | 6 DPBASE 0033 R | 6 DPBLK0 00A3 R + 6 DPBLK1 00B2 R | 6 DPBLK2 00C1 R | 6 DPBLK3 00D0 R + 6 DPBLK4 00DF R | 6 DPBLK5 00EE R | 6 DPBLK6 00FD R + 6 DPBLK7 010C R | 6 DRM_0 00AA R | 6 DRM_1 00B9 R + 6 DRM_2 00C8 R | 6 DRM_3 00D7 R | 6 DRM_4 00E6 R + 6 DRM_5 00F5 R | 6 DRM_6 0104 R | 6 DRM_7 0113 R + 6 DSKEXIT 0875 R | 6 DSKOP 082E R | 6 DSKOPEND 0903 R + 6 DSM_0 00A8 R | 6 DSM_1 00B7 R | 6 DSM_2 00C6 R + 6 DSM_3 00D5 R | 6 DSM_4 00E4 R | 6 DSM_5 00F3 R + 6 DSM_6 0102 R | 6 DSM_7 0111 R | 6 DSTEMP 11EA R + 6 DTL 0AF1 R | END = 00FF | 6 ENDDAT 11EA R + 6 ENDSENDI 0A2F R | 6 EOTSEC 0AED R | 6 ERRORT 0A06 R + 6 EXM_0 00A7 R | 6 EXM_1 00B6 R | 6 EXM_2 00C5 R + 6 EXM_3 00D4 R | 6 EXM_4 00E3 R | 6 EXM_5 00F2 R + 6 EXM_6 0101 R | 6 EXM_7 0110 R | FALSE = 0000 + FDATA = 0037 | 6 FDC_RW_P 08F9 R | 6 FDC_RW_P 08FE R + FDDENSIT= 0040 | FDMA = 003C | FDREADY = 0080 + FLATCH = 003A | 6 FLATCH_S 0B01 R | 6 FLOPPYRE 081E R + 6 FLOPPYST 0A63 R | 6 FLOPPYWR 0826 R | FMSR = 0036 + 6 FSECSIZ 0AEF R | 6 FTRACK 0B06 R | 6 GAP 0AEE R + GET_KEY = 039C | 6 GFDATA 0A30 R | 6 GOCPM 0167 R + 6 HEAD 0AEB R | 6 HLT 0AF3 R | 6 HOME 01DA R + IDEADDR = 002F | 6 IDEBUFRD 0642 R | 6 IDEBUFWT 0656 R + IDECTRL = 002E | IDECYLHI= 0025 | IDECYLLO= 0024 + 6 IDEDEVIC 0B17 R | IDEERR = 0021 | IDEHEAD = 0026 + IDEHI = 0028 | IDELO = 0020 | IDESECTC= 0022 + IDESECTN= 0023 | IDESTTS = 0027 | 6 IDE_BLP 0627 R + 6 IDE_DLP 05F8 R | 6 IDE_ERR 0620 R | 6 IDE_LBA0 0B18 R + 6 IDE_LBA1 0B19 R | 6 IDE_LBA2 0B1A R | 6 IDE_LBA3 0B1B R + 6 IDE_READ 063C R | 6 IDE_READ 056A R | 6 IDE_READ 058B R + 6 IDE_SETU 0666 R | 6 IDE_SOFT 05C3 R | 6 IDE_SREX 057B R + 6 IDE_TEST 060F R | 6 IDE_TO 060D R | 6 IDE_TO2 063A R + 6 IDE_WAIT 0622 R | 6 IDE_WAIT 05F3 R | 6 IDE_WAIT 05E5 R + 6 IDE_WAIT 05EC R | 6 IDE_WBSY 05F6 R | 6 IDE_WDRQ 0625 R + 6 IDE_WRIT 0650 R | 6 IDE_WRIT 059F R | INT_LOC = 0038 + 6 INT_RD 091E R | 6 INT_WR 0921 R | IOBYTE = 0003 + 6 IRTEMP 0921 R | 6 ISCUR 02DC R | IS_KBHIT= 0395 + 6 IS_READ 08B6 R | 6 IWTEMP 0924 R | 6 LASTBYTE 11EA R + 6 LBA_TARG 0B15 R | 6 LBA_TARG 0B13 R | LF = 000A + 6 LIST 01BC R | 6 LISTST 01BE R | L_INT_RD= 0003 + L_INT_WR= 0003 | 6 MIN 0AF4 R | MINI = 0004 + MOTOR = 0000 | MOVSIZ_C= 2BFF | MPCL_RAM= 0078 + MPCL_ROM= 007C | MSIZE = 003B | 6 NOT_READ 01A5 R + 6 OFF_0 00B0 R | 6 OFF_1 00BF R | 6 OFF_2 00CE R + 6 OFF_3 00DD R | 6 OFF_4 00EC R | 6 OFF_5 00FB R + 6 OFF_6 010A R | 6 OFF_7 0119 R | 6 OUTFLATC 0818 R + 6 PAGER 0B08 R | 6 PAGERB 04D9 R | 6 PARKSTAC 0A64 R + 6 PFD1 09C3 R | 6 PFDATA 09C2 R | 6 PFDATAS 09AF R + 6 PFDS1 09B0 R | PIOCONT = 0063 | PORTA = 0060 + PORTB = 0061 | PORTC = 0062 | 6 PRE 0AF5 R + PRECOMP = 0020 | 6 PRTMSG 04BC R | 6 PRTMSG1 04CA R + PR_OUTCH= 0CD6 | 6 PSECTOR 0B0C R | 6 PTRACK 0B04 R + 6 PUNCH 01C0 R | RAMTARG_= D000 | 6 RDD_POLL 08F9 R + 6 RDONLY 03F4 R | 6 READ 01F2 R | 6 READER 01C2 R + 6 READ_ATA 039D R | 6 READ_ATA 03C5 R | 6 READ_ATA 03A2 R + 6 READ_DIS 0A68 R | 6 READ_EEP 0214 R | 6 READ_FLP 02FE R + 6 READ_FLP 0315 R | 6 READ_FLP 031A R | 6 READ_FLP 0365 R + 6 READ_FLP 032F R | 6 READ_HDP 03D6 R | 6 READ_IDE 0378 R + 6 READ_IDE 0396 R | 6 READ_RAM 025A R | 6 RECAL 094A R + 6 REQUEST_ 06B8 R | 6 REQUEST_ 06C4 R | RESETL = 0002 + 6 RESULT 0880 R | 6 RETRY 0AFF R | 6 RETRY1 0B00 R + 6 ROMD 04F3 R | ROMSTART= 0A00 | 6 RPAGE 0504 R + 6 RRA16 0561 R | 6 RS3 0885 R | 6 RSTEXIT 0898 R + 6 SCYL 0AF9 R | 6 SECPAGE 04CB R | 6 SECST 0B0E R + 6 SECTOR 0B0A R | 6 SECTOR_B 0FE2 R | 6 SECTOR_I 0B1C R + 6 SECTRN 01E9 R | 6 SELDSK 01C4 R | 6 SENDINT 0A12 R + 6 SETDMA 01EC R | 6 SETSEC 01E3 R | 6 SETTRACK 0924 R + 6 SETTRK 01DD R | 6 SETUPDRI 07BF R | 6 SHEAD 0AFA R + 6 SNBIT 0AFC R | 6 SPT_0 00A3 R | 6 SPT_1 00B2 R + 6 SPT_2 00C1 R | 6 SPT_3 00D0 R | 6 SPT_4 00DF R + 6 SPT_5 00EE R | 6 SPT_6 00FD R | 6 SPT_7 010C R + 6 SREC 0AFB R | 6 SRTHUT 0AF2 R | 6 ST0 0AF6 R + 6 ST0A 0AFD R | 6 ST1 0AF7 R | 6 ST1A 0AFE R + 6 ST2 0AF8 R | TERMCN = 0001 | 6 TRACK 0B02 R + 6 TRFLSEC 0282 R | TRUE = 0001 | 6 TXT_RO_E 0A8C R + 6 TXT_STAR 0AAD R | UART = 0068 | 6 UNIT 0AEA R + VDU_INIT= 0100 | 6 WAINT 095A R | 6 WBOOT 0146 R + 6 WBOOTE 0003 R | 6 WRITE 03D7 R | 6 WRITE_AT 048E R + 6 WRITE_AT 04B4 R | 6 WRITE_DI 0A74 R | 6 WRITE_FL 0425 R + 6 WRITE_FL 045E R | 6 WRITE_FL 0444 R | 6 WRITE_HD 04BB R + 6 WRITE_ID 0466 R | 6 WRITE_ID 0487 R | 6 WRITE_RA 03FD R + 6 WRITE_RE 043C R | 6 _cbios 0000 GR | 6 _cbios_e 11EB GR + 6 _cbios_s 0000 GR + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 2. +cbios.s derived from cbios.asm +Area Table + + 0 _CODE size 0 flags 0 + 1 _DATA size 0 flags 0 + 2 _OVERLAY size 0 flags 0 + 3 _HOME size 0 flags 0 + 4 _GSINIT size 0 flags 0 + 5 _GSFINAL size 0 flags 0 + 6 _CBIOS size 11EB flags 0 + 7 _CABS size 0 flags 0 diff --git a/doug/src/cbiosn8.arf b/doug/src/cbiosn8.arf new file mode 100755 index 00000000..a32ae1a9 --- /dev/null +++ b/doug/src/cbiosn8.arf @@ -0,0 +1,6 @@ +-mjx +-i cbioshc.ihx +-k /usr/local/share/sdcc/lib/z80 +-l z80 +cbioshc.rel +-e diff --git a/doug/src/cbiosn8.lst b/doug/src/cbiosn8.lst new file mode 100755 index 00000000..ea08c586 --- /dev/null +++ b/doug/src/cbiosn8.lst @@ -0,0 +1,1718 @@ + 1 ;-------------------------------------------------------- + 2 ; cbioshc.s derived from CPM22-HC.ASM by dwg 5/18-30/2011 + 3 ;-------------------------------------------------------- + 4 .module cbioshc + 5 .optsdcc -mz80 + 6 ;-------------------------------------------------------- + 7 ; Public variables in this module + 8 ;-------------------------------------------------------- + 9 .globl _cbioshc + 10 ;-------------------------------------------------------- + 11 ; special function registers + 12 ;-------------------------------------------------------- + 13 ;-------------------------------------------------------- + 14 ; ram data + 15 ;-------------------------------------------------------- + 16 .area _DATA + 17 ;-------------------------------------------------------- + 18 ; overlayable items in ram + 19 ;-------------------------------------------------------- + 20 .area _OVERLAY + 21 ;-------------------------------------------------------- + 22 ; external initialized ram data + 23 ;-------------------------------------------------------- + 24 ;-------------------------------------------------------- + 25 ; global & static initialisations + 26 ;-------------------------------------------------------- + 27 .area _HOME + 28 .area _GSINIT + 29 .area _GSFINAL + 30 .area _GSINIT + 31 ;-------------------------------------------------------- + 32 ; Home + 33 ;-------------------------------------------------------- + 34 .area _HOME + 35 .area _HOME + 36 ;-------------------------------------------------------- + 37 ; code + 38 ;-------------------------------------------------------- + 39 .area _CBIOS + 0000 40 _cbioshc_start:: + 0000 41 _cbioshc: + 42 + 43 ;************************************************************** + 44 ;* + 45 ;* C B I O S f o r + 46 ;* + 47 ;* T e s t P r o t o t y p e + 48 ;* + 49 ;* by Andrew Lynch, with input from many sources + 50 ;* Updated 24-Mar-2009 Max Scane - changed seldsk: to not save bogus drive value + 51 ;* changed a: to be ram drive, B: to be rom disk + 52 ;* Updated 1-Jun-2010 Max Scane - Changed DPBs to be more sane + 53 ;* Updated 1-Jul-2010 Max Scane - Added PPIDE driver and conditionals + 54 ;* Updated April 2011 Max Scane - Adapted for the N8VEM Home Computer + 55 ;************************************************************** + 56 ; + 57 ; SKELETAL CBIOS FOR FIRST LEVEL OF CP/M 2.0 ALTERATION + 58 ; WITH MODS FOR CP/M ROMDISK AND RAMDISK. + 59 ; + 60 ; ENTIRELY IN 8080 MNEUMONICS (SO ASM CAN BE USED) + 61 ; BUT ASSUMES A Z80! (remove) + 62 ; + 63 + 003C 64 MEM = 60 ; DOUGTEMP DOUGTEMP + 65 + 66 + 67 ;MSIZE .EQU 20 ;CP/M VERSION MEMORY SIZE IN KILOBYTES + 68 ;MSIZE .EQU 62 ;CP/M VERSION MEMORY SIZE IN KILOBYTES + 69 ; MEM defined in CPM22 above, line 0015 + 70 + 003C 71 MSIZE = MEM ;CP/M VERSION MEMORY SIZE IN KILOBYTES + 72 + 73 ; + 74 ; "BIAS" IS ADDRESS OFFSET FROM 3400H FOR MEMORY SYSTEMS + 75 ; THAN 16K (REFERRED TO AS "B" THROUGHOUT THE TEXT). + 76 ; + 77 + A000 78 BIAS = (MSIZE-20)*1024 + 79 + D400 80 CCP = 0x3400+BIAS ; base of ccp + 81 + DC06 82 BDOS = CCP+0x0806 ; base of BDOS + 83 + EA00 84 BIOS = CCP+0x1600 ; base of BIOS + 85 + 0004 86 CDISK = 0x0004 ; current disk number 0=a,...,15=p + 87 + 88 ; IOBYTE already defined in CPM22 above, line 0017 + 89 ;IOBYTE .EQU 0003H ;INTEL I/O BYTE + 90 + 91 ; since the assembly has been broken into pieces, + 92 ; this symbols wasn't previously encountered. + 93 ; It could be exported from other module, but why? + 0003 94 IOBYTE = 0x0003 + 95 + 96 ; + 97 ; CONSTANTS + 98 + 99 + 00FF 100 END = 0x0FF + 101 + 102 + 000D 103 CR = 0x0d + 000A 104 LF = 0x0a + 105 + 0094 106 DEFIOB = 0x94 ; default IOBYTE (TTY,RDR,PUN,LPT) + 107 + 108 ; + 109 + 0100 110 ROMSTART_MON = 0x0100 ; where the monitor is stored in ROM + 111 + F800 112 RAMTARG_MON = 0x0f800 ; where the monitor starts in RAM + 113 + 0800 114 MOVSIZ_MON = 0x0800 ; monitor is 2K in length + 115 + 0900 116 ROMSTART_CPM = 0x0900 ; where ccp+bdos+bios is stored in ROM + 117 + D400 118 RAMTARG_CPM = 0x0D400 ; where ccp+bdos+bios starts in RAM + 119 + 120 ;dwg; INTERESTING - 0x15FF is 4K+1K+512-1, not 5KB + 121 ;dwg;MOVSIZ_CPM: .EQU $15FF ; CCP, BDOS IS 5KB IN LENGTH + 15FF 122 MOVSIZ_CPM = 0x15FF ; ccp+bdos is 5KB in length + 123 + 0080 124 HC_REG_BASE = 0x80 ; N8 I/I Regs $80-9F + 125 + 0080 126 PPI1 = HC_REG_BASE+0x00 + 127 + 0094 128 ACR = HC_REG_BASE+0x14 + 129 + 0096 130 RMAP = ACR+2 + 131 + 0040 132 IO_REG_BASE = 0x40 ; IO reg base offset for Z1x80 + 133 + 0040 134 CNTLA0 = IO_REG_BASE+0x00 + 135 + 0042 136 CNTLB0 = IO_REG_BASE+0x02 + 137 + 0044 138 STAT0 = IO_REG_BASE+0x04 + 139 + 0046 140 TDR0 = IO_REG_BASE+0x06 + 141 + 0048 142 RDR0 = IO_REG_BASE+0x08 + 143 + 0052 144 ASEXT0 = IO_REG_BASE+0x12 + 145 + 0078 146 CBR = IO_REG_BASE+0x38 + 147 + 0079 148 BBR = IO_REG_BASE+0x39 + 149 + 007A 150 CBAR = IO_REG_BASE+0x3A + 151 + 152 ; + 153 ; + 154 ; PIO 82C55 I/O IS ATTACHED TO THE FIRST IO BASE ADDRESS + 155 + 0080 156 IDELSB = PPI1+0 ; LSB + 157 + 0081 158 IDEMSB = PPI1+1 ; MSB + 159 + 0082 160 IDECTL = PPI1+2 ; Control Signals + 161 + 0083 162 PIO1CONT = PPI1+3 ; Control Byte PIO 82C55 + 163 + 164 ; PPI control bytes for read and write to IDE drive + 165 + 0092 166 rd_ide_8255 = 0b10010010 ; ide_8255_ctl out ide_8255_lsb/msb input + 167 + 0080 168 wr_ide_8255 = 0b10000000 ; all three ports output + 169 + 170 ;ide control lines for use with ide_8255_ctl. Change these 8 + 171 ;constants to reflect where each signal of the 8255 each of the + 172 ;ide control signals is connected. All the control signals must + 173 ;be on the same port, but these 8 lines let you connect them to + 174 ;whichever pins on that port. + 175 + 0001 176 ide_a0_line = 0x01 ; direct from 8255 to ide interface + 177 + 0002 178 ide_a1_line = 0x02 ; direct from 8255 to ide intereface + 179 + 0004 180 ide_a2_line = 0x04 ; direct from 8255 to ide interface + 181 + 0008 182 ide_cs0_line = 0x08 ; inverter between 8255 and ide interface + 183 + 0010 184 ide_cs1_line = 0x10 ; inverter between 8255 and ide interface + 185 + 0020 186 ide_wr_line = 0x20 ; inverter between 8255 and ide interface + 187 + 0040 188 ide_rd_line = 0x40 ; inverter between 8255 and ide interface + 189 + 0080 190 ide_rst_line = 0x80 ; inverter between 8255 and ide interface + 191 + 192 ;------------------------------------------------------------------ + 193 ; More symbolic constants... these should not be changed, unless of + 194 ; course the IDE drive interface changes, perhaps when drives get + 195 ; to 128G and the PC industry will do yet another kludge. + 196 + 197 ;some symbolic constants for the ide registers, which makes the + 198 ;code more readable than always specifying the address pins + 199 + 0008 200 ide_data = ide_cs0_line + 0009 201 ide_err = ide_cs0_line + ide_a0_line + 000A 202 ide_sec_cnt = ide_cs0_line + ide_a1_line + 000B 203 ide_sector = ide_cs0_line + ide_a1_line + ide_a0_line + 000C 204 ide_cyl_lsb = ide_cs0_line + ide_a2_line + 000D 205 ide_cyl_msb = ide_cs0_line + ide_a2_line + ide_a0_line + 000E 206 ide_head = ide_cs0_line + ide_a2_line + ide_a1_line + 000F 207 ide_command = ide_cs0_line + ide_a2_line + ide_a1_line + ide_a0_line + 000F 208 ide_status = ide_cs0_line + ide_a2_line + ide_a1_line + ide_a0_line + 0016 209 ide_control = ide_cs1_line + ide_a2_line + ide_a1_line + 0017 210 ide_astatus = ide_cs1_line + ide_a2_line + ide_a1_line + ide_a0_line + 211 + 212 ;IDE Command Constants. These should never change. + 213 + 0010 214 ide_cmd_recal = 0x10 + 0020 215 ide_cmd_read = 0x20 + 0030 216 ide_cmd_write = 0x30 + 0091 217 ide_cmd_init = 0x91 + 00EC 218 ide_cmd_id = 0x0ec + 00E0 219 ide_cmd_spindown = 0xe0 + 00E1 220 ide_cmd_spinup = 0xe1 + 221 + 222 + 223 ; .ORG BIOS ;ORIGIN OF THIS PROGRAM + 224 + 225 + 226 ;dwg;NSECTS .EQU ($-CCP)/128 ;WARM START SECTOR COUNT + 227 + 228 ; + 229 ; JUMP VECTOR FOR INDIVIDUAL SUBROUTINES + 230 + 0000 C3rDDs00 231 JP BOOT ;COLD START + 0003 C3rF5s00 232 WBOOTE: JP WBOOT ;WARM START + 0006 C3r2Fs01 233 JP CONST ;CONSOLE STATUS + 0009 C3r41s01 234 JP CONIN ;CONSOLE CHARACTER IN + 000C C3r53s01 235 JP CONOUT ;CONSOLE CHARACTER OUT + 000F C3r65s01 236 JP LIST ;LIST CHARACTER OUT (NULL ROUTINE) + 0012 C3r6Bs01 237 JP PUNCH ;PUNCH CHARACTER OUT (NULL ROUTINE) + 0015 C3r6Es01 238 JP READER ;READER CHARACTER OUT (NULL ROUTINE) + 0018 C3rC6s01 239 JP HOME ;MOVE HEAD TO HOME POSITION + 001B C3rAFs01 240 JP SELDSK ;SELECT DISK + 001E C3rC9s01 241 JP SETTRK ;SET TRACK NUMBER + 0021 C3rCFs01 242 JP SETSEC ;SET SECTOR NUMBER + 0024 C3rD8s01 243 JP SETDMA ;SET DMA ADDRESS + 0027 C3rDEs01 244 JP READ ;READ DISK + 002A C3r02s02 245 JP WRITE ;WRITE DISK + 002D C3r68s01 246 JP LISTST ;RETURN LIST STATUS (NULL ROUTINE) + 0030 C3rD5s01 247 JP SECTRN ;SECTOR TRANSLATE + 248 + 249 ; + 250 ; FIXED DATA TABLES FOR ALL DRIVES + 251 ; 0= RAMDISK, 1=ROMDISK, 2=HDPART1, 3=HDPART2 + 252 ; DISK PARAMETER HEADER FOR DISK 00 (RAM Disk) + 0033 253 DPBASE: + 0033 00 00 00 00 254 .DW 0x0000,0x0000 + 0037 00 00 00 00 255 .DW 0x0000,0x0000 + 003Br7Cs07r83s00 256 .DW DIRBF,DPBLK0 + 003Fr9Es0ArFCs07 257 .DW CHK00,ALL00 + 258 + 259 ; DISK PARAMETER HEADER FOR DISK 05 (Large ROM Disk) + 0043 00 00 00 00 260 .DW 0x0000,0x0000 + 0047 00 00 00 00 261 .DW 0x0000,0x0000 + 004Br7Cs07rCEs00 262 .DW DIRBF,DPBLK5 + 004Fr9Es0Ar5Es0A 263 .DW CHK05,ALL05 + 264 + 265 + 266 ; DISK PARAMETER HEADER FOR DISK 02 (8MB disk Partition) + 0053 00 00 00 00 267 .DW 0x0000,0x0000 + 0057 00 00 00 00 268 .DW 0x0000,0x0000 + 005Br7Cs07rA1s00 269 .DW DIRBF,DPBLK2 + 005Fr9Es0Ar20s08 270 .DW CHK02,ALL02 + 271 + 272 ; DISK PARAMETER HEADER FOR DISK 03 (8MB disk Partition) + 0063 00 00 00 00 273 .DW 0x0000,0x0000 + 0067 00 00 00 00 274 .DW 0x0000,0x0000 + 006Br7Cs07rB0s00 275 .DW DIRBF,DPBLK3 + 006Fr9Es0Ar1Fs09 276 .DW CHK03,ALL03 + 277 + 278 ; DISK PARAMETER HEADER FOR DISK 04 (??? third disk partition ???) + 0073 00 00 00 00 279 .DW 0x0000,0x0000 + 0077 00 00 00 00 280 .DW 0x0000,0x0000 + 007Br7Cs07rBFs00 281 .DW DIRBF,DPBLK4 + 007Fr9Es0Ar1Es0A 282 .DW CHK04,ALL04 + 283 + 0083 284 DPBLK0: ;DISK PARAMETER BLOCK (RAMDISK 512K, 448K usable) + 0083 00 01 285 SPT_1: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK + 0085 04 286 BSH_1: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 0086 0F 287 BLM_1: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 0087 01 288 EXM_1: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 0088 DF 00 289 DSM_1: .DW 223 ; BLOCKSIZE [2048] * NUMBER OF BLOCKS + 1 = DRIVE SIZE + 008A FF 00 290 DRM_1: .DW 255 ; NUMBER OF DIRECTORY ENTRIES + 008C F0 291 AL0_1: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 008D 00 292 AL1_1: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 008E 00 00 293 CKS_1: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 0090 02 00 294 OFF_1: .DW 2 ; 2 TRACK RESERVED [FIRST 64K OF RAM] + 295 ; Note: changed to 2 tracks to skip over the 1st 64KB or RAM. + 296 + 0092 297 DPBLK1: ;DISK PARAMETER BLOCK (ROMDISK 32KB WITH 16 2K TRACKS, 22K usable) + 0092 10 00 298 SPT_0: .DW 16 ; 16 SECTORS OF 128 BYTES PER 2K TRACK + 0094 03 299 BSH_0: .DB 3 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 0095 07 300 BLM_0: .DB 7 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 0096 00 301 EXM_0: .DB 0 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 0097 1F 00 302 DSM_0: .DW 31 ; BLOCKSIZE [1024] * NUMBER OF BLOCKS + 1 = DRIVE SIZE + 0099 1F 00 303 DRM_0: .DW 31 ; NUMBER OF DIRECTORY ENTRIES + 009B 80 304 AL0_0: .DB 0b10000000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 009C 00 305 AL1_0: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 009D 00 00 306 CKS_0: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 009F 05 00 307 OFF_0: .DW 5 ; FIRST 5 TRACKS TRACKS RESERVED (10K FOR SYSTEM) + 308 ; SYSTEM IS ROM LOADER, CCP, BDOS, CBIOS, AND MONITOR + 309 ; + 310 ; IMPORTANT NOTE: TRACKS $00 - $04 OF 2K BYTES + 311 ; EACH ARE MARKED WITH THE OFF_0 SET TO 5 AS + 312 ; SYSTEM TRACKS. USABLE ROM DRIVE SPACE + 313 ; STARTING AFTER THE FIFTH TRACK (IE, TRACK $05) + 314 ; MOST LIKELY FIX TO THIS IS PLACING A DUMMY + 315 ; FIRST 10K ROM CONTAINS THE ROM LOADER, MONITOR, + 316 ; CCP, BDOS, BIOS, ETC (5 TRACKS * 2K EACH) + 317 + 318 + 00A1 319 DPBLK2: ;DISK PARAMETER BLOCK (IDE HARD DISK 8MB) + 00A1 00 01 320 SPT_2: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK + 00A3 05 321 BSH_2: .DB 5 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 00A4 1F 322 BLM_2: .DB 31 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 00A5 01 323 EXM_2: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 00A6 F7 07 324 DSM_2: .DW 2039 ; BLOCKSIZE [4096] * NUMBER OF BLOCKS + 1 = DRIVE SIZE + 325 ; HD PARTITION 2 IS 16128 SECTORS LONG + 326 ; AT 512 BYTES EACH WHICH IS + 327 ; 2016 BLOCKS AT 4096 BYTES A PIECE. + 00A8 FF 01 328 DRM_2: .DW 511 ; NUMBER OF DIRECTORY ENTRIES + 00AA F0 329 AL0_2: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 00AB 00 330 AL1_2: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 00AC 00 00 331 CKS_2: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 00AE 01 00 332 OFF_2: .DW 1 ; 1 TRACK (32K) RESERVED FOR SYSTEM + 333 + 00B0 334 DPBLK3: ;DISK PARAMETER BLOCK (IDE HARD DISK 8MB) + 00B0 00 01 335 SPT_3: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK + 00B2 05 336 BSH_3: .DB 5 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 00B3 1F 337 BLM_3: .DB 31 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 00B4 01 338 EXM_3: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 00B5 F7 07 339 DSM_3: .DW 2039 ; BLOCKSIZE [4096] * NUMBER OF BLKS + 1 = DRIVE SIZE + 340 ; HD PARTITION 3 IS 16128 SECTORS LONG + 341 ; AT 512 BYTES EACH WHICH IS + 342 ; 2016 BLOCKS AT 4096 BYTES A PIECE. + 00B7 FF 01 343 DRM_3: .DW 511 ; NUMBER OF DIRECTORY ENTRIES + 00B9 F0 344 AL0_3: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 00BA 00 345 AL1_3: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 00BB 00 00 346 CKS_3: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 00BD 01 00 347 OFF_3: .DW 1 ; 1 TRACK (32K) RESERVED FOR SYSTEM + 348 + 00BF 349 DPBLK4: ;DISK PARAMETER BLOCK (IDE HARD DISK 1024K) + 00BF 00 01 350 SPT_4: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK + 00C1 04 351 BSH_4: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 00C2 0F 352 BLM_4: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 00C3 00 353 EXM_4: .DB 0 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 00C4 F1 01 354 DSM_4: .DW 497 ; BLKSIZE [2048] * NUMBER OF BLKS + 1 = DRIVE SIZE + 355 ; HD PARTITION 4 IS 4032 SECTORS LONG + 356 ; AT 512 BYTES EACH WHICH IS + 357 ; 1008 BLOCKS AT 2048 BYTES A PIECE. + 358 ; NOT USING ALL OF THE AVAILABLE SECTORS SINCE THIS + 359 ; DRIVE IS INTENDED TO EMULATE A ROM DRIVE AND COPIED + 360 ; INTO A ROM IN THE FUTURE. + 00C6 FF 00 361 DRM_4: .DW 255 ; NUMBER OF DIRECTORY ENTRIES + 00C8 F0 362 AL0_4: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 00C9 00 363 AL1_4: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED + 00CA 00 00 364 CKS_4: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] + 00CC 01 00 365 OFF_4: .DW 1 ; 1 TRACK RESERVED [FIRST 32K OF PARTITION] + 366 + 367 ; + 00CE 368 DPBLK5: ;DISK PARAMETER BLOCK (ROMDISK 1MB) + 00CE 00 01 369 SPT_5: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK + 00D0 04 370 BSH_5: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) + 00D1 0F 371 BLM_5: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH + 00D2 00 372 EXM_5: .DB 0 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) + 00D3 EF 01 373 DSM_5: .DW 495 ; BLKSIZE [2048] * NUMBER OF BLKS +1 =DRIVE SIZE + 374 ;DSM_5: .DW 511 ; BLKSIZE [2048] * NUMBER OF BLKS +1 =DRIVE SIZE + 00D5 FF 00 375 DRM_5: .DW 255 ; NUMBER OF DIRECTORY ENTRIES + 00D7 F0 376 AL0_5: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY + 00D8 00 377 AL1_5: .DB 0b00000000 ; DIR CAN HAVE UP TO 16 BLOCKS ALLOCATED + 00D9 00 00 378 CKS_5: .DW 0 ; SIZE OF DIR CHECK [0 IF NON REMOVEABLE] + 00DB 01 00 379 OFF_5: .DW 1 ; 1 TRACK RESERVED [FIRST 32K OF ROM] + 380 + 381 ; + 382 ; END OF FIXED TABLES + 383 ; + 384 ; INDIVIDUAL SUBROUTINES TO PERFORM EACH FUNCTION + 385 + 00DD 386 BOOT: ;SIMPLEST CASE IS TO JUST PERFORM PARAMETER INITIALIZATION + 00DD F3 387 di ; disable interrupts + 388 ; IM 1 ; SET INTERRUPT MODE 1 + 389 ; .DB $ED,$56 ; Z80 "IM 1" INSTRUCTION + 390 + 00DE 3E 80 391 ld a,#0x80 + 392 + 393 ; out0 ACR + 394 ; .BYTE $ED,$39,ACR ; ensure that the ROM is switched out + 395 + 00E0 D3 94 396 out (ACR),a + 397 + 00E2 3E 01 398 ld a,#1 + 00E4 32 04 00 399 ld (CDISK),a ; select disk 0 + 400 + 00E7 3E 94 401 ld a,#DEFIOB + 00E9 32 03 00 402 ld (IOBYTE),a + 403 + 404 ; ei ; enable interrupts + 405 + 00EC 21r30s05 406 ld hl,#TXT_STARTUP_MSG + 00EF CDr89s03 407 CALL PRTMSG + 408 + 00F2 C3r0Es01 409 JP GOCPM ;INITIALIZE AND GO TO CP/M + 410 + 411 ; + 00F5 412 WBOOT: ;SIMPLEST CASE IS TO READ THE DISK UNTIL ALL SECTORS LOADED + 413 ; WITH A ROMDISK WE SELECT THE ROM AND THE CORRECT PAGE [0] + 414 ; THEN COPY THE CP/M IMAGE (CCP, BDOS, BIOS, MONITOR) TO HIGH RAM + 415 ; LOAD ADDRESS. + 416 + 00F5 F3 417 DI ; DISABLE INTERRUPT + 418 + 00F6 31 80 00 419 ld SP,#0x0080 ; use space below buffer for stack + 420 + 421 ; IM 1 ; SET INTERRUPT MODE 1 + 422 ; .DB $ED,$56 ; Z80 "IM 1" INSTRUCTION + 423 + 00F9 AF 424 xor a,a + 425 + 426 ; CHEAP ZERO IN ACC + 427 ; mvi a,00h ; switch in the ROM + 428 ; out0 ACR + 429 ; .BYTE $ED,$39,ACR + 430 + 00FA D3 94 431 out (ACR),a + 432 + 00FC AF 433 xor a,a + 434 + 435 ; out0 RMAP + 436 ; .BYTE $ED,$39,$F6 + 437 + 00FD D3 96 438 out (RMAP),a ; set the rom map + 439 + 440 ; Just reload CCP and BDOS + 441 + 00FF 21 00 09 442 ld hl,#ROMSTART_CPM ; where in rom cp/m is stored (1st byte) + 0102 11 00 D4 443 ld de,#RAMTARG_CPM ; where in ram to move ccp+BDOS to + 0105 01 FF 15 444 ld bc,#MOVSIZ_CPM + 0108 ED B0 445 ldir + 446 + 010A 3E 80 447 ld a,#0x80 + 010C D3 94 448 out (ACR),a + 449 + 450 ; EI ; ENABLE INTERRUPTS + 451 + 452 ; + 453 ; END OF LOAD OPERATION, SET PARAMETERS AND GO TO CP/M + 010E 454 GOCPM: + 455 ;CPU RESET HANDLER + 010E 3E C3 456 ld a,#0xC3 ; C32 is a jump opcode + 0110 32 00 00 457 ld (0x0000),a + 0113 21r03s00 458 ld hl,#WBOOTE ; address of warm boot + 0116 22 01 00 459 ld (0x0001),hl ; set addr field for jmp at 0 + 460 + 0119 32 05 00 461 ld (0x0005),a ; for jump to bdos + 011C 21 06 DC 462 ld hl,#BDOS + 011F 22 06 00 463 ld (0x0006),hl + 464 + 0122 01 80 00 465 ld bc,#0x0080 ; default DMA address + 0125 CDrD8s01 466 CALL SETDMA + 467 + 0128 3A 04 00 468 ld a,(CDISK) ; get current disk number + 012B 4F 469 ld c,a ; send to the ccp + 012C C3 00 D4 470 JP CCP ;GO TO CP/M FOR FURTHER PROCESSING + 471 + 472 + 473 ; + 474 ;---------------------------------------------------------------------------------------------------------------------- + 475 ; N8VEM Home computer I/O handlers + 476 ; + 477 ; This implementation uses IOBYTE and allocates devices as follows: + 478 ; + 479 ; TTY - Driver for the Z180 ASCI port 0 + 480 ; CRT - Driver for the + 481 ; UC1 - Driver for the + 482 ; xxx - Driver for the + 483 ; + 484 ; Logical device drivers - these pass control to the physical + 485 ; device drivers depending on the value of the IOBYTE + 486 ; + 487 + 012F 488 CONST: ;CONSOLE STATUS, RETURN 0FFH IF CHARACTER READY, 00H IF NOT + 489 + 012F 3A 03 00 490 ld a,(IOBYTE) + 0132 E6 03 491 and a,#3 + 0134 FE 00 492 cp #0 + 0136 CAr91s01 493 jp z,TTYISTS + 494 + 0139 FE 01 495 cp #1 + 013B CArA9s01 496 jp z,CRTISTS + 497 + 013E C3r76s01 498 jp NULLSTS + 499 + 500 + 501 + 502 + 0141 503 CONIN: ;CONSOLE CHARACTER INTO REGISTER A + 0141 3A 03 00 504 ld a,(IOBYTE) + 0144 E6 03 505 and a,#3 + 0146 FE 00 506 cp #0 + 0148 CAr79s01 507 jp z,TTYIN + 014B FE 01 508 cp #1 + 014D CArA3s01 509 jp z,CRTIN + 0150 C3r71s01 510 jp NULLIN + 511 + 512 + 0153 513 CONOUT: ;CONSOLE CHARACTER OUTPUT FROM REGISTER C + 0153 3A 03 00 514 ld a,(IOBYTE) + 0156 E6 03 515 and a,#3 ; isolate console bits + 0158 FE 00 516 cp #0 + 015A CAr85s01 517 jp z,TTYOUT + 015D FE 01 518 cp #1 + 015F CArA6s01 519 jp z,CRTOUT + 0162 C3r74s01 520 jp NULLOUT + 521 + 0165 522 LIST: ;LIST CHARACTER FROM REGISTER C + 0165 C3r74s01 523 jp NULLOUT + 524 + 525 + 526 + 0168 527 LISTST: ;RETURN LIST STATUS (0 IF NOT READY, 1 IF READY) + 0168 C3r76s01 528 jp NULLSTS + 529 + 530 ; + 016B 531 PUNCH: ;PUNCH CHARACTER FROM REGISTER C + 016B C3r74s01 532 jp NULLOUT + 533 + 534 ; + 016E 535 READER: ;READ CHARACTER INTO REGISTER A FROM READER DEVICE + 536 + 016E C3r71s01 537 jp NULLIN ; currently not used + 538 + 539 + 540 + 541 ;---------------------------------------------------------------------------------------------------------------------------------------- + 542 ; + 543 ; Here are the physical io device drivers + 544 ; + 545 ; Null driver - this is a dummy driver for the NULL device + 546 + 0171 547 NULLIN: + 0171 3E 1A 548 ld a,#0x1a + 0173 C9 549 ret + 550 + 0174 551 NULLOUT: + 0174 79 552 ld a,c + 0175 C9 553 ret + 554 + 0176 555 NULLSTS: + 0176 3E 01 556 ld a,#1 + 0178 C9 557 ret + 558 + 559 ; + 560 ;--------------------------------------------------------------------------------------------------------------------------------------------- + 561 ; + 562 ; TTY Driver (programmed i/o) this is the driver for the Home Computer console port + 563 ; + 0179 564 TTYIN: + 0179 CDr91s01 565 CALL TTYISTS; IS A CHAR READY TO BE READ FROM UART? + 017C FE 00 566 cp #0 + 017E CAr79s01 567 jp z,TTYIN + 568 + 569 ; IN0 A,(RDR0) + 570 + 571 ;dwg; .BYTE $ED,$38,RDR0 + 0181 ED 38 48 572 .byte 0xED,0x38,RDR0 + 573 + 0184 C9 574 ret + 575 + 0185 576 TTYOUT: + 0185 CDr9As01 577 call TTYOSTS + 0188 A7 578 and a,a + 0189 CAr85s01 579 jp z,TTYOUT ; if not repeat + 580 + 018C 79 581 ld a,c ; get to accum + 582 + 583 ; OUT0 (TDR0),A + 018D ED 39 46 584 .byte 0xed,0x39,TDR0 + 585 + 0190 C9 586 ret + 587 + 0191 588 TTYISTS: + 589 ; IN0 A,(STAT0) + 590 ;dwg; .BYTE $ED,$38,STAT0 + 591 ;;dwg;; in0 a,(STAT0) + 0191 ED 38 44 592 .byte 0xed,0x38,STAT0 + 593 + 0194 E6 80 594 and a,#0x80 + 0196 C8 595 ret z ; is there a char ready? 0=no 1=yes + 0197 3E FF 596 ld a,#0xff + 0199 C9 597 ret ; NO, LEAVE $00 IN A AND RETURN + 598 + 019A 599 TTYOSTS: + 600 ; IN0 A,(STAT0) + 601 ;dwg; .BYTE $ED,$38,STAT0 + 602 ;;dwg;; in0 a,(STAT0) + 019A ED 38 44 603 .byte 0xed,0x38,STAT0 + 604 + 019D E6 02 605 and a,#2 + 019F C8 606 ret z + 01A0 3E FF 607 ld a,#0xff + 608 + 01A2 C9 609 ret ; NO, LEAVE $00 IN A AND RETURN + 610 ;--------------------------------------------------------------------------------------------------------------------------------------------- + 611 ; CRT Driver - This is the driver for the Prop VDU + 612 ; + 613 + 01A3 614 CRTIN: + 01A3 C3r71s01 615 jp NULLIN + 616 + 01A6 617 CRTOUT: + 01A6 C3r74s01 618 jp NULLOUT + 619 + 01A9 620 CRTISTS: + 01A9 C3r76s01 621 jp NULLSTS + 622 + 01AC 623 CRTOSTS: + 01AC C3r76s01 624 jp NULLSTS + 625 + 626 + 627 ;--------------------------------------------------------------------------------------------------------------------------------------------- + 628 ;; + 629 ; I/O DRIVERS FOR THE DISK FOLLOW + 630 ; FOR NOW, WE WILL SIMPLY STORE THE PARAMETERS AWAY FOR USE + 631 ; IN THE READ AND WRITE SUBROUTINES + 632 ; + 633 + 634 ; + 635 ; SELECT DISK GIVEN BY REGISTER C + 636 ; + 01AF 637 SELDSK: + 638 + 01AF 21 00 00 639 ld hl,#0 ; error return code + 640 + 01B2 79 641 ld a,c + 642 + 01B3 FE 04 643 cp a,#4 ; must be between 0 and 4 + 01B5 D0 644 ret nc ; no carry if 4,5,6,7 + 01B6 79 645 ld a,c + 01B7 32r68s05 646 ld (DISKNO),a ; save valid disk number + 647 + 648 ; + 649 ; DISK NUMBER IS IN THE PROPER RANGE + 650 ; COMPUTE PROPER DISK PARAMETER HEADER ADDRESS + 651 + 01BA 6F 652 ld l,a ; l = disk num 0,1,2,3,4 + 01BB 26 00 653 ld h,#0 ; high order + 01BD 29 654 add hl,hl ; * 2 + 01BE 29 655 add hl,hl ; * 4 + 01BF 29 656 add hl,hl ; * 8 + 01C0 29 657 add hl,hl ; * 16 (size of each header) + 01C1 11r33s00 658 ld de,#DPBASE + 01C4 19 659 add hl,de ; hl = .DPBASE(DISKNO*16) + 01C5 C9 660 RET + 661 ; + 01C6 662 HOME: ;MOVE TO THE TRACK 00 POSITION OF CURRENT DRIVE + 663 ; TRANSLATE THIS CALL INTO A SETTRK CALL WITH PARAMETER 00 + 664 + 01C6 01 00 00 665 ld bc,#0 ; select track zero + 666 + 667 ; CALL SETTRK + 668 ; RET ;WE WILL MOVE TO 00 ON FIRST READ/WRITE + 669 ; FALL THROUGH TO SETTRK TO STORE VALUE + 670 + 01C9 671 SETTRK: ;SET TRACK GIVEN BY REGISTER BC + 01C9 60 672 ld h,b + 01CA 69 673 ld l,c + 01CB 22r62s05 674 ld (TRACK),hl + 01CE C9 675 RET + 676 ; + 01CF 677 SETSEC: ;SET SECTOR GIVEN BY REGISTER BC + 01CF 60 678 ld h,b + 01D0 69 679 ld l,c + 01D1 22r64s05 680 ld (SECTOR),hl + 01D4 C9 681 RET + 682 ; + 683 ; TRANSLATE THE SECTOR GIVEN BY BC USING THE + 684 ; TRANSLATE TABLE GIVEN BY DE + 685 ; ONLY USED FOR FLOPPIES! FOR ROMDISK/RAMDISK IT'S 1:1 + 686 ; DO THE NEXT ROUTINE IS A NULL (RETURNS THE SAME) + 01D5 687 SECTRN: + 01D5 60 688 ld h,b + 01D6 69 689 ld l,c + 01D7 C9 690 RET + 691 ; + 692 + 01D8 693 SETDMA: ;SET DMA ADDRESS GIVEN BY REGISTERS B AND C + 01D8 69 694 ld l,c + 01D9 60 695 ld h,b + 01DA 22r66s05 696 ld (DMAAD),hl + 01DD C9 697 RET + 698 + 699 ; READ DISK + 700 ; USES DE,DL, BC, ACC FLAGS + 701 ; Z80 COULD USE BLOCK MOVE [LDIR] BUT WRITTEN IN 8080 + 01DE 702 READ: + 703 ; DI ; DISABLE INTERRUPTS + 704 + 01DE 3Ar68s05 705 ld a,(DISKNO) + 706 ; FIND OUT WHICH DRIVE IS BEING REQUESTED + 707 ; ARE WE READING RAM OR ROM? + 01E1 FE 00 708 cp #0 + 01E3 CAr2Fs02 709 jp z,READ_RAM_DISK + 710 + 01E6 FE 01 711 cp #1 + 01E8 CAr5Fs02 712 jp z,READ_ROM_DISK + 713 + 01EB FE 02 714 cp #2 + 01ED CArB6s02 715 jp z,READ_HDPART1 + 716 + 01F0 FE 03 717 cp #3 + 01F2 CArC5s02 718 jp z,READ_HDPART2 ; READ FROM 8 MB IDE HD, PARTITION 2 + 719 + 01F5 FE 04 720 cp #4 + 01F7 CArD4s02 721 jp z,READ_HDPART3 ; READ FROM 1 MB IDE HD, PARTITION 4 + 722 + 01FA FE 05 723 cp #5 + 01FC CArD4s02 724 jp z,READ_HDPART4 ; READ FROM 1 MB IDE HD, PARTITION 5 + 725 + 01FF 3E 01 726 ld a,#1 ; BDOS WILL ALSO PRINT ITS OWN ERROR MESSAGE + 0201 C9 727 ret + 728 + 729 + 730 ; + 731 ; WRITE DISK + 732 ; + 0202 733 WRITE: + 734 ; DI ; DISABLE INTERRUPTS + 735 + 0202 3Ar68s05 736 ld a,(DISKNO) ; get drive + 737 + 738 ; ORA A ; SET FLAGS + 739 + 0205 FE 00 740 cp #0 ; find out which drive is being requested + 741 + 0207 CAr86s02 742 jp z,WRITE_RAM_DISK ; write to 448K ram disk + 743 + 020A FE 01 744 cp #1 + 020C CAr26s02 745 jp z,RDONLY ; jump to read only routine + 746 + 747 ; READ ONLY, FROM 22K EEPROM DISK, ERROR ON WRITE + 020F FE 02 748 cp #2 + 0211 CAr1Cs03 749 jp z,WRITE_HDPART1 ; write to 8MB IDE HD, Part 2 + 750 + 0214 FE 03 751 cp #3 + 0216 CAr2Bs03 752 jp z,WRITE_HDPART2 ; write to 8MB IDE HD, Part 3 + 753 + 0219 FE 04 754 cp #4 + 021B CAr3As03 755 jp z,WRITE_HDPART3 ; write to 1MB IDE HD, Part 4 + 756 + 021E FE 05 757 cp #5 + 0220 CAr3As03 758 jp z,WRITE_HDPART4 ; write to 1MB IDE HD Part 5 + 759 + 760 + 761 ; IF NONE OF THE OTHER DISKS, IT MUST BE + 762 ; THE RAM DISK, SO FALL THROUGH + 763 + 0223 3E 01 764 ld a,#1 ; send bad sector error back + 765 ; BDOS WILL ALSO PRINT ITS OWN ERROR MESSAGE + 0225 C9 766 ret + 767 + 768 + 769 + 0226 770 RDONLY: + 771 ; + 772 ; HANDLE WRITE TO READ ONLY + 773 ; + 774 ; SENDS A MESSAGE TO TERMINAL THAT ROM DRIVE IS NOT WRITEABLE + 775 ; DOES A PAUSE THEN RETURNS TO CPM WITH ERROR FLAGGED. THIS IS + 776 ; DONE TO ALLOW A POSSIBLE GRACEFUL EXIT (SOME APPS MAY PUKE). + 777 ; + 778 + 779 ; CODE TBD, PRINT A HEY WRONG DISK AND PAUSE 5 SEC AND + 780 ; CONTINUE. + 781 + 0226 21r0Fs05 782 ld hl,#TXT_RO_ERROR ; set hp --> error msg + 0229 CDr89s03 783 CALL PRTMSG ; PRINT ERROR MESSAGE + 784 + 022C 3E 01 785 ld a,#1 ; send bad sector error back + 786 ; BDOS WILL ALSO PRINT ITS OWN ERROR MESSAGE + 787 ; ADD 5 SECOND PAUSE ROUTINE HERE + 022E C9 788 ret + 789 + 790 ; + 791 ;-------------------------------------------------------------------------------------------------------------- + 792 ; + 793 ; DISK DRIVERS... + 794 ; + 795 ; DRIVER NEED TO DO SEVERAL THINGS FOR ROM AND RAM DISKS. + 796 ; - INTERRUPTS ARE NOT ALLOWED DURING LOW RAM/ROM ACCESS (DISABLE!) + 797 ; -TRANSLATE TRACK AND SECTOR INTO A POINTER TO WHERE THE 128 BYTE + 798 ; SECTOR BEGINS IN THE RAM/ROM + 799 ; -TRANSLATE THE DRIVE INTO A RAM/ROM SELECT, COMBINE WITH TRACK ADDRESS + 800 ; AND SEND TO THE MAP PORT. + 801 ; -COPY 128 BYTE FROM OR TO THE ROM/RAMDISK AND MEM POINTED TO BY DMA + 802 ; ADDRESS PREVIOUSLY STORED. + 803 ; -RESTORE MAP PORT TO PRIOR CONDITION BEFOR READ/WRITE + 804 ; + 805 ; - FIRST TRICK IS THAT WE MADE SECTORS 256 AS 256*128=32768. SO WE COPY + 806 ; THE LOW SECTOR ADDRESS TO THE LOW BYTE OF THE HL REGISTER AND THEN + 807 ; MULTIPLY BY 128. THIS RESULTS IN THE STARTING ADDR IN THE RAM OR ROM + 808 ; (0000 -> 7F80H) 32K PAGE. + 809 ; + 810 ; - TRICK TWO IS THE TRACK ADDRESS EQUALS THE 32K PAGE ADDRESS AND IS A + 811 ; DIRECT SELECT THAT CAN BE COPIED TO THE MAP PORT D0 THROUGH D5. D7 + 812 ; SELECTS THE DRIVE (ROM OR RAM). + 813 ; THAT MEANS THE LOW BYTE OF TRACK CONTAINS THE D0-D5 VALUE AND + 814 ; DISKNO HAS THE DRIVE SELECTED. WE FIRST COPY DISKNO TO ACC + 815 ; AND RIGHTSHIFT IT TO PLACE THAT IN BIT7, WE THEN ADD LOW BYTE OF + 816 ; TRACK TO ACC AND THEN SEND THAT TO THE MAP PORT. + 817 ; + 818 ; NOTE 1: A WRITE TO ROM SHOULD BE FLAGGED AS AN ERROR. + 819 ; NOTE 2: RAM MUST START AS A "FORMATTED DISK" IF BATTERY BACKED UP + 820 ; IT'S A DO ONCE AT COLD COLD START. IF NOT BATTERY BACKED UP + 821 ; IT WILL HAVE TO BE DONE EVERY TIME THE SYSTEM IS POWERED. + 822 ; FORMATTING THE RAM IS SIMPLE AS CLEARING THE DIRECTORY AREA + 823 ; TO A VALUE OF E5H (THE FIRST 8K OF TRACK 1 OR THE RAMDISK). + 824 ; IT COULD BE DONE AS A SIMPLE UTILITY PROGRAM STORED IN ROMDISK + 825 ; OR ANYTIME COLBOOT IS CALLED(LESS DESIREABLE). + 826 ; + 827 ; -WE NOW CAN COPY TO/FROM AS CORRECT FOR THE DEVICE 128 BYTES (SECTOR) + 828 ; TO OR FROM THE DMA ADDRESS. ALMOST! SINCE ROM OR RAM IS BEING PAGED + 829 ; WE HAVE TO COPY ANYTHING DESTINED FOR BELOW 8000H TO TEMP BUFFER + 830 ; THEN HANDLE THE PAGING. + 831 ; + 832 ; + 833 ; - LAST STEP IS TO RESTORE THE MAP PORT TO POINT TO THE RAM (TRACK 0) + 834 ; SO THE CP/M MEMORY MAP IS ALL RAM AGAIN AND NOT POINTING INTO THE + 835 ; DATA AREAS OR THE "DISK". + 836 ; SINCE THE RAM 0TH PAGE IS NOMINALLY THE LOW 32K OF RAM IN THE i + 837 ; SYSTEM WE CAN SEND A SIMPLE MVI A,80H ; OUT MPCL_ROM; MVI A,00H ; + 838 ; OUT MPCL_RAM. + 839 ; + 840 ; - THE READ OR WRITE OPERATION IS DONE. + 841 ; + 842 ; + 843 ; + 844 ; + 845 ; + 846 ; + 847 + 848 ; ACCESS ALGORITHM (ONLY APPLICABLE TO 32K ROM PART!) + 022F 849 READ_RAM_DISK: + 022F F3 850 DI ; IF RAM, PROCEED WITH NORMAL TRACK/SECTOR READ + 0230 CDr98s03 851 CALL SECPAGE ; SETUP FOR READ OF RAM OR ROM DISK + 852 + 0233 2Ar62s05 853 ld hl,(TRACK) ; multiply by 8 (4k segs) + 854 + 855 ;dwg; dad h ; *2 + 0236 29 856 add hl,hl + 857 + 858 ;dwg; dad h ; *4 + 0237 29 859 add hl,hl + 860 + 861 ;dwg; dad h ; *8 + 0238 29 862 add hl,hl + 863 + 864 ;dwg; MOV A,L ; get track in L + 0239 7D 865 ld a,l + 866 + 867 ; out0 BBR ; select RAM bank + 868 + 869 ;dwg; .BYTE $ED,$39,BBR + 870 ;;dwg;; out0 BBR + 023A ED 39 79 871 .byte 0xed,0x39,BBR + 872 + 023D 21r7Cs05 873 ld hl,#TMPBUF ; load hl with temp buf addr + 0240 54 874 ld d,h ; get it into de + 0241 5D 875 ld e,l + 0242 2Ar6Ds05 876 ld hl,(SECST) ; rom/ram addr + 0245 01 80 00 877 ld bc,#128 + 0248 ED B0 878 ldir + 879 + 880 ; + 881 ; NOW WITH THE ROM/RAM DATA IN THE BUFFER WE CAN NOW MOVE IT TO THE + 882 ; DMA ADDRESS (IN RAM) + 883 ; + 884 + 024A 3E 00 885 ld a,#0 ; return to system bank + 886 + 887 ; out0 BBR ; select RAM bank + 888 + 889 ;dwg; .BYTE $ED,$39,BBR + 890 ;;dwg;; out0 BBR + 024C ED 39 79 891 .db 0xed,0x39,BBR + 892 + 893 ; CALL RPAGE ; SET PAGE TO CP/M RAM + 894 + 895 ; EI ; RE-ENABLE INTERRUPTS + 896 + 024F 2Ar66s05 897 ld hl,(DMAAD) ; load hl with dma addr + 0252 5D 898 ld e,l + 0253 54 899 ld d,h ; get it into de + 0254 21r7Cs05 900 ld hl,#TMPBUF ; get rom/ram addr + 0257 01 80 00 901 ld bc,#128 + 025A ED B0 902 ldir + 903 + 025C 3E 00 904 ld a,#0 + 025E C9 905 RET + 906 + 025F 907 READ_ROM_DISK: + 025F F3 908 DI ; IF RAM, PROCEED WITH NORMAL TRACK/SECTOR READ + 0260 CDr98s03 909 CALL SECPAGE ; SETUP FOR READ OF RAM OR ROM DISK + 0263 CDrA6s03 910 CALL PAGERB ; SET PAGER WITH DRIVE AND TRACK + 911 + 0266 21r7Cs05 912 ld hl,#TMPBUF ; load hl with temp buf address + 0269 54 913 ld d,h + 026A 5D 914 ld e,l ; get it into de + 026B 2Ar6Ds05 915 ld hl,(SECST) ; rom/ram address + 026E 01 80 00 916 ld bc,#128 + 0271 ED B0 917 ldir + 918 + 919 ; + 920 ; NOW WITH THE ROM/RAM DATA IN THE BUFFER WE CAN NOW MOVE IT TO THE + 921 ; DMA ADDRESS (IN RAM) + 922 ; + 0273 CDrB9s03 923 CALL RPAGE ; SET PAGE TO CP/M RAM + 924 ; EI ; RE-ENABLE INTERRUPTS + 925 + 0276 2Ar66s05 926 ld hl,(DMAAD) ; load hl with dma address + 0279 5D 927 ld e,l + 027A 54 928 ld d,h + 027B 21r7Cs05 929 ld hl,#TMPBUF ; get rom/ram address + 027E 01 80 00 930 ld bc,#128 + 0281 ED B0 931 ldir + 932 + 0283 3E 00 933 ld a,#0 + 0285 C9 934 ret + 935 + 936 + 0286 937 WRITE_RAM_DISK: + 938 + 0286 21r7Cs05 939 ld hl,#TMPBUF ; load hl with temp buf address + 0289 54 940 ld d,h + 028A 5D 941 ld e,l + 028B 2Ar66s05 942 ld hl,(DMAAD) + 028E 01 80 00 943 ld bc,#128 + 0291 ED B0 944 ldir + 945 + 946 ; + 947 ; NOW THAT DATA IS IN THE TEMP BUF WE SET TO RAM PAGE + 948 ; FOR WRITE. + 949 ; + 0293 F3 950 DI + 0294 CDr98s03 951 CALL SECPAGE ; GET RAM PAGE WRITE ADDRESS + 952 + 0297 2Ar62s05 953 ld hl,(TRACK) + 954 + 029A 29 955 add hl,hl ; *2 multiply by 8 (4k segs) + 029B 29 956 add hl,hl ; *4 + 029C 29 957 add hl,hl ; *8 + 029D 7D 958 ld a,l ; get track in l + 959 + 960 ; out0 BBR ; select RAM bank + 961 ;dwg; .BYTE $ED,$39,BBR + 962 ;;dwg;; out0 BBR + 029E ED 39 79 963 .db 0xed,0x39,BBR + 964 + 02A1 2Ar6Ds05 965 ld hl,(SECST) ; load hl with dma addr (where to write to) + 02A4 54 966 ld d,h ; get it into de + 02A5 5D 967 ld e,l + 02A6 21r7Cs05 968 ld hl,#TMPBUF ; get temp buffer address + 02A9 01 80 00 969 ld bc,#128 + 02AC ED B0 970 ldir + 971 + 02AE 3E 00 972 ld a,#0 ; return to system bank + 973 + 974 ; out0 BBR ; select RAM bank + 975 ;dwg; .BYTE $ED,$39,BBR + 976 ;;dwg;; out0 BBR + 02B0 ED 39 79 977 .db 0xed,0x39,BBR + 978 + 979 ; EI + 980 ; RE-ENABLE INTERRUPTS + 02B3 3E 00 981 ld a,#0 + 02B5 C9 982 ret + 983 + 984 ;------------------------------------------------------------------- + 985 + 986 ; Logical disk drivers + 987 + 02B6 988 READ_HDPART1: + 989 + 02B6 21 01 00 990 ld hl,#1 ; init LBA offset sector lo word + 02B9 22r6Fs05 991 ld (LBA_OFFSET_LO),hl + 02BC 21 00 00 992 ld hl,#0 ; init LBA offset sector hi word + 02BF 22r71s05 993 ld (LBA_OFFSET_HI),hl + 02C2 C3rD5s02 994 JP READ_HDPARTX + 995 + 02C5 996 READ_HDPART2: + 02C5 21 01 40 997 ld hl,#0x4001 ; init LBA offset sector lo word + 02C8 22r6Fs05 998 ld (LBA_OFFSET_LO),hl + 02CB 21 00 00 999 ld hl,#0 ; init LBA offset sector hi word + 02CE 22r71s05 1000 ld (LBA_OFFSET_HI),hl + 02D1 C3rD5s02 1001 JP READ_HDPARTX + 1002 + 02D4 1003 READ_HDPART3: + 02D4 1004 READ_HDPART4: + 02D4 C9 1005 ret + 1006 + 1007 + 02D5 1008 READ_HDPARTX: + 1009 + 1010 ; BDOS TRACK PARAMETER (16 BITS) + 1011 ; BDOS SECTOR PARAMETER (16 BITS) + 1012 + 02D5 2Ar62s05 1013 ld hl,(TRACK) ; load track number (word) + 02D8 45 1014 ld b,l ; save lower 8 bits (tracks 0-255) + 02D9 2Ar64s05 1015 ld hl,(SECTOR) ; load sector number (word) + 02DC 60 1016 ld h,b ; hl is 8 bit track in h, 8 bit sector in l + 02DD CDrC4s03 1017 CALL CONVERT_IDE_SECTOR_CPM ; COMPUTE WHERE CP/M SECTOR IS ON THE + 1018 ; IDE PARTITION + 1019 + 1020 ; MAP COMPUTED IDE HD SECTOR TO LBA REGISTERS + 1021 + 1022 ; LBA REGISTERS STORE 28 BIT VALUE OF IDE HD SECTOR ADDRESS + 1023 + 02E0 3Ar73s05 1024 ld a,(LBA_TARGET_LO) ; load LBA reg 0 with sector addr to read + 02E3 32r77s05 1025 ld (IDE_LBA0),a + 02E6 3Ar74s05 1026 ld a,(LBA_TARGET_LO+1) ; load LBA reg 1 with sector addr t read + 02E9 32r78s05 1027 ld (IDE_LBA1),a + 02EC 3Ar75s05 1028 ld a,(LBA_TARGET_HI) ; load LBA reg 2 with sector addr to read + 02EF 32r79s05 1029 ld (IDE_LBA2),a + 02F2 3Ar76s05 1030 ld a,(LBA_TARGET_HI+1) ; load LBA reg 3 with sector addr to read + 02F5 E6 0F 1031 and a,#0b00001111 ; only lower 4 bits are valid + 02F7 C6 E0 1032 add a,#0b11100000 ; enable LBA bits 5:7=111 in IDE_LBA3 + 02F9 32r7As05 1033 ld (IDE_LBA3),a + 02FC CDrFCs03 1034 CALL IDE_READ_SECTOR ; READ THE IDE HARD DISK SECTOR + 1035 + 1036 ; NEED TO ADD ERROR CHECKING HERE, CARRY FLAG IS SET IF IDE_READ_SECTOR SUCCESSFUL! + 1037 + 1038 ; COMPUTE STARTING ADDRESS OF CP/M SECTOR IN READ IDE HD SECTOR BUFFER + 1039 + 02FF 21r7Cs05 1040 ld hl,#SECTOR_BUFFER ; load hl with sector buffer address + 1041 + 0302 3Ar7Bs05 1042 ld a,(SECTOR_INDEX) ; get the sector index (off in buff) + 1043 + 0305 CB 0F 1044 RRC a ; MOVE BIT 0 TO BIT 7 + 0307 CB 0F 1045 RRC a ; DO AGAIN - IN EFFECT MULTIPLY BY 64 + 1046 + 0309 16 00 1047 ld d,#0 ; put result as 16 value in de, upper byte in d is 0 + 1048 + 030B 5F 1049 ld e,a ; put addr offset in e + 1050 + 030C 19 1051 add hl,de ; multiply by 2, total mult is x 128 + 1052 + 030D 19 1053 add hl,de ; cp/m sect starting addr in IDE HD sector buffer + 1054 + 1055 ; COPY CP/M SECTOR TO BDOS DMA ADDRESS BUFFER + 1056 + 030E 54 1057 ld D,H ; TRANSFER HL REGISTERS TO DE + 030F 5D 1058 ld E,L + 0310 2Ar66s05 1059 ld hl,(DMAAD) ; LOAD HL WITH DMA ADDRESS + 0313 EB 1060 ex de,hl + 0314 01 80 00 1061 ld bc,#128 + 0317 ED B0 1062 ldir + 1063 + 1064 ; EI ; RE-ENABLE INTERRUPTS + 1065 + 0319 3E 00 1066 ld a,#0 ; return err code read successful a=0 + 031B C9 1067 ret + 1068 + 1069 + 1070 + 1071 + 1072 ;------------------------------------------------------------------- + 1073 + 1074 + 031C 1075 WRITE_HDPART1: + 1076 + 1077 ; DI ; DISABLE INTERRUPTS + 1078 + 031C 21 01 00 1079 ld hl,#1 ; init LBA offset sector lo word + 031F 22r6Fs05 1080 ld (LBA_OFFSET_LO),hl + 0322 21 00 00 1081 ld hl,#0 ; init LBA offset sector hi word + 0325 22r71s05 1082 ld (LBA_OFFSET_HI),hl + 0328 C3r3Bs03 1083 JP WRITE_HDPARTX + 1084 + 1085 + 032B 1086 WRITE_HDPART2: + 1087 + 1088 ; DI ; DISABLE INTERRUPTS + 1089 + 032B 21 01 40 1090 ld hl,#0x4001 ; init LBA offset sector lo word + 032E 22r6Fs05 1091 ld (LBA_OFFSET_LO),hl + 0331 21 00 00 1092 ld hl,#0 ; init LBA offset sector hi word + 0334 22r71s05 1093 ld (LBA_OFFSET_HI),hl + 0337 C3r3Bs03 1094 JP WRITE_HDPARTX + 1095 + 1096 ;------------------------------------------------------------------- + 1097 + 033A 1098 WRITE_HDPART3: ; STUB + 033A 1099 WRITE_HDPART4: ; STUB + 033A C9 1100 RET + 1101 + 1102 ;------------------------------------------------------------------- + 1103 + 1104 + 033B 1105 WRITE_HDPARTX: + 1106 + 1107 ; BDOS TRACK PARAMETER (16 BITS) + 1108 ; BDOS SECTOR PARAMETER (16 BITS) + 1109 + 033B 2Ar62s05 1110 ld hl,(TRACK) ; load track # (word) + 033E 45 1111 ld b,l ; save lower 8 bits (tracks 0-255) + 033F 2Ar64s05 1112 ld hl,(SECTOR) ; load sector # (word) + 0342 60 1113 ld h,b ; hl is 8 bit track in h, 8 bit sector in l + 1114 + 0343 CDrC4s03 1115 CALL CONVERT_IDE_SECTOR_CPM ; COMPUTE WHERE THE CP/M SECT IS ON THE + 1116 ; IDE PARTITION + 1117 + 1118 ; MAP COMPUTED IDE HD SECTOR TO LBA REGISTERS + 1119 ; LBA REGISTERS STORE 28 BIT VALUE OF IDE HD SECTOR ADDRESS + 1120 + 0346 3Ar73s05 1121 ld a,(LBA_TARGET_LO) ; load LBA reg 0 with sect addr to read + 0349 32r77s05 1122 ld (IDE_LBA0),a + 034C 3Ar74s05 1123 ld a,(LBA_TARGET_LO+1) ; load LBA reg 1 with sect addr to read + 034F 32r78s05 1124 ld (IDE_LBA1),a + 0352 3Ar75s05 1125 ld a,(LBA_TARGET_HI) ; load LBA reg 2 with sect addr to read + 0355 32r79s05 1126 ld (IDE_LBA2),a + 0358 3Ar76s05 1127 ld a,(LBA_TARGET_HI+1) ; load LBA reg 3 with sect addr to read + 035B E6 0F 1128 and a,#0b00001111 ; only lower four bits are valid + 035D C6 E0 1129 add a,#0b11100000 ; enable LBA bits 5:7=111 in IDE_LBA3 + 035F 32r7As05 1130 ld (IDE_LBA3),a + 0362 CDrFCs03 1131 CALL IDE_READ_SECTOR ; READ THE IDE HARD DISK SECTOR + 1132 + 1133 ; NEED TO ADD ERROR CHECKING HERE, + 1134 ; CARRY FLAG IS SET IF IDE_READ_SECTOR SUCCESSFUL! + 1135 + 1136 ; COMPUTE STARTING ADDRESS OF CP/M SECTOR IN READ IDE HD SECTOR BUFFER + 1137 + 0365 21r7Cs05 1138 ld hl,#SECTOR_BUFFER ; load hl with sector buffer address + 1139 + 0368 3Ar7Bs05 1140 ld a,(SECTOR_INDEX) ; get the sector index (off in buffer) + 1141 + 036B CB 0F 1142 RRC a ; MOVE BIT 0 TO BIT 7 + 036D CB 0F 1143 RRC a ; DO AGAIN - IN EFFECT MULTIPLY BY 64 + 1144 + 036F 16 00 1145 ld d,#0 ; put result as 16 bit value in de + 1146 ; UPPER BYTE IN D IS $00 + 0371 5F 1147 ld e,a ; put address offset in e + 1148 + 0372 19 1149 add hl,de ; cp/m starting addr in buffer + 1150 + 0373 19 1151 add hl,de ; *2, total mult is x128 + 1152 + 1153 ; KEEP CP/M SECTOR ADDRESS FOR LATER USE + 1154 ; COPY CP/M SECTOR FROM BDOS DMA ADDRESS BUFFER + 0374 22r6Ds05 1155 ld (SECST),hl + 1156 + 0377 2Ar6Ds05 1157 ld hl,(SECST) ; setup destination + 037A EB 1158 ex de,hl ; swap for next LHLD + 037B 2Ar66s05 1159 ld hl,(DMAAD) ; setup source + 037E 01 80 00 1160 ld bc,#128 ; byte count + 0381 ED B0 1161 ldir + 1162 + 1163 ; IDE HD SECTOR IS NOW UPDATED + 1164 ; WITH CURRENT CP/M SECTOR DATA SO WRITE TO DISK + 1165 + 0383 CDr15s04 1166 CALL IDE_WRITE_SECTOR ; WRITE THE UPDATED IDE HARD DISK SECTOR + 1167 + 1168 ; NEED TO ADD ERROR CHECKING HERE, + 1169 ; CARRY FLAG IS SET IF IDE_WRITE_SECTOR SUCCESSFUL! + 1170 + 1171 ; EI ; RE-ENABLE INTERRUPTS + 1172 + 0386 3E 00 1173 ld a,#0 ; return error code write successful a=0 + 0388 C9 1174 ret + 1175 + 1176 ;------------------------------------------------------------------- + 1177 + 1178 + 0389 1179 PRTMSG: + 0389 7E 1180 ld a,(hl) ; get char into A + 038A FE FF 1181 cp a,#END ; test for end byte + 038C CAr97s03 1182 jp z,PRTMSG1 ; jump if end byte is found + 038F 4F 1183 ld c,a ; put char to print in C for conout + 0390 CDr53s01 1184 CALL CONOUT ; SEND CHARACTER TO CONSOLE FROM REG C + 0393 23 1185 inc hl ; inc ptr to next char + 0394 C3r89s03 1186 JP PRTMSG ; TRANSMIT LOOP + 0397 1187 PRTMSG1: + 0397 C9 1188 ret + 1189 + 1190 + 1191 ; + 1192 ; UTILITY ROUTINE FOR SECTOR TO PAGE ADDRESS + 1193 ; USES HL AND CARRY + 1194 ; + 0398 1195 SECPAGE: + 0398 2Ar64s05 1196 ld hl,(SECTOR) + 039B 29 1197 add hl,hl ; * 2 + 039C 29 1198 add hl,hl ; * 4 + 039D 29 1199 add hl,hl ; * 8 + 039E 29 1200 add hl,hl ; * 16 + 039F 29 1201 add hl,hl ; * 32 + 03A0 29 1202 add hl,hl ; * 64 + 03A1 29 1203 add hl,hl ; * 128 + 03A2 22r6Ds05 1204 ld (SECST),hl ; save sector starting address + 03A5 C9 1205 ret + 1206 + 1207 ; + 1208 ; PAGER BYTE CREATION + 1209 ; ASSEMBLES DRIVE AND TRACK AND SENDS IT TO PAGER PORT + 1210 ; + 03A6 1211 PAGERB: + 03A6 2Ar62s05 1212 ld hl,(TRACK) + 03A9 7D 1213 ld a,l ; or l with acc to combine track and drive + 1214 ; out0 ACR+2 + 03AA ED 39 96 1215 .db 0xed,0x39,ACR+2 ; rom latch + 03AD 3E 00 1216 ld a,#0 ; switch in the rom + 1217 ; out0 ACR + 03AF ED 39 94 1218 .db 0xed,0x39,ACR + 03B2 32r69s05 1219 ld (PAGER),a ; save copy (just because) + 03B5 32r6As05 1220 ld (DB_PAGER),a ; save another copy for debug + 03B8 C9 1221 RET + 1222 + 1223 ; + 1224 ; RESET PAGER BACK TO RAM. + 1225 ; + 03B9 1226 RPAGE: + 1227 + 03B9 3E 80 1228 ld a,#0x80 ; deselect rom page + 1229 ; out0 ACR + 03BB ED 39 94 1230 .db 0xed,0x39,ACR + 1231 + 03BE 3E 00 1232 ld a,#0 ; set to RAM track 0 + 1233 ;dwg; STA PAGER ; SAVE COPY OF PAGER BYTE + 03C0 32r69s05 1234 ld (PAGER),a + 1235 + 03C3 C9 1236 RET + 1237 + 1238 + 03C4 1239 CONVERT_IDE_SECTOR_CPM: + 1240 + 1241 ; COMPUTES WHERE THE CP/M SECTOR IS IN THE IDE PARTITION + 1242 ; IDE HD SECTORS ARE 512 BYTES EACH, CP/M SECTORS ARE 128 BYTES EACH + 1243 ; MAXIMUM SIZE OF CP/M DISK IS 8 MB = 65536 (16 BITS) X 128 BYTES PER SECTOR + 1244 ; IDE HD PARTITION CAN HAVE AT MOST 16384 IDE SECTORS -> 65536 CP/M SECTORS + 1245 ; EACH IDE HD SECTOR CONTAINS 4 ADJACENT CP/M SECTORS + 1246 ; + 1247 ; + 1248 ; INPUT: + 1249 ; IDE HD PARTITION STARTING SECTOR NUMBER (FROM PARTITION TABLE) + 1250 ; - LOWER 16 BITS STORED IN LBA_OFFSET_LO + 1251 ; - UPPER 16 BITS STORED IN LBA_OFFSET_HI + 1252 ; PARTITION OFFSET IN HL (16 BITS) + 1253 ; - A UNIQUELY COMPUTED FUNCTION BASED ON GEOMETRY OF DISKS NUMBER OF + 1254 ; CP/M TRACKS AND SECTORS SPECIFIED IN DPB + 1255 ; + 1256 ; + 1257 ; OUTPUT: + 1258 ; IDE TARGET SECTOR (SENT TO IDE HD CONTROLLER FOR READ OPERATION) + 1259 ; - LOWER 16 BITS STORED IN LBA_TARGET_LO + 1260 ; - UPPER 16 BITS STORED IN LBA_TARGET_HI + 1261 ; CP/M TO IDE HD SECTOR MAPPING PARAMETER STORED IN SECTOR_INDEX + 1262 ; - 8 BIT VALUE WITH 4 LEGAL STATES (00, 01, 02, 04) WHICH IS + 1263 ; TO BE USED TO COMPUTE STARTING ADDRESS OF 128 BYTE CP/M SECTOR ONCE + 1264 ; 512 BYTE IDE HD SECTOR READ INTO MEMORY BUFFER + 1265 ; + 1266 + 1267 ; ROTATE WITH CARRY 16 BIT TRACK,SECTOR VALUE IN HL TO GET 14 BIT IDE HD + 1268 ; TARGET SECTOR IN PARTITION + 1269 ; KEEP LAST TWO BITS IN B FOR IDE HD SECTOR TO CP/M SECTOR TRANSLATION + 1270 + 1271 ; COMPUTE SECTOR_INDEX + 1272 + 1273 ;;dwg;; What is the point of this? the next inst sets A anyway?? + 03C4 AF 1274 xor a,a ; zero accumulator + 1275 + 03C5 7D 1276 ld a,l ; store the last 2 bits of l in b + 03C6 E6 03 1277 and a,#0b00000011 + 03C8 47 1278 ld b,a + 1279 + 03C9 32r7Bs05 1280 ld (SECTOR_INDEX),a ; locates the 128 cpm sector in buffer + 1281 + 1282 ; COMPUTE WHICH IDE HD SECTOR TO READ TO WITHIN 4 CP/M SECTORS + 1283 ; SHIFTS 16 BIT PARTITION OFFSET TO THE RIGHT 2 BITS AND ADDS RESULT TO + 1284 ; IDE HD PARTITION STARTING SECTOR + 1285 + 1286 ; SHIFT PARTITION OFFSET RIGHT 1 BIT + 1287 + 03CC 37 1288 scf ; set the carry flag, so we can clear it + 03CD 3F 1289 ccf ; Complement Carry Flag + 1290 + 03CE 7C 1291 ld a,h ; 16 bit rotate hl with carry + 03CF 1F 1292 rra + 03D0 67 1293 ld h,a ; rotate HL right 1 bit (divide by 2) + 03D1 7D 1294 ld a,l + 03D2 1F 1295 rra + 03D3 6F 1296 ld l,a + 1297 + 1298 ; SHIFT PARTITION OFFSET RIGHT 1 BIT + 1299 + 03D4 37 1300 scf + 03D5 3F 1301 ccf ; CLEAR CARRY FLAG + 1302 + 03D6 7C 1303 ld a,h ; 16 bit rotate HL with carry + 03D7 1F 1304 rra + 03D8 67 1305 ld H,A ; ROTATE HL RIGHT 1 BIT (DIVIDE BY 2) + 03D9 7D 1306 ld A,L + 03DA 1F 1307 rra + 03DB 6F 1308 ld L,A + 1309 + 1310 ; ADD RESULTING 14 BIT VALUE TO IDE HD PARTITION STARTING SECTOR + 1311 ; STORE RESULT IN IDE HD TARGET SECTOR PARAMETER + 1312 + 03DC 3Ar6Fs05 1313 ld a,(LBA_OFFSET_LO) ; 16 bit add of LBA_OFFSET_LO with hl + 03DF 85 1314 ADD L + 03E0 32r73s05 1315 ld (LBA_TARGET_LO),a + 03E3 3Ar70s05 1316 ld a,(LBA_OFFSET_LO+1) + 03E6 8C 1317 adc a,h + 03E7 32r74s05 1318 ld (LBA_TARGET_LO+1),a ; store overflow bit in carry + 03EA 21 00 00 1319 ld hl,#0 + 03ED 3Ar71s05 1320 ld a,(LBA_OFFSET_HI) ; 16 bit add w/carry of LBA_OFFSET_HI w/ + 03F0 8D 1321 adc a,l + 03F1 32r75s05 1322 ld (LBA_TARGET_HI),a + 03F4 3Ar72s05 1323 ld a,(LBA_OFFSET_HI+1) + 03F7 8C 1324 adc a,h + 03F8 32r76s05 1325 ld (LBA_TARGET_HI+1),a + 03FB C9 1326 RET + 1327 + 1328 + 1329 + 1330 ;------------------------------------------------------------------------------------ + 1331 ; Parallel port IDE driver + 1332 ; + 1333 ; + 1334 ; ----------------------------------------------------------------------------- + 1335 + 1336 ;read a sector, specified by the 4 bytes in "lba", + 1337 ;Return, acc is zero on success, non-zero for an error + 03FC 1338 IDE_READ_SECTOR: + 03FC CDr4Fs04 1339 call ide_wait_not_busy ;make sure drive is ready + 03FF CDr9Fs04 1340 call wr_lba ;tell it which sector we want + 1341 + 0402 3E 0F 1342 ld a,#ide_command ; select IDE reg + 0404 0E 20 1343 ld c,#ide_cmd_read + 0406 CDrEBs04 1344 call ide_write ;ask the drive to read it + 0409 CDr69s04 1345 call ide_wait_drq ;wait until it's got the data + 1346 ; bit 0,a + 1347 ; ani 1 + 1348 ; jnz get_err + 1349 + 040C 21r7Cs05 1350 ld hl,#SECTOR_BUFFER + 040F CDr77s04 1351 call read_data ;grab the data + 0412 3E 00 1352 ld a,#0 ; ? set successful return code ? + 1353 + 0414 C9 1354 ret + 1355 + 1356 + 1357 ;----------------------------------------------------------------------------- + 1358 + 1359 + 1360 ;write a sector, specified by the 4 bytes in "lba", + 1361 ;whatever is in the buffer gets written to the drive! + 1362 ;Return, acc is zero on success, non-zero for an error + 0415 1363 IDE_WRITE_SECTOR: + 0415 CDr4Fs04 1364 call ide_wait_not_busy ;make sure drive is ready + 0418 CDr9Fs04 1365 call wr_lba ;tell it which sector we want + 1366 + 041B 3E 0F 1367 ld a,#ide_command + 041D 0E 30 1368 ld c,#ide_cmd_write + 041F CDrEBs04 1369 call ide_write ;tell drive to write a sector + 0422 CDr69s04 1370 call ide_wait_drq ;wait unit it wants the data + 1371 + 1372 ; bit 0,a ; check for error returned + 1373 ; ani 1 + 1374 ; jnz get_err + 1375 + 0425 21r7Cs05 1376 ld hl,#SECTOR_BUFFER + 0428 CDr8Bs04 1377 call write_data ;give the data to the drive + 042B CDr4Fs04 1378 call ide_wait_not_busy ;wait until the write is complete + 1379 + 1380 ; bit 0,a + 1381 ; ani 1 + 1382 ; jnz get_err + 1383 + 1384 ; ld a,#0 ; SHOULD THIS BE HERE (Doug's idea) + 042E C9 1385 ret + 1386 + 1387 + 1388 ;----------------------------------------------------------------------------- + 1389 + 1390 ;--------ide_hard_reset--------------------------------------------------------------- + 1391 ;do a hard reset on the drive, by pulsing its reset pin. + 1392 ;this should usually be followed with a call to "ide_init". + 1393 ;------------------------------------------------------------------------------------------- + 042F 1394 ide_hard_reset: + 042F CDr05s05 1395 call set_ppi_rd + 0432 3E 80 1396 ld a,#ide_rst_line + 0434 D3 82 1397 out (IDECTL),a ; assert rst line on IDE interface + 0436 01 00 00 1398 ld bc,#0 + 0439 1399 rst_dly: + 0439 05 1400 dec b + 043A C2r39s04 1401 jp nz,rst_dly + 043D 3E 00 1402 ld a,#0 ; this could be XOR A,A (shorter) + 043F D3 82 1403 out (IDECTL),a ; deassert RST line on IDE interface + 0441 C9 1404 ret + 1405 + 1406 ;------------------------------------------------------------------------------ + 1407 ; IDE INTERNAL SUBROUTINES + 1408 ;------------------------------------------------------------------------------ + 1409 + 1410 + 1411 + 1412 ;---------------------------------------------------------------------------- + 1413 ;when an error occurs, we get bit 0 of A set from a call to ide_drq + 1414 ;or ide_wait_not_busy (which read the drive's status register). If + 1415 ;that error bit is set, we should jump here to read the drive's + 1416 ;explaination of the error, to be returned to the user. If for + 1417 ;some reason the error code is zero (shouldn't happen), we'll + 1418 ;return 255, so that the main program can always depend on a + 1419 ;return of zero to indicate success. + 0442 1420 get_err: + 0442 3E 09 1421 ld a,#ide_err + 0444 CDrCFs04 1422 call ide_read + 0447 79 1423 ld a,c + 0448 CAr4Cs04 1424 jp z,gerr2 + 044B C9 1425 ret + 044C 1426 gerr2: + 044C 3E FF 1427 ld a,#255 + 044E C9 1428 ret + 1429 + 1430 ;----------------------------------------------------------------------------- + 1431 + 044F 1432 ide_wait_not_busy: + 044F 3E 0F 1433 ld a,#ide_status ; wait for RDY bit to be set + 0451 CDrCFs04 1434 call ide_read + 0454 79 1435 ld a,c + 0455 E6 80 1436 and a,#0x80 ; isolate busy bit + 0457 C2r4Fs04 1437 jp nz,ide_wait_not_busy + 045A C9 1438 ret + 1439 + 1440 + 045B 1441 ide_wait_ready: + 045B 3E 0F 1442 ld a,#ide_status ; wait for RDY bit to be set + 045D CDrCFs04 1443 call ide_read + 0460 79 1444 ld a,c + 0461 E6 C0 1445 and a,#0b11000000 ; mask off busy and ready bits + 0463 EE 40 1446 xor a,#0b01000000 ; we want Busy(7) to be 0 and ready(6) to be 1 + 0465 C2r5Bs04 1447 jp nz,ide_wait_ready + 0468 C9 1448 ret + 1449 + 1450 ;Wait for the drive to be ready to transfer data. + 1451 ;Returns the drive's status in Acc + 0469 1452 ide_wait_drq: + 0469 3E 0F 1453 ld a,#ide_status ; waut for DRQ bit to be set + 046B CDrCFs04 1454 call ide_read + 046E 79 1455 ld a,c + 046F E6 88 1456 and a,#0b10001000 ; mask off busy(7) and DRQ(3) + 0471 EE 08 1457 xor a,#0b00001000 ; we want busy(7) to be 0 and DRQ (3) to be 1 + 0473 C2r69s04 1458 jp nz,ide_wait_drq + 0476 C9 1459 ret + 1460 + 1461 + 1462 + 1463 ;------------------------------------------------------------------------------ + 1464 + 1465 ;Read a block of 512 bytes (one sector) from the drive + 1466 ;and store it in memory @ HL + 0477 1467 read_data: + 0477 06 00 1468 ld b,#0 + 0479 1469 rdblk2: + 0479 C5 1470 push bc + 047A E5 1471 push hl + 047B 3E 08 1472 ld a,#ide_data + 047D CDrCFs04 1473 call ide_read ; read form data port + 0480 E1 1474 pop hl + 0481 71 1475 ld (hl),c + 0482 23 1476 inc hl + 0483 70 1477 ld (hl),b + 0484 23 1478 inc hl + 0485 C1 1479 pop bc + 0486 05 1480 dec b + 0487 C2r79s04 1481 jp nz,rdblk2 + 048A C9 1482 ret + 1483 + 1484 ;----------------------------------------------------------------------------- + 1485 + 1486 ;Write a block of 512 bytes (at HL) to the drive + 048B 1487 write_data: + 048B 06 00 1488 ld b,#0 + 048D 1489 wrblk2: + 048D C5 1490 push bc + 048E 4E 1491 ld c,(hl) ; lsb + 048F 23 1492 inc hl + 0490 46 1493 ld b,(hl) ; msb + 0491 23 1494 inc hl + 0492 E5 1495 push hl + 0493 3E 08 1496 ld a,#ide_data + 0495 CDrEBs04 1497 call ide_write + 0498 E1 1498 pop hl + 0499 C1 1499 pop bc + 049A 05 1500 dec b + 049B C2r8Ds04 1501 jp nz,wrblk2 + 049E C9 1502 ret + 1503 + 1504 + 1505 ;----------------------------------------------------------------------------- + 1506 + 1507 ;write the logical block address to the drive's registers + 049F 1508 wr_lba: + 049F 3Ar7As05 1509 ld a,(IDE_LBA0+3) ; MSB + 04A2 E6 0F 1510 and a,#0x0f + 04A4 F6 E0 1511 or a,#0xe0 + 04A6 4F 1512 ld c,a + 04A7 3E 0E 1513 ld a,#ide_head + 04A9 CDrEBs04 1514 call ide_write + 04AC 3Ar79s05 1515 ld a,(IDE_LBA0+2) + 04AF 4F 1516 ld c,a + 04B0 3E 0D 1517 ld a,#ide_cyl_msb + 04B2 CDrEBs04 1518 call ide_write + 04B5 3Ar78s05 1519 ld a,(IDE_LBA0+1) + 04B8 4F 1520 ld c,a + 04B9 3E 0C 1521 ld a,#ide_cyl_lsb + 04BB CDrEBs04 1522 call ide_write + 04BE 3Ar77s05 1523 ld a,(IDE_LBA0) ; LSB + 04C1 4F 1524 ld c,a + 04C2 3E 0B 1525 ld a,#ide_sector + 04C4 CDrEBs04 1526 call ide_write + 04C7 0E 01 1527 ld c,#1 + 04C9 3E 0A 1528 ld a,#ide_sec_cnt + 04CB CDrEBs04 1529 call ide_write + 1530 + 04CE C9 1531 ret + 1532 + 1533 ;------------------------------------------------------------------------------- + 1534 + 1535 ; Low Level I/O to the drive. These are the routines that talk + 1536 ; directly to the drive, via the 8255 chip. Normally a main + 1537 ; program would not call to these. + 1538 + 1539 ;Do a read bus cycle to the drive, using the 8255. + 1540 ;input A = ide regsiter address + 1541 ;output C = lower byte read from ide drive + 1542 ;output B = upper byte read from ide drive + 1543 + 04CF 1544 ide_read: + 04CF F5 1545 push af ; save register value + 04D0 CDr05s05 1546 call set_ppi_rd ; setup for a read cycle + 04D3 F1 1547 pop af ; restore register value + 04D4 D3 82 1548 out (IDECTL),a ;drive address onto control lines + 04D6 F6 40 1549 or a,#ide_rd_line ; assert RD pin + 04D8 D3 82 1550 out (IDECTL),a + 04DA F5 1551 push af ; save register value + 04DB DB 80 1552 in a,(IDELSB) ; read lower byte + 04DD 4F 1553 ld c,a ; save in c reg + 04DE DB 81 1554 in a,(IDEMSB) ; read upper byte + 04E0 47 1555 ld b,a ; save in reg b + 04E1 F1 1556 pop af ; restore reg value + 04E2 EE 40 1557 xor a,#ide_rd_line ; deassert RD signal + 04E4 D3 82 1558 out (IDECTL),a + 04E6 3E 00 1559 ld a,#0 ;; DWG SAYS couln't this be a 1 byter? + 04E8 D3 82 1560 out (IDECTL),a ;deassert all control pins + 04EA C9 1561 ret + 1562 + 1563 ;Do a write bus cycle to the drive, via the 8255 + 1564 ;input A = ide register address + 1565 ;input register C = lsb to write + 1566 ;input register B = msb to write + 1567 ; + 1568 + 1569 + 04EB 1570 ide_write: + 04EB F5 1571 push af ; save IDE reg valure + 04EC CDr0As05 1572 call set_ppi_wr ; setup for a write cycle + 04EF 79 1573 ld a,c ; get value to be written + 04F0 D3 80 1574 out (IDELSB),a + 04F2 78 1575 ld a,b ; get value to be written + 04F3 D3 81 1576 out (IDEMSB),a + 04F5 F1 1577 pop af ; restore saved IDE reg + 04F6 D3 82 1578 out (IDECTL),a ; drive address onto control lines + 04F8 F6 20 1579 or a,#ide_wr_line ; assert write pin + 04FA D3 82 1580 out (IDECTL),a + 04FC EE 20 1581 xor a,#ide_wr_line ; deasser write pin + 04FE D3 82 1582 out (IDECTL),a ;drive address onto control lines + 0500 3E 00 1583 ld a,#0 ;; DWG SAYS couldn't this be 1 byter? + 0502 D3 82 1584 out (IDECTL),a ; release bus signals + 0504 C9 1585 ret + 1586 + 1587 + 1588 ;----------------------------------------------------------------------------------- + 1589 ; ppi setup routine to configure the appropriate PPI mode + 1590 ; + 1591 ;------------------------------------------------------------------------------------ + 1592 + 0505 1593 set_ppi_rd: + 0505 3E 92 1594 ld a,#rd_ide_8255 + 0507 D3 83 1595 out (PIO1CONT),a ;config 8255 chip, read mode + 0509 C9 1596 ret + 1597 + 050A 1598 set_ppi_wr: + 050A 3E 80 1599 ld a,#wr_ide_8255 + 050C D3 83 1600 out (PIO1CONT),a ;config 8255 chip, write mode + 050E C9 1601 ret + 1602 + 1603 ;----------------------------------------------------------------------------- + 1604 ; End of PPIDE disk driver + 1605 ;------------------------------------------------------------------------------------ + 1606 + 1607 + 1608 ; TEXT STRINGS + 1609 + 050F 1610 TXT_RO_ERROR: + 050F 0D 0A 1611 .DB CR,LF + 0511 45 52 52 4F 52 3A 1612 .ascii "ERROR: WRITE TO READ ONLY DISK" + 20 57 52 49 54 45 + 20 54 4F 20 52 45 + 41 44 20 4F 4E 4C + 59 20 44 49 53 4B + 052F FF 1613 .DB END + 1614 + 0530 1615 TXT_STARTUP_MSG: + 0530 0D 0A 1616 .DB CR,LF + 0532 43 50 2F 4D 2D 38 1617 .ascii "CP/M-80 VERSION 2.2C FOR THE " + 30 20 56 45 52 53 + 49 4F 4E 20 32 2E + 32 43 20 46 4F 52 + 20 54 48 45 20 + 054F 4E 38 56 45 4D 20 1618 .ascii "N8VEM N8" + 4E 38 + 0557 20 28 50 50 49 44 1619 .ascii " (PPIDE)" + 45 29 + 055F 0D 0A 1620 .DB CR,LF + 0561 FF 1621 .DB END + 1622 + 1623 ; + 1624 ; THE REMAINDER OF THE CBIOS IS RESERVED UNINITIALIZED + 1625 ; DATA AREA, AND DOES NOT NEED TO BE A PART OF THE + 1626 ; SYSTEM MEMORY IMAGE + 1627 ; + 0562 1628 TRACK: .DS 2 ; TWO BYTES FOR TRACK # + 0564 1629 SECTOR: .DS 2 ; TWO BYTES FOR SECTOR # + 0566 1630 DMAAD: .DS 2 ; DIRECT MEMORY ADDRESS + 0568 1631 DISKNO: .DS 1 ; DISK NUMBER 0-15 + 1632 + 1633 + 0569 01 1634 PAGER: .DB 1 ; COPY OF PAGER BYTE + 1635 + 056A FF 1636 DB_PAGER: .db 0xff ; copy of pager byte + 1637 + 056B 1638 V_SECTOR: .DS 2 ; TWO BYTES FOR VIRTUAL SECTOR # + 056D 1639 SECST: .DS 2 ; SECTOR IN ROM/RAM START ADDRESS + 1640 + 1641 + 056F 00 00 1642 LBA_OFFSET_LO: .DW 0 ; IDE HD PART STARTING SECTOR (LOW 16 BITS) + 0571 00 00 1643 LBA_OFFSET_HI: .DW 0 ; IDE HD PART STARTING SECTOR (HI 16 BITS, 12 USED) + 0573 00 00 1644 LBA_TARGET_LO: .DW 0 ; IDE HD PART TARGET SECTOR (LOW 16 BITS) + 0575 00 00 1645 LBA_TARGET_HI: .DW 0 ; IDE HD PART TARGET SECTOR (HI 16 BITS, 12 USED) + 1646 + 0577 1647 IDE_LBA0: .DS 1 ;SET LBA 0:7 + 0578 1648 IDE_LBA1: .DS 1 ;SET LBA 8:15 + 0579 1649 IDE_LBA2: .DS 1 ;SET LBA 16:23 + 057A 1650 IDE_LBA3: .DS 1 ;LOWEST 4 BITS USED ONLY TO ENABLE LBA MODE + 1651 + 057B 00 1652 SECTOR_INDEX: .DB 0 ;WHERE 128 BYTE CP/M SECTOR IS IN 512 BYTE IDE HD SECTOR + 1653 + 1654 + 1655 ; + 1656 ; SCRATCH RAM AREA FOR BDOS USE + 1657 ; + 1658 ; Note: this can extend up to the beginning of the debug monitor however + 1659 ; there is a limitation in the amount of space available in the EPROM + 1660 ; + 1661 ;BEGDAT .EQU $ ;BEGINNING OF DATA AREA + 1662 ; + 1663 ; + 1664 + 057C 1665 SECTOR_BUFFER: .DS 512 ;Deblocking STORAGE FOR 512 BYTE IDE HD SECTOR + 1666 + 1667 ;dwg;TMPBUF .EQU SECTOR_BUFFER + 057C 1668 TMPBUF = SECTOR_BUFFER + 1669 + 077C 1670 DIRBF: .DS 128 ;SCRATCH DIRECTORY AREA + 07FC 1671 ALL00: .DS 4 ;ALLOCATION VECTOR 0 (DSM/8 = 1 BIT PER BLOCK) + 0800 1672 ALL01: .DS 32 ;ALLOCATION VECTOR 1 (225/8) + 0820 1673 ALL02: .DS 255 ;ALLOCATION VECTOR 2 (2040/8) + 091F 1674 ALL03: .DS 255 ;ALLOCATION VECTOR 3 (2040/8) + 0A1E 1675 ALL04: .DS 64 ;ALLOCATION VECTOR 4 (511/8) + 0A5E 1676 ALL05: .DS 64 ;ALLOCATION VECTOR 5 (495/8) + 1677 ; + 0A9E 1678 CHK00: .DS 0 ; NOT USED FOR FIXED MEDIA + 0A9E 1679 CHK01: .DS 0 ; NOT USED FOR FIXED MEDIA + 0A9E 1680 CHK02: .DS 0 ; NOT USED FOR FIXED MEDIA + 0A9E 1681 CHK03: .DS 0 ; NOT USED FOR FIXED MEDIA + 0A9E 1682 CHK04: .DS 0 ; NOT USED FOR FIXED MEDIA + 0A9E 1683 CHK05: .DS 0 ; NOT USED FOR FIXED MEDIA + 1684 + 1685 ; DOUG SAYS - THIS NEEDS TO BE DONE ANOTHER WAY NO ORGS IN REL SEG + 1686 ; + 1687 ; .ORG $F2FF + 1688 ; + 1689 ; F2FF - desired org + 1690 ; - E600 - BIOS ORG + 1691 ; ______ + 1692 ; 0CFF - necessary offset in this module + 1693 ; + 1694 ; 0CCF ; where we want to be + 1695 ; - 0AA9 ; where we are now + 1696 ; ______ + 1697 ; 0256 - adjustment to reach desired org in rel segment + 1698 ; + 1699 + 0A9E 1700 .ds 0x0256 ; THIS NEEDS TO BE ADJUSTED SO LASTBYTE IS AT 0CFF + 1701 + 0CF4 E5 1702 LASTBYTE: .DB 0xE5 ; note this is just to force out the last byte. + 1703 ; this address will actually fall within the + 1704 ; allocation vector block + 1705 + 0CF5 1706 _cbioshc_end:: + 1707 .area _CODE + 1708 .area _CABS diff --git a/doug/src/cbiosn8.rel b/doug/src/cbiosn8.rel new file mode 100755 index 00000000..8164539c --- /dev/null +++ b/doug/src/cbiosn8.rel @@ -0,0 +1,526 @@ +XL +H 8 areas 4 global symbols +M cbioshc +O -mz80 +S .__.ABS. Def0000 +A _CODE size 0 flags 0 addr 0 +A _DATA size 0 flags 0 addr 0 +A _OVERLAY size 0 flags 0 addr 0 +A _HOME size 0 flags 0 addr 0 +A _GSINIT size 0 flags 0 addr 0 +A _GSFINAL size 0 flags 0 addr 0 +A _CBIOS size CF5 flags 0 addr 0 +S _cbioshc_start Def0000 +S _cbioshc_end Def0CF5 +S _cbioshc Def0000 +A _CABS size 0 flags 0 addr 0 +T 00 00 +R 00 00 06 00 +T 00 00 +R 00 00 06 00 +T 00 00 C3 DD 00 C3 F5 00 C3 2F 01 C3 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 0A 00 41 01 C3 53 01 C3 65 01 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 13 00 6B 01 C3 6E 01 C3 C6 01 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 1C 00 AF 01 C3 C9 01 C3 CF 01 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 25 00 D8 01 C3 DE 01 C3 02 02 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 2E 00 68 01 C3 D5 01 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 33 00 +R 00 00 06 00 +T 33 00 00 00 00 00 00 00 00 00 7C 07 83 00 9E 0A +R 00 00 06 00 00 0A 06 00 00 0C 06 00 00 0E 06 00 +T 41 00 FC 07 00 00 00 00 00 00 00 00 7C 07 CE 00 +R 00 00 06 00 00 02 06 00 00 0C 06 00 00 0E 06 00 +T 4F 00 9E 0A 5E 0A 00 00 00 00 00 00 00 00 7C 07 +R 00 00 06 00 00 02 06 00 00 04 06 00 00 0E 06 00 +T 5D 00 A1 00 9E 0A 20 08 00 00 00 00 00 00 00 00 +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 6B 00 7C 07 B0 00 9E 0A +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 71 00 1F 09 00 00 00 00 00 00 00 00 7C 07 BF 00 +R 00 00 06 00 00 02 06 00 00 0C 06 00 00 0E 06 00 +T 7F 00 9E 0A 1E 0A +R 00 00 06 00 00 02 06 00 00 04 06 00 +T 83 00 +R 00 00 06 00 +T 83 00 00 01 04 0F 01 DF 00 FF 00 F0 00 00 00 +R 00 00 06 00 +T 90 00 02 00 +R 00 00 06 00 +T 92 00 +R 00 00 06 00 +T 92 00 10 00 03 07 00 1F 00 1F 00 80 00 00 00 +R 00 00 06 00 +T 9F 00 05 00 +R 00 00 06 00 +T A1 00 +R 00 00 06 00 +T A1 00 00 01 05 1F 01 F7 07 FF 01 F0 00 00 00 +R 00 00 06 00 +T AE 00 01 00 +R 00 00 06 00 +T B0 00 +R 00 00 06 00 +T B0 00 00 01 05 1F 01 F7 07 FF 01 F0 00 00 00 +R 00 00 06 00 +T BD 00 01 00 +R 00 00 06 00 +T BF 00 +R 00 00 06 00 +T BF 00 00 01 04 0F 00 F1 01 FF 00 F0 00 00 00 +R 00 00 06 00 +T CC 00 01 00 +R 00 00 06 00 +T CE 00 +R 00 00 06 00 +T CE 00 00 01 04 0F 00 EF 01 FF 00 F0 00 00 00 +R 00 00 06 00 +T DB 00 01 00 +R 00 00 06 00 +T DD 00 +R 00 00 06 00 +T DD 00 F3 3E 80 D3 94 3E 01 32 04 00 3E 94 32 +R 00 00 06 00 +T EA 00 03 00 21 30 05 CD 89 03 C3 0E 01 +R 00 00 06 00 00 05 06 00 00 08 06 00 00 0B 06 00 +T F5 00 +R 00 00 06 00 +T F5 00 F3 31 80 00 AF D3 94 AF D3 96 21 00 09 11 +R 00 00 06 00 +T 03 01 00 D4 01 FF 15 ED B0 3E 80 D3 94 +R 00 00 06 00 +T 0E 01 +R 00 00 06 00 +T 0E 01 3E C3 32 00 00 21 03 00 22 01 00 32 05 00 +R 00 00 06 00 00 08 06 00 +T 1C 01 21 06 DC 22 06 00 01 80 00 CD D8 01 3A +R 00 00 06 00 00 0C 06 00 +T 29 01 04 00 4F C3 00 D4 +R 00 00 06 00 +T 2F 01 +R 00 00 06 00 +T 2F 01 3A 03 00 E6 03 FE 00 CA 91 01 FE 01 CA +R 00 00 06 00 00 0A 06 00 +T 3C 01 A9 01 C3 76 01 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 41 01 +R 00 00 06 00 +T 41 01 3A 03 00 E6 03 FE 00 CA 79 01 FE 01 CA +R 00 00 06 00 00 0A 06 00 +T 4E 01 A3 01 C3 71 01 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 53 01 +R 00 00 06 00 +T 53 01 3A 03 00 E6 03 FE 00 CA 85 01 FE 01 CA +R 00 00 06 00 00 0A 06 00 +T 60 01 A6 01 C3 74 01 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 65 01 +R 00 00 06 00 +T 65 01 C3 74 01 +R 00 00 06 00 00 03 06 00 +T 68 01 +R 00 00 06 00 +T 68 01 C3 76 01 +R 00 00 06 00 00 03 06 00 +T 6B 01 +R 00 00 06 00 +T 6B 01 C3 74 01 +R 00 00 06 00 00 03 06 00 +T 6E 01 +R 00 00 06 00 +T 6E 01 C3 71 01 +R 00 00 06 00 00 03 06 00 +T 71 01 +R 00 00 06 00 +T 71 01 3E 1A C9 +R 00 00 06 00 +T 74 01 +R 00 00 06 00 +T 74 01 79 C9 +R 00 00 06 00 +T 76 01 +R 00 00 06 00 +T 76 01 3E 01 C9 +R 00 00 06 00 +T 79 01 +R 00 00 06 00 +T 79 01 CD 91 01 FE 00 CA 79 01 ED 38 48 C9 +R 00 00 06 00 00 03 06 00 00 08 06 00 +T 85 01 +R 00 00 06 00 +T 85 01 CD 9A 01 A7 CA 85 01 79 ED 39 46 C9 +R 00 00 06 00 00 03 06 00 00 07 06 00 +T 91 01 +R 00 00 06 00 +T 91 01 ED 38 44 E6 80 C8 3E FF C9 +R 00 00 06 00 +T 9A 01 +R 00 00 06 00 +T 9A 01 ED 38 44 E6 02 C8 3E FF C9 +R 00 00 06 00 +T A3 01 +R 00 00 06 00 +T A3 01 C3 71 01 +R 00 00 06 00 00 03 06 00 +T A6 01 +R 00 00 06 00 +T A6 01 C3 74 01 +R 00 00 06 00 00 03 06 00 +T A9 01 +R 00 00 06 00 +T A9 01 C3 76 01 +R 00 00 06 00 00 03 06 00 +T AC 01 +R 00 00 06 00 +T AC 01 C3 76 01 +R 00 00 06 00 00 03 06 00 +T AF 01 +R 00 00 06 00 +T AF 01 21 00 00 79 FE 04 D0 79 32 68 05 6F 26 00 +R 00 00 06 00 00 0B 06 00 +T BD 01 29 29 29 29 11 33 00 19 C9 +R 00 00 06 00 00 07 06 00 +T C6 01 +R 00 00 06 00 +T C6 01 01 00 00 +R 00 00 06 00 +T C9 01 +R 00 00 06 00 +T C9 01 60 69 22 62 05 C9 +R 00 00 06 00 00 05 06 00 +T CF 01 +R 00 00 06 00 +T CF 01 60 69 22 64 05 C9 +R 00 00 06 00 00 05 06 00 +T D5 01 +R 00 00 06 00 +T D5 01 60 69 C9 +R 00 00 06 00 +T D8 01 +R 00 00 06 00 +T D8 01 69 60 22 66 05 C9 +R 00 00 06 00 00 05 06 00 +T DE 01 +R 00 00 06 00 +T DE 01 3A 68 05 FE 00 CA 2F 02 FE 01 CA 5F 02 FE +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0D 06 00 +T EC 01 02 CA B6 02 FE 03 CA C5 02 FE 04 CA D4 02 +R 00 00 06 00 00 04 06 00 00 09 06 00 00 0E 06 00 +T FA 01 FE 05 CA D4 02 3E 01 C9 +R 00 00 06 00 00 05 06 00 +T 02 02 +R 00 00 06 00 +T 02 02 3A 68 05 FE 00 CA 86 02 FE 01 CA 26 02 FE +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0D 06 00 +T 10 02 02 CA 1C 03 FE 03 CA 2B 03 FE 04 CA 3A 03 +R 00 00 06 00 00 04 06 00 00 09 06 00 00 0E 06 00 +T 1E 02 FE 05 CA 3A 03 3E 01 C9 +R 00 00 06 00 00 05 06 00 +T 26 02 +R 00 00 06 00 +T 26 02 21 0F 05 CD 89 03 3E 01 C9 +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 2F 02 +R 00 00 06 00 +T 2F 02 F3 CD 98 03 2A 62 05 29 29 29 7D ED 39 79 +R 00 00 06 00 00 04 06 00 00 07 06 00 +T 3D 02 21 7C 05 54 5D 2A 6D 05 01 80 00 ED B0 3E +R 00 00 06 00 00 03 06 00 00 08 06 00 +T 4B 02 00 ED 39 79 2A 66 05 5D 54 21 7C 05 01 +R 00 00 06 00 00 07 06 00 00 0C 06 00 +T 58 02 80 00 ED B0 3E 00 C9 +R 00 00 06 00 +T 5F 02 +R 00 00 06 00 +T 5F 02 F3 CD 98 03 CD A6 03 21 7C 05 54 5D 2A +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T 6C 02 6D 05 01 80 00 ED B0 CD B9 03 2A 66 05 5D +R 00 00 06 00 00 02 06 00 00 0A 06 00 00 0D 06 00 +T 7A 02 54 21 7C 05 01 80 00 ED B0 3E 00 C9 +R 00 00 06 00 00 04 06 00 +T 86 02 +R 00 00 06 00 +T 86 02 21 7C 05 54 5D 2A 66 05 01 80 00 ED B0 F3 +R 00 00 06 00 00 03 06 00 00 08 06 00 +T 94 02 CD 98 03 2A 62 05 29 29 29 7D ED 39 79 2A +R 00 00 06 00 00 03 06 00 00 06 06 00 +T A2 02 6D 05 54 5D 21 7C 05 01 80 00 ED B0 3E 00 +R 00 00 06 00 00 02 06 00 00 07 06 00 +T B0 02 ED 39 79 3E 00 C9 +R 00 00 06 00 +T B6 02 +R 00 00 06 00 +T B6 02 21 01 00 22 6F 05 21 00 00 22 71 05 C3 +R 00 00 06 00 00 06 06 00 00 0C 06 00 +T C3 02 D5 02 +R 00 00 06 00 00 02 06 00 +T C5 02 +R 00 00 06 00 +T C5 02 21 01 40 22 6F 05 21 00 00 22 71 05 C3 +R 00 00 06 00 00 06 06 00 00 0C 06 00 +T D2 02 D5 02 +R 00 00 06 00 00 02 06 00 +T D4 02 +R 00 00 06 00 +T D4 02 +R 00 00 06 00 +T D4 02 C9 +R 00 00 06 00 +T D5 02 +R 00 00 06 00 +T D5 02 2A 62 05 45 2A 64 05 60 CD C4 03 3A +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0B 06 00 +T E1 02 73 05 32 77 05 3A 74 05 32 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T EA 02 78 05 3A 75 05 32 79 05 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T F3 02 76 05 E6 0F C6 E0 32 7A 05 CD FC 03 21 +R 00 00 06 00 00 02 06 00 00 09 06 00 00 0C 06 00 +T 00 03 7C 05 3A 7B 05 CB 0F CB 0F 16 00 5F 19 19 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 0E 03 54 5D 2A 66 05 EB 01 80 00 ED B0 3E 00 C9 +R 00 00 06 00 00 05 06 00 +T 1C 03 +R 00 00 06 00 +T 1C 03 21 01 00 22 6F 05 21 00 00 22 71 05 C3 +R 00 00 06 00 00 06 06 00 00 0C 06 00 +T 29 03 3B 03 +R 00 00 06 00 00 02 06 00 +T 2B 03 +R 00 00 06 00 +T 2B 03 21 01 40 22 6F 05 21 00 00 22 71 05 C3 +R 00 00 06 00 00 06 06 00 00 0C 06 00 +T 38 03 3B 03 +R 00 00 06 00 00 02 06 00 +T 3A 03 +R 00 00 06 00 +T 3A 03 +R 00 00 06 00 +T 3A 03 C9 +R 00 00 06 00 +T 3B 03 +R 00 00 06 00 +T 3B 03 2A 62 05 45 2A 64 05 60 CD C4 03 3A +R 00 00 06 00 00 03 06 00 00 07 06 00 00 0B 06 00 +T 47 03 73 05 32 77 05 3A 74 05 32 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 50 03 78 05 3A 75 05 32 79 05 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 59 03 76 05 E6 0F C6 E0 32 7A 05 CD FC 03 21 +R 00 00 06 00 00 02 06 00 00 09 06 00 00 0C 06 00 +T 66 03 7C 05 3A 7B 05 CB 0F CB 0F 16 00 5F 19 19 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 74 03 22 6D 05 2A 6D 05 EB 2A 66 05 01 80 00 ED +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0A 06 00 +T 82 03 B0 CD 15 04 3E 00 C9 +R 00 00 06 00 00 04 06 00 +T 89 03 +R 00 00 06 00 +T 89 03 7E FE FF CA 97 03 4F CD 53 01 23 C3 89 03 +R 00 00 06 00 00 06 06 00 00 0A 06 00 00 0E 06 00 +T 97 03 +R 00 00 06 00 +T 97 03 C9 +R 00 00 06 00 +T 98 03 +R 00 00 06 00 +T 98 03 2A 64 05 29 29 29 29 29 29 29 22 6D 05 C9 +R 00 00 06 00 00 03 06 00 00 0D 06 00 +T A6 03 +R 00 00 06 00 +T A6 03 2A 62 05 7D ED 39 96 3E 00 ED 39 94 32 +R 00 00 06 00 00 03 06 00 +T B3 03 69 05 32 6A 05 C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T B9 03 +R 00 00 06 00 +T B9 03 3E 80 ED 39 94 3E 00 32 69 05 C9 +R 00 00 06 00 00 0A 06 00 +T C4 03 +R 00 00 06 00 +T C4 03 AF 7D E6 03 47 32 7B 05 37 3F 7C 1F 67 7D +R 00 00 06 00 00 08 06 00 +T D2 03 1F 6F 37 3F 7C 1F 67 7D 1F 6F 3A 6F 05 85 +R 00 00 06 00 00 0D 06 00 +T E0 03 32 73 05 3A 70 05 8C 32 74 05 21 00 00 3A +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0A 06 00 +T EE 03 71 05 8D 32 75 05 3A 72 05 8C 32 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T F9 03 76 05 C9 +R 00 00 06 00 00 02 06 00 +T FC 03 +R 00 00 06 00 +T FC 03 CD 4F 04 CD 9F 04 3E 0F 0E 20 CD EB 04 CD +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0D 06 00 +T 0A 04 69 04 21 7C 05 CD 77 04 3E 00 C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 15 04 +R 00 00 06 00 +T 15 04 CD 4F 04 CD 9F 04 3E 0F 0E 30 CD EB 04 CD +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0D 06 00 +T 23 04 69 04 21 7C 05 CD 8B 04 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 2C 04 4F 04 C9 +R 00 00 06 00 00 02 06 00 +T 2F 04 +R 00 00 06 00 +T 2F 04 CD 05 05 3E 80 D3 82 01 00 00 +R 00 00 06 00 00 03 06 00 +T 39 04 +R 00 00 06 00 +T 39 04 05 C2 39 04 3E 00 D3 82 C9 +R 00 00 06 00 00 04 06 00 +T 42 04 +R 00 00 06 00 +T 42 04 3E 09 CD CF 04 79 CA 4C 04 C9 +R 00 00 06 00 00 05 06 00 00 09 06 00 +T 4C 04 +R 00 00 06 00 +T 4C 04 3E FF C9 +R 00 00 06 00 +T 4F 04 +R 00 00 06 00 +T 4F 04 3E 0F CD CF 04 79 E6 80 C2 4F 04 C9 +R 00 00 06 00 00 05 06 00 00 0B 06 00 +T 5B 04 +R 00 00 06 00 +T 5B 04 3E 0F CD CF 04 79 E6 C0 EE 40 C2 5B 04 C9 +R 00 00 06 00 00 05 06 00 00 0D 06 00 +T 69 04 +R 00 00 06 00 +T 69 04 3E 0F CD CF 04 79 E6 88 EE 08 C2 69 04 C9 +R 00 00 06 00 00 05 06 00 00 0D 06 00 +T 77 04 +R 00 00 06 00 +T 77 04 06 00 +R 00 00 06 00 +T 79 04 +R 00 00 06 00 +T 79 04 C5 E5 3E 08 CD CF 04 E1 71 23 70 23 C1 05 +R 00 00 06 00 00 07 06 00 +T 87 04 C2 79 04 C9 +R 00 00 06 00 00 03 06 00 +T 8B 04 +R 00 00 06 00 +T 8B 04 06 00 +R 00 00 06 00 +T 8D 04 +R 00 00 06 00 +T 8D 04 C5 4E 23 46 23 E5 3E 08 CD EB 04 E1 C1 05 +R 00 00 06 00 00 0B 06 00 +T 9B 04 C2 8D 04 C9 +R 00 00 06 00 00 03 06 00 +T 9F 04 +R 00 00 06 00 +T 9F 04 3A 7A 05 E6 0F F6 E0 4F 3E 0E CD EB 04 3A +R 00 00 06 00 00 03 06 00 00 0D 06 00 +T AD 04 79 05 4F 3E 0D CD EB 04 3A 78 05 4F 3E 0C +R 00 00 06 00 00 02 06 00 00 08 06 00 00 0B 06 00 +T BB 04 CD EB 04 3A 77 05 4F 3E 0B CD EB 04 0E 01 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0C 06 00 +T C9 04 3E 0A CD EB 04 C9 +R 00 00 06 00 00 05 06 00 +T CF 04 +R 00 00 06 00 +T CF 04 F5 CD 05 05 F1 D3 82 F6 40 D3 82 F5 DB 80 +R 00 00 06 00 00 04 06 00 +T DD 04 4F DB 81 47 F1 EE 40 D3 82 3E 00 D3 82 C9 +R 00 00 06 00 +T EB 04 +R 00 00 06 00 +T EB 04 F5 CD 0A 05 79 D3 80 78 D3 81 F1 D3 82 F6 +R 00 00 06 00 00 04 06 00 +T F9 04 20 D3 82 EE 20 D3 82 3E 00 D3 82 C9 +R 00 00 06 00 +T 05 05 +R 00 00 06 00 +T 05 05 3E 92 D3 83 C9 +R 00 00 06 00 +T 0A 05 +R 00 00 06 00 +T 0A 05 3E 80 D3 83 C9 +R 00 00 06 00 +T 0F 05 +R 00 00 06 00 +T 0F 05 0D 0A 45 52 52 4F 52 3A 20 57 52 49 54 45 +R 00 00 06 00 +T 1D 05 20 54 4F 20 52 45 41 44 20 4F 4E 4C 59 20 +R 00 00 06 00 +T 2B 05 44 49 53 4B FF +R 00 00 06 00 +T 30 05 +R 00 00 06 00 +T 30 05 0D 0A 43 50 2F 4D 2D 38 30 20 56 45 52 53 +R 00 00 06 00 +T 3E 05 49 4F 4E 20 32 2E 32 43 20 46 4F 52 20 54 +R 00 00 06 00 +T 4C 05 48 45 20 4E 38 56 45 4D 20 4E 38 20 28 50 +R 00 00 06 00 +T 5A 05 50 49 44 45 29 0D 0A FF +R 00 00 06 00 +T 62 05 +R 00 00 06 00 +T 64 05 +R 00 00 06 00 +T 66 05 +R 00 00 06 00 +T 68 05 +R 00 00 06 00 +T 69 05 01 FF +R 00 00 06 00 +T 6B 05 +R 00 00 06 00 +T 6D 05 +R 00 00 06 00 +T 6F 05 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 77 05 +R 00 00 06 00 +T 78 05 +R 00 00 06 00 +T 79 05 +R 00 00 06 00 +T 7A 05 +R 00 00 06 00 +T 7B 05 00 +R 00 00 06 00 +T 7C 05 +R 00 00 06 00 +T 7C 07 +R 00 00 06 00 +T FC 07 +R 00 00 06 00 +T 00 08 +R 00 00 06 00 +T 20 08 +R 00 00 06 00 +T 1F 09 +R 00 00 06 00 +T 1E 0A +R 00 00 06 00 +T 5E 0A +R 00 00 06 00 +T 9E 0A +R 00 00 06 00 +T 9E 0A +R 00 00 06 00 +T 9E 0A +R 00 00 06 00 +T 9E 0A +R 00 00 06 00 +T 9E 0A +R 00 00 06 00 +T 9E 0A +R 00 00 06 00 +T 9E 0A +R 00 00 06 00 +T F4 0C E5 +R 00 00 06 00 +T F5 0C +R 00 00 06 00 diff --git a/doug/src/cbiosn8.s b/doug/src/cbiosn8.s new file mode 100755 index 00000000..79957ceb --- /dev/null +++ b/doug/src/cbiosn8.s @@ -0,0 +1,1708 @@ +;-------------------------------------------------------- +; cbioshc.s derived from CPM22-HC.ASM by dwg 5/18-30/2011 +;-------------------------------------------------------- + .module cbioshc + .optsdcc -mz80 +;-------------------------------------------------------- +; Public variables in this module +;-------------------------------------------------------- + .globl _cbioshc +;-------------------------------------------------------- +; special function registers +;-------------------------------------------------------- +;-------------------------------------------------------- +; ram data +;-------------------------------------------------------- + .area _DATA +;-------------------------------------------------------- +; overlayable items in ram +;-------------------------------------------------------- + .area _OVERLAY +;-------------------------------------------------------- +; external initialized ram data +;-------------------------------------------------------- +;-------------------------------------------------------- +; global & static initialisations +;-------------------------------------------------------- + .area _HOME + .area _GSINIT + .area _GSFINAL + .area _GSINIT +;-------------------------------------------------------- +; Home +;-------------------------------------------------------- + .area _HOME + .area _HOME +;-------------------------------------------------------- +; code +;-------------------------------------------------------- + .area _CBIOS +_cbioshc_start:: +_cbioshc: + +;************************************************************** +;* +;* C B I O S f o r +;* +;* T e s t P r o t o t y p e +;* +;* by Andrew Lynch, with input from many sources +;* Updated 24-Mar-2009 Max Scane - changed seldsk: to not save bogus drive value +;* changed a: to be ram drive, B: to be rom disk +;* Updated 1-Jun-2010 Max Scane - Changed DPBs to be more sane +;* Updated 1-Jul-2010 Max Scane - Added PPIDE driver and conditionals +;* Updated April 2011 Max Scane - Adapted for the N8VEM Home Computer +;************************************************************** +; +; SKELETAL CBIOS FOR FIRST LEVEL OF CP/M 2.0 ALTERATION +; WITH MODS FOR CP/M ROMDISK AND RAMDISK. +; +; ENTIRELY IN 8080 MNEUMONICS (SO ASM CAN BE USED) +; BUT ASSUMES A Z80! (remove) +; + +MEM = 60 ; DOUGTEMP DOUGTEMP + + +;MSIZE .EQU 20 ;CP/M VERSION MEMORY SIZE IN KILOBYTES +;MSIZE .EQU 62 ;CP/M VERSION MEMORY SIZE IN KILOBYTES +; MEM defined in CPM22 above, line 0015 + +MSIZE = MEM ;CP/M VERSION MEMORY SIZE IN KILOBYTES + +; +; "BIAS" IS ADDRESS OFFSET FROM 3400H FOR MEMORY SYSTEMS +; THAN 16K (REFERRED TO AS "B" THROUGHOUT THE TEXT). +; + +BIAS = (MSIZE-20)*1024 + +CCP = 0x3400+BIAS ; base of ccp + +BDOS = CCP+0x0806 ; base of BDOS + +BIOS = CCP+0x1600 ; base of BIOS + +CDISK = 0x0004 ; current disk number 0=a,...,15=p + +; IOBYTE already defined in CPM22 above, line 0017 +;IOBYTE .EQU 0003H ;INTEL I/O BYTE + +; since the assembly has been broken into pieces, +; this symbols wasn't previously encountered. +; It could be exported from other module, but why? +IOBYTE = 0x0003 + +; +; CONSTANTS + + +END = 0x0FF + + +CR = 0x0d +LF = 0x0a + +DEFIOB = 0x94 ; default IOBYTE (TTY,RDR,PUN,LPT) + +; + +ROMSTART_MON = 0x0100 ; where the monitor is stored in ROM + +RAMTARG_MON = 0x0f800 ; where the monitor starts in RAM + +MOVSIZ_MON = 0x0800 ; monitor is 2K in length + +ROMSTART_CPM = 0x0900 ; where ccp+bdos+bios is stored in ROM + +RAMTARG_CPM = 0x0D400 ; where ccp+bdos+bios starts in RAM + +;dwg; INTERESTING - 0x15FF is 4K+1K+512-1, not 5KB +;dwg;MOVSIZ_CPM: .EQU $15FF ; CCP, BDOS IS 5KB IN LENGTH +MOVSIZ_CPM = 0x15FF ; ccp+bdos is 5KB in length + +HC_REG_BASE = 0x80 ; N8 I/I Regs $80-9F + +PPI1 = HC_REG_BASE+0x00 + +ACR = HC_REG_BASE+0x14 + +RMAP = ACR+2 + +IO_REG_BASE = 0x40 ; IO reg base offset for Z1x80 + +CNTLA0 = IO_REG_BASE+0x00 + +CNTLB0 = IO_REG_BASE+0x02 + +STAT0 = IO_REG_BASE+0x04 + +TDR0 = IO_REG_BASE+0x06 + +RDR0 = IO_REG_BASE+0x08 + +ASEXT0 = IO_REG_BASE+0x12 + +CBR = IO_REG_BASE+0x38 + +BBR = IO_REG_BASE+0x39 + +CBAR = IO_REG_BASE+0x3A + +; +; +; PIO 82C55 I/O IS ATTACHED TO THE FIRST IO BASE ADDRESS + +IDELSB = PPI1+0 ; LSB + +IDEMSB = PPI1+1 ; MSB + +IDECTL = PPI1+2 ; Control Signals + +PIO1CONT = PPI1+3 ; Control Byte PIO 82C55 + +; PPI control bytes for read and write to IDE drive + +rd_ide_8255 = 0b10010010 ; ide_8255_ctl out ide_8255_lsb/msb input + +wr_ide_8255 = 0b10000000 ; all three ports output + +;ide control lines for use with ide_8255_ctl. Change these 8 +;constants to reflect where each signal of the 8255 each of the +;ide control signals is connected. All the control signals must +;be on the same port, but these 8 lines let you connect them to +;whichever pins on that port. + +ide_a0_line = 0x01 ; direct from 8255 to ide interface + +ide_a1_line = 0x02 ; direct from 8255 to ide intereface + +ide_a2_line = 0x04 ; direct from 8255 to ide interface + +ide_cs0_line = 0x08 ; inverter between 8255 and ide interface + +ide_cs1_line = 0x10 ; inverter between 8255 and ide interface + +ide_wr_line = 0x20 ; inverter between 8255 and ide interface + +ide_rd_line = 0x40 ; inverter between 8255 and ide interface + +ide_rst_line = 0x80 ; inverter between 8255 and ide interface + +;------------------------------------------------------------------ +; More symbolic constants... these should not be changed, unless of +; course the IDE drive interface changes, perhaps when drives get +; to 128G and the PC industry will do yet another kludge. + +;some symbolic constants for the ide registers, which makes the +;code more readable than always specifying the address pins + +ide_data = ide_cs0_line +ide_err = ide_cs0_line + ide_a0_line +ide_sec_cnt = ide_cs0_line + ide_a1_line +ide_sector = ide_cs0_line + ide_a1_line + ide_a0_line +ide_cyl_lsb = ide_cs0_line + ide_a2_line +ide_cyl_msb = ide_cs0_line + ide_a2_line + ide_a0_line +ide_head = ide_cs0_line + ide_a2_line + ide_a1_line +ide_command = ide_cs0_line + ide_a2_line + ide_a1_line + ide_a0_line +ide_status = ide_cs0_line + ide_a2_line + ide_a1_line + ide_a0_line +ide_control = ide_cs1_line + ide_a2_line + ide_a1_line +ide_astatus = ide_cs1_line + ide_a2_line + ide_a1_line + ide_a0_line + +;IDE Command Constants. These should never change. + +ide_cmd_recal = 0x10 +ide_cmd_read = 0x20 +ide_cmd_write = 0x30 +ide_cmd_init = 0x91 +ide_cmd_id = 0x0ec +ide_cmd_spindown = 0xe0 +ide_cmd_spinup = 0xe1 + + +; .ORG BIOS ;ORIGIN OF THIS PROGRAM + + +;dwg;NSECTS .EQU ($-CCP)/128 ;WARM START SECTOR COUNT + +; +; JUMP VECTOR FOR INDIVIDUAL SUBROUTINES + + JP BOOT ;COLD START +WBOOTE: JP WBOOT ;WARM START + JP CONST ;CONSOLE STATUS + JP CONIN ;CONSOLE CHARACTER IN + JP CONOUT ;CONSOLE CHARACTER OUT + JP LIST ;LIST CHARACTER OUT (NULL ROUTINE) + JP PUNCH ;PUNCH CHARACTER OUT (NULL ROUTINE) + JP READER ;READER CHARACTER OUT (NULL ROUTINE) + JP HOME ;MOVE HEAD TO HOME POSITION + JP SELDSK ;SELECT DISK + JP SETTRK ;SET TRACK NUMBER + JP SETSEC ;SET SECTOR NUMBER + JP SETDMA ;SET DMA ADDRESS + JP READ ;READ DISK + JP WRITE ;WRITE DISK + JP LISTST ;RETURN LIST STATUS (NULL ROUTINE) + JP SECTRN ;SECTOR TRANSLATE + +; +; FIXED DATA TABLES FOR ALL DRIVES +; 0= RAMDISK, 1=ROMDISK, 2=HDPART1, 3=HDPART2 +; DISK PARAMETER HEADER FOR DISK 00 (RAM Disk) +DPBASE: + .DW 0x0000,0x0000 + .DW 0x0000,0x0000 + .DW DIRBF,DPBLK0 + .DW CHK00,ALL00 + +; DISK PARAMETER HEADER FOR DISK 05 (Large ROM Disk) + .DW 0x0000,0x0000 + .DW 0x0000,0x0000 + .DW DIRBF,DPBLK5 + .DW CHK05,ALL05 + + +; DISK PARAMETER HEADER FOR DISK 02 (8MB disk Partition) + .DW 0x0000,0x0000 + .DW 0x0000,0x0000 + .DW DIRBF,DPBLK2 + .DW CHK02,ALL02 + +; DISK PARAMETER HEADER FOR DISK 03 (8MB disk Partition) + .DW 0x0000,0x0000 + .DW 0x0000,0x0000 + .DW DIRBF,DPBLK3 + .DW CHK03,ALL03 + +; DISK PARAMETER HEADER FOR DISK 04 (??? third disk partition ???) + .DW 0x0000,0x0000 + .DW 0x0000,0x0000 + .DW DIRBF,DPBLK4 + .DW CHK04,ALL04 + +DPBLK0: ;DISK PARAMETER BLOCK (RAMDISK 512K, 448K usable) +SPT_1: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK +BSH_1: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_1: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_1: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_1: .DW 223 ; BLOCKSIZE [2048] * NUMBER OF BLOCKS + 1 = DRIVE SIZE +DRM_1: .DW 255 ; NUMBER OF DIRECTORY ENTRIES +AL0_1: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_1: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_1: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_1: .DW 2 ; 2 TRACK RESERVED [FIRST 64K OF RAM] +; Note: changed to 2 tracks to skip over the 1st 64KB or RAM. + +DPBLK1: ;DISK PARAMETER BLOCK (ROMDISK 32KB WITH 16 2K TRACKS, 22K usable) +SPT_0: .DW 16 ; 16 SECTORS OF 128 BYTES PER 2K TRACK +BSH_0: .DB 3 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_0: .DB 7 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_0: .DB 0 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_0: .DW 31 ; BLOCKSIZE [1024] * NUMBER OF BLOCKS + 1 = DRIVE SIZE +DRM_0: .DW 31 ; NUMBER OF DIRECTORY ENTRIES +AL0_0: .DB 0b10000000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_0: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_0: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_0: .DW 5 ; FIRST 5 TRACKS TRACKS RESERVED (10K FOR SYSTEM) + ; SYSTEM IS ROM LOADER, CCP, BDOS, CBIOS, AND MONITOR + ; + ; IMPORTANT NOTE: TRACKS $00 - $04 OF 2K BYTES + ; EACH ARE MARKED WITH THE OFF_0 SET TO 5 AS + ; SYSTEM TRACKS. USABLE ROM DRIVE SPACE + ; STARTING AFTER THE FIFTH TRACK (IE, TRACK $05) + ; MOST LIKELY FIX TO THIS IS PLACING A DUMMY + ; FIRST 10K ROM CONTAINS THE ROM LOADER, MONITOR, + ; CCP, BDOS, BIOS, ETC (5 TRACKS * 2K EACH) + + +DPBLK2: ;DISK PARAMETER BLOCK (IDE HARD DISK 8MB) +SPT_2: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK +BSH_2: .DB 5 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_2: .DB 31 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_2: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_2: .DW 2039 ; BLOCKSIZE [4096] * NUMBER OF BLOCKS + 1 = DRIVE SIZE + ; HD PARTITION 2 IS 16128 SECTORS LONG + ; AT 512 BYTES EACH WHICH IS + ; 2016 BLOCKS AT 4096 BYTES A PIECE. +DRM_2: .DW 511 ; NUMBER OF DIRECTORY ENTRIES +AL0_2: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_2: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_2: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_2: .DW 1 ; 1 TRACK (32K) RESERVED FOR SYSTEM + +DPBLK3: ;DISK PARAMETER BLOCK (IDE HARD DISK 8MB) +SPT_3: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK +BSH_3: .DB 5 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_3: .DB 31 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_3: .DB 1 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_3: .DW 2039 ; BLOCKSIZE [4096] * NUMBER OF BLKS + 1 = DRIVE SIZE + ; HD PARTITION 3 IS 16128 SECTORS LONG + ; AT 512 BYTES EACH WHICH IS + ; 2016 BLOCKS AT 4096 BYTES A PIECE. +DRM_3: .DW 511 ; NUMBER OF DIRECTORY ENTRIES +AL0_3: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_3: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_3: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_3: .DW 1 ; 1 TRACK (32K) RESERVED FOR SYSTEM + +DPBLK4: ;DISK PARAMETER BLOCK (IDE HARD DISK 1024K) +SPT_4: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK +BSH_4: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_4: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_4: .DB 0 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_4: .DW 497 ; BLKSIZE [2048] * NUMBER OF BLKS + 1 = DRIVE SIZE + ; HD PARTITION 4 IS 4032 SECTORS LONG + ; AT 512 BYTES EACH WHICH IS + ; 1008 BLOCKS AT 2048 BYTES A PIECE. + ; NOT USING ALL OF THE AVAILABLE SECTORS SINCE THIS + ; DRIVE IS INTENDED TO EMULATE A ROM DRIVE AND COPIED + ; INTO A ROM IN THE FUTURE. +DRM_4: .DW 255 ; NUMBER OF DIRECTORY ENTRIES +AL0_4: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_4: .DB 0b00000000 ; DIRECTORY CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_4: .DW 0 ; SIZE OF DIRECTORY CHECK [0 IF NON REMOVEABLE] +OFF_4: .DW 1 ; 1 TRACK RESERVED [FIRST 32K OF PARTITION] + +; +DPBLK5: ;DISK PARAMETER BLOCK (ROMDISK 1MB) +SPT_5: .DW 256 ; 256 SECTORS OF 128 BYTES PER 32K TRACK +BSH_5: .DB 4 ; BLOCK SHIFT FACTOR (SIZE OF ALLOCATION BLOCK) +BLM_5: .DB 15 ; PART OF THE ALLOCATION BLOCK SIZE MATH +EXM_5: .DB 0 ; DEFINES SIZE OF EXTENT (DIRECTORY INFO) +DSM_5: .DW 495 ; BLKSIZE [2048] * NUMBER OF BLKS +1 =DRIVE SIZE +;DSM_5: .DW 511 ; BLKSIZE [2048] * NUMBER OF BLKS +1 =DRIVE SIZE +DRM_5: .DW 255 ; NUMBER OF DIRECTORY ENTRIES +AL0_5: .DB 0b11110000 ; BIT MAP OF SPACE ALLOCATED TO DIRECTORY +AL1_5: .DB 0b00000000 ; DIR CAN HAVE UP TO 16 BLOCKS ALLOCATED +CKS_5: .DW 0 ; SIZE OF DIR CHECK [0 IF NON REMOVEABLE] +OFF_5: .DW 1 ; 1 TRACK RESERVED [FIRST 32K OF ROM] + +; +; END OF FIXED TABLES +; +; INDIVIDUAL SUBROUTINES TO PERFORM EACH FUNCTION + +BOOT: ;SIMPLEST CASE IS TO JUST PERFORM PARAMETER INITIALIZATION + di ; disable interrupts +; IM 1 ; SET INTERRUPT MODE 1 +; .DB $ED,$56 ; Z80 "IM 1" INSTRUCTION + + ld a,#0x80 + +; out0 ACR +; .BYTE $ED,$39,ACR ; ensure that the ROM is switched out + + out (ACR),a + + ld a,#1 + ld (CDISK),a ; select disk 0 + + ld a,#DEFIOB + ld (IOBYTE),a + +; ei ; enable interrupts + + ld hl,#TXT_STARTUP_MSG + CALL PRTMSG + + JP GOCPM ;INITIALIZE AND GO TO CP/M + +; +WBOOT: ;SIMPLEST CASE IS TO READ THE DISK UNTIL ALL SECTORS LOADED + ; WITH A ROMDISK WE SELECT THE ROM AND THE CORRECT PAGE [0] + ; THEN COPY THE CP/M IMAGE (CCP, BDOS, BIOS, MONITOR) TO HIGH RAM + ; LOAD ADDRESS. + + DI ; DISABLE INTERRUPT + + ld SP,#0x0080 ; use space below buffer for stack + +; IM 1 ; SET INTERRUPT MODE 1 +; .DB $ED,$56 ; Z80 "IM 1" INSTRUCTION + + xor a,a + + ; CHEAP ZERO IN ACC +; mvi a,00h ; switch in the ROM +; out0 ACR +; .BYTE $ED,$39,ACR + + out (ACR),a + + xor a,a + +; out0 RMAP +; .BYTE $ED,$39,$F6 + + out (RMAP),a ; set the rom map + + ; Just reload CCP and BDOS + + ld hl,#ROMSTART_CPM ; where in rom cp/m is stored (1st byte) + ld de,#RAMTARG_CPM ; where in ram to move ccp+BDOS to + ld bc,#MOVSIZ_CPM + ldir + + ld a,#0x80 + out (ACR),a + +; EI ; ENABLE INTERRUPTS + +; +; END OF LOAD OPERATION, SET PARAMETERS AND GO TO CP/M +GOCPM: + ;CPU RESET HANDLER + ld a,#0xC3 ; C32 is a jump opcode + ld (0x0000),a + ld hl,#WBOOTE ; address of warm boot + ld (0x0001),hl ; set addr field for jmp at 0 + + ld (0x0005),a ; for jump to bdos + ld hl,#BDOS + ld (0x0006),hl + + ld bc,#0x0080 ; default DMA address + CALL SETDMA + + ld a,(CDISK) ; get current disk number + ld c,a ; send to the ccp + JP CCP ;GO TO CP/M FOR FURTHER PROCESSING + + +; +;---------------------------------------------------------------------------------------------------------------------- +; N8VEM Home computer I/O handlers +; +; This implementation uses IOBYTE and allocates devices as follows: +; +; TTY - Driver for the Z180 ASCI port 0 +; CRT - Driver for the +; UC1 - Driver for the +; xxx - Driver for the +; +; Logical device drivers - these pass control to the physical +; device drivers depending on the value of the IOBYTE +; + +CONST: ;CONSOLE STATUS, RETURN 0FFH IF CHARACTER READY, 00H IF NOT + + ld a,(IOBYTE) + and a,#3 + cp #0 + jp z,TTYISTS + + cp #1 + jp z,CRTISTS + + jp NULLSTS + + + + +CONIN: ;CONSOLE CHARACTER INTO REGISTER A + ld a,(IOBYTE) + and a,#3 + cp #0 + jp z,TTYIN + cp #1 + jp z,CRTIN + jp NULLIN + + +CONOUT: ;CONSOLE CHARACTER OUTPUT FROM REGISTER C + ld a,(IOBYTE) + and a,#3 ; isolate console bits + cp #0 + jp z,TTYOUT + cp #1 + jp z,CRTOUT + jp NULLOUT + +LIST: ;LIST CHARACTER FROM REGISTER C + jp NULLOUT + + + +LISTST: ;RETURN LIST STATUS (0 IF NOT READY, 1 IF READY) + jp NULLSTS + + ; +PUNCH: ;PUNCH CHARACTER FROM REGISTER C + jp NULLOUT + +; +READER: ;READ CHARACTER INTO REGISTER A FROM READER DEVICE + + jp NULLIN ; currently not used + + + +;---------------------------------------------------------------------------------------------------------------------------------------- +; +; Here are the physical io device drivers +; +; Null driver - this is a dummy driver for the NULL device + +NULLIN: + ld a,#0x1a + ret + +NULLOUT: + ld a,c + ret + +NULLSTS: + ld a,#1 + ret + +; +;--------------------------------------------------------------------------------------------------------------------------------------------- +; +; TTY Driver (programmed i/o) this is the driver for the Home Computer console port +; +TTYIN: + CALL TTYISTS; IS A CHAR READY TO BE READ FROM UART? + cp #0 + jp z,TTYIN + +; IN0 A,(RDR0) + +;dwg; .BYTE $ED,$38,RDR0 + .byte 0xED,0x38,RDR0 + + ret + +TTYOUT: + call TTYOSTS + and a,a + jp z,TTYOUT ; if not repeat + + ld a,c ; get to accum + +; OUT0 (TDR0),A + .byte 0xed,0x39,TDR0 + + ret + +TTYISTS: +; IN0 A,(STAT0) +;dwg; .BYTE $ED,$38,STAT0 +;;dwg;; in0 a,(STAT0) + .byte 0xed,0x38,STAT0 + + and a,#0x80 + ret z ; is there a char ready? 0=no 1=yes + ld a,#0xff + ret ; NO, LEAVE $00 IN A AND RETURN + +TTYOSTS: +; IN0 A,(STAT0) +;dwg; .BYTE $ED,$38,STAT0 +;;dwg;; in0 a,(STAT0) + .byte 0xed,0x38,STAT0 + + and a,#2 + ret z + ld a,#0xff + + ret ; NO, LEAVE $00 IN A AND RETURN +;--------------------------------------------------------------------------------------------------------------------------------------------- +; CRT Driver - This is the driver for the Prop VDU +; + +CRTIN: + jp NULLIN + +CRTOUT: + jp NULLOUT + +CRTISTS: + jp NULLSTS + +CRTOSTS: + jp NULLSTS + + +;--------------------------------------------------------------------------------------------------------------------------------------------- + ;; +; I/O DRIVERS FOR THE DISK FOLLOW +; FOR NOW, WE WILL SIMPLY STORE THE PARAMETERS AWAY FOR USE +; IN THE READ AND WRITE SUBROUTINES +; + +; +; SELECT DISK GIVEN BY REGISTER C +; +SELDSK: + + ld hl,#0 ; error return code + + ld a,c + + cp a,#4 ; must be between 0 and 4 + ret nc ; no carry if 4,5,6,7 + ld a,c + ld (DISKNO),a ; save valid disk number + +; +; DISK NUMBER IS IN THE PROPER RANGE +; COMPUTE PROPER DISK PARAMETER HEADER ADDRESS + + ld l,a ; l = disk num 0,1,2,3,4 + ld h,#0 ; high order + add hl,hl ; * 2 + add hl,hl ; * 4 + add hl,hl ; * 8 + add hl,hl ; * 16 (size of each header) + ld de,#DPBASE + add hl,de ; hl = .DPBASE(DISKNO*16) + RET +; +HOME: ;MOVE TO THE TRACK 00 POSITION OF CURRENT DRIVE + ; TRANSLATE THIS CALL INTO A SETTRK CALL WITH PARAMETER 00 + + ld bc,#0 ; select track zero + +; CALL SETTRK +; RET ;WE WILL MOVE TO 00 ON FIRST READ/WRITE + ; FALL THROUGH TO SETTRK TO STORE VALUE + +SETTRK: ;SET TRACK GIVEN BY REGISTER BC + ld h,b + ld l,c + ld (TRACK),hl + RET +; +SETSEC: ;SET SECTOR GIVEN BY REGISTER BC + ld h,b + ld l,c + ld (SECTOR),hl + RET +; +; TRANSLATE THE SECTOR GIVEN BY BC USING THE +; TRANSLATE TABLE GIVEN BY DE +; ONLY USED FOR FLOPPIES! FOR ROMDISK/RAMDISK IT'S 1:1 +; DO THE NEXT ROUTINE IS A NULL (RETURNS THE SAME) +SECTRN: + ld h,b + ld l,c + RET +; + +SETDMA: ;SET DMA ADDRESS GIVEN BY REGISTERS B AND C + ld l,c + ld h,b + ld (DMAAD),hl + RET + +; READ DISK +; USES DE,DL, BC, ACC FLAGS +; Z80 COULD USE BLOCK MOVE [LDIR] BUT WRITTEN IN 8080 +READ: +; DI ; DISABLE INTERRUPTS + + ld a,(DISKNO) + ; FIND OUT WHICH DRIVE IS BEING REQUESTED + ; ARE WE READING RAM OR ROM? + cp #0 + jp z,READ_RAM_DISK + + cp #1 + jp z,READ_ROM_DISK + + cp #2 + jp z,READ_HDPART1 + + cp #3 + jp z,READ_HDPART2 ; READ FROM 8 MB IDE HD, PARTITION 2 + + cp #4 + jp z,READ_HDPART3 ; READ FROM 1 MB IDE HD, PARTITION 4 + + cp #5 + jp z,READ_HDPART4 ; READ FROM 1 MB IDE HD, PARTITION 5 + + ld a,#1 ; BDOS WILL ALSO PRINT ITS OWN ERROR MESSAGE + ret + + +; +; WRITE DISK +; +WRITE: +; DI ; DISABLE INTERRUPTS + + ld a,(DISKNO) ; get drive + +; ORA A ; SET FLAGS + + cp #0 ; find out which drive is being requested + + jp z,WRITE_RAM_DISK ; write to 448K ram disk + + cp #1 + jp z,RDONLY ; jump to read only routine + + ; READ ONLY, FROM 22K EEPROM DISK, ERROR ON WRITE + cp #2 + jp z,WRITE_HDPART1 ; write to 8MB IDE HD, Part 2 + + cp #3 + jp z,WRITE_HDPART2 ; write to 8MB IDE HD, Part 3 + + cp #4 + jp z,WRITE_HDPART3 ; write to 1MB IDE HD, Part 4 + + cp #5 + jp z,WRITE_HDPART4 ; write to 1MB IDE HD Part 5 + + + ; IF NONE OF THE OTHER DISKS, IT MUST BE + ; THE RAM DISK, SO FALL THROUGH + + ld a,#1 ; send bad sector error back + ; BDOS WILL ALSO PRINT ITS OWN ERROR MESSAGE + ret + + + +RDONLY: +; +; HANDLE WRITE TO READ ONLY +; +; SENDS A MESSAGE TO TERMINAL THAT ROM DRIVE IS NOT WRITEABLE +; DOES A PAUSE THEN RETURNS TO CPM WITH ERROR FLAGGED. THIS IS +; DONE TO ALLOW A POSSIBLE GRACEFUL EXIT (SOME APPS MAY PUKE). +; + + ; CODE TBD, PRINT A HEY WRONG DISK AND PAUSE 5 SEC AND + ; CONTINUE. + + ld hl,#TXT_RO_ERROR ; set hp --> error msg + CALL PRTMSG ; PRINT ERROR MESSAGE + + ld a,#1 ; send bad sector error back + ; BDOS WILL ALSO PRINT ITS OWN ERROR MESSAGE + ; ADD 5 SECOND PAUSE ROUTINE HERE + ret + +; +;-------------------------------------------------------------------------------------------------------------- +; +; DISK DRIVERS... +; +; DRIVER NEED TO DO SEVERAL THINGS FOR ROM AND RAM DISKS. +; - INTERRUPTS ARE NOT ALLOWED DURING LOW RAM/ROM ACCESS (DISABLE!) +; -TRANSLATE TRACK AND SECTOR INTO A POINTER TO WHERE THE 128 BYTE +; SECTOR BEGINS IN THE RAM/ROM +; -TRANSLATE THE DRIVE INTO A RAM/ROM SELECT, COMBINE WITH TRACK ADDRESS +; AND SEND TO THE MAP PORT. +; -COPY 128 BYTE FROM OR TO THE ROM/RAMDISK AND MEM POINTED TO BY DMA +; ADDRESS PREVIOUSLY STORED. +; -RESTORE MAP PORT TO PRIOR CONDITION BEFOR READ/WRITE +; +; - FIRST TRICK IS THAT WE MADE SECTORS 256 AS 256*128=32768. SO WE COPY +; THE LOW SECTOR ADDRESS TO THE LOW BYTE OF THE HL REGISTER AND THEN +; MULTIPLY BY 128. THIS RESULTS IN THE STARTING ADDR IN THE RAM OR ROM +; (0000 -> 7F80H) 32K PAGE. +; +; - TRICK TWO IS THE TRACK ADDRESS EQUALS THE 32K PAGE ADDRESS AND IS A +; DIRECT SELECT THAT CAN BE COPIED TO THE MAP PORT D0 THROUGH D5. D7 +; SELECTS THE DRIVE (ROM OR RAM). +; THAT MEANS THE LOW BYTE OF TRACK CONTAINS THE D0-D5 VALUE AND +; DISKNO HAS THE DRIVE SELECTED. WE FIRST COPY DISKNO TO ACC +; AND RIGHTSHIFT IT TO PLACE THAT IN BIT7, WE THEN ADD LOW BYTE OF +; TRACK TO ACC AND THEN SEND THAT TO THE MAP PORT. +; +; NOTE 1: A WRITE TO ROM SHOULD BE FLAGGED AS AN ERROR. +; NOTE 2: RAM MUST START AS A "FORMATTED DISK" IF BATTERY BACKED UP +; IT'S A DO ONCE AT COLD COLD START. IF NOT BATTERY BACKED UP +; IT WILL HAVE TO BE DONE EVERY TIME THE SYSTEM IS POWERED. +; FORMATTING THE RAM IS SIMPLE AS CLEARING THE DIRECTORY AREA +; TO A VALUE OF E5H (THE FIRST 8K OF TRACK 1 OR THE RAMDISK). +; IT COULD BE DONE AS A SIMPLE UTILITY PROGRAM STORED IN ROMDISK +; OR ANYTIME COLBOOT IS CALLED(LESS DESIREABLE). +; +; -WE NOW CAN COPY TO/FROM AS CORRECT FOR THE DEVICE 128 BYTES (SECTOR) +; TO OR FROM THE DMA ADDRESS. ALMOST! SINCE ROM OR RAM IS BEING PAGED +; WE HAVE TO COPY ANYTHING DESTINED FOR BELOW 8000H TO TEMP BUFFER +; THEN HANDLE THE PAGING. +; +; +; - LAST STEP IS TO RESTORE THE MAP PORT TO POINT TO THE RAM (TRACK 0) +; SO THE CP/M MEMORY MAP IS ALL RAM AGAIN AND NOT POINTING INTO THE +; DATA AREAS OR THE "DISK". +; SINCE THE RAM 0TH PAGE IS NOMINALLY THE LOW 32K OF RAM IN THE i +; SYSTEM WE CAN SEND A SIMPLE MVI A,80H ; OUT MPCL_ROM; MVI A,00H ; +; OUT MPCL_RAM. +; +; - THE READ OR WRITE OPERATION IS DONE. +; +; +; +; +; +; + + ; ACCESS ALGORITHM (ONLY APPLICABLE TO 32K ROM PART!) +READ_RAM_DISK: + DI ; IF RAM, PROCEED WITH NORMAL TRACK/SECTOR READ + CALL SECPAGE ; SETUP FOR READ OF RAM OR ROM DISK + + ld hl,(TRACK) ; multiply by 8 (4k segs) + +;dwg; dad h ; *2 + add hl,hl + +;dwg; dad h ; *4 + add hl,hl + +;dwg; dad h ; *8 + add hl,hl + +;dwg; MOV A,L ; get track in L + ld a,l + +; out0 BBR ; select RAM bank + +;dwg; .BYTE $ED,$39,BBR +;;dwg;; out0 BBR + .byte 0xed,0x39,BBR + + ld hl,#TMPBUF ; load hl with temp buf addr + ld d,h ; get it into de + ld e,l + ld hl,(SECST) ; rom/ram addr + ld bc,#128 + ldir + +; +; NOW WITH THE ROM/RAM DATA IN THE BUFFER WE CAN NOW MOVE IT TO THE +; DMA ADDRESS (IN RAM) +; + + ld a,#0 ; return to system bank + +; out0 BBR ; select RAM bank + +;dwg; .BYTE $ED,$39,BBR +;;dwg;; out0 BBR + .db 0xed,0x39,BBR + +; CALL RPAGE ; SET PAGE TO CP/M RAM + +; EI ; RE-ENABLE INTERRUPTS + + ld hl,(DMAAD) ; load hl with dma addr + ld e,l + ld d,h ; get it into de + ld hl,#TMPBUF ; get rom/ram addr + ld bc,#128 + ldir + + ld a,#0 + RET + +READ_ROM_DISK: + DI ; IF RAM, PROCEED WITH NORMAL TRACK/SECTOR READ + CALL SECPAGE ; SETUP FOR READ OF RAM OR ROM DISK + CALL PAGERB ; SET PAGER WITH DRIVE AND TRACK + + ld hl,#TMPBUF ; load hl with temp buf address + ld d,h + ld e,l ; get it into de + ld hl,(SECST) ; rom/ram address + ld bc,#128 + ldir + +; +; NOW WITH THE ROM/RAM DATA IN THE BUFFER WE CAN NOW MOVE IT TO THE +; DMA ADDRESS (IN RAM) +; + CALL RPAGE ; SET PAGE TO CP/M RAM +; EI ; RE-ENABLE INTERRUPTS + + ld hl,(DMAAD) ; load hl with dma address + ld e,l + ld d,h + ld hl,#TMPBUF ; get rom/ram address + ld bc,#128 + ldir + + ld a,#0 + ret + + +WRITE_RAM_DISK: + + ld hl,#TMPBUF ; load hl with temp buf address + ld d,h + ld e,l + ld hl,(DMAAD) + ld bc,#128 + ldir + +; +; NOW THAT DATA IS IN THE TEMP BUF WE SET TO RAM PAGE +; FOR WRITE. +; + DI + CALL SECPAGE ; GET RAM PAGE WRITE ADDRESS + + ld hl,(TRACK) + + add hl,hl ; *2 multiply by 8 (4k segs) + add hl,hl ; *4 + add hl,hl ; *8 + ld a,l ; get track in l + +; out0 BBR ; select RAM bank +;dwg; .BYTE $ED,$39,BBR +;;dwg;; out0 BBR + .db 0xed,0x39,BBR + + ld hl,(SECST) ; load hl with dma addr (where to write to) + ld d,h ; get it into de + ld e,l + ld hl,#TMPBUF ; get temp buffer address + ld bc,#128 + ldir + + ld a,#0 ; return to system bank + +; out0 BBR ; select RAM bank +;dwg; .BYTE $ED,$39,BBR +;;dwg;; out0 BBR + .db 0xed,0x39,BBR + +; EI + ; RE-ENABLE INTERRUPTS + ld a,#0 + ret + +;------------------------------------------------------------------- + +; Logical disk drivers + +READ_HDPART1: + + ld hl,#1 ; init LBA offset sector lo word + ld (LBA_OFFSET_LO),hl + ld hl,#0 ; init LBA offset sector hi word + ld (LBA_OFFSET_HI),hl + JP READ_HDPARTX + +READ_HDPART2: + ld hl,#0x4001 ; init LBA offset sector lo word + ld (LBA_OFFSET_LO),hl + ld hl,#0 ; init LBA offset sector hi word + ld (LBA_OFFSET_HI),hl + JP READ_HDPARTX + +READ_HDPART3: +READ_HDPART4: + ret + + +READ_HDPARTX: + + ; BDOS TRACK PARAMETER (16 BITS) + ; BDOS SECTOR PARAMETER (16 BITS) + + ld hl,(TRACK) ; load track number (word) + ld b,l ; save lower 8 bits (tracks 0-255) + ld hl,(SECTOR) ; load sector number (word) + ld h,b ; hl is 8 bit track in h, 8 bit sector in l + CALL CONVERT_IDE_SECTOR_CPM ; COMPUTE WHERE CP/M SECTOR IS ON THE + ; IDE PARTITION + + ; MAP COMPUTED IDE HD SECTOR TO LBA REGISTERS + + ; LBA REGISTERS STORE 28 BIT VALUE OF IDE HD SECTOR ADDRESS + + ld a,(LBA_TARGET_LO) ; load LBA reg 0 with sector addr to read + ld (IDE_LBA0),a + ld a,(LBA_TARGET_LO+1) ; load LBA reg 1 with sector addr t read + ld (IDE_LBA1),a + ld a,(LBA_TARGET_HI) ; load LBA reg 2 with sector addr to read + ld (IDE_LBA2),a + ld a,(LBA_TARGET_HI+1) ; load LBA reg 3 with sector addr to read + and a,#0b00001111 ; only lower 4 bits are valid + add a,#0b11100000 ; enable LBA bits 5:7=111 in IDE_LBA3 + ld (IDE_LBA3),a + CALL IDE_READ_SECTOR ; READ THE IDE HARD DISK SECTOR + +; NEED TO ADD ERROR CHECKING HERE, CARRY FLAG IS SET IF IDE_READ_SECTOR SUCCESSFUL! + + ; COMPUTE STARTING ADDRESS OF CP/M SECTOR IN READ IDE HD SECTOR BUFFER + + ld hl,#SECTOR_BUFFER ; load hl with sector buffer address + + ld a,(SECTOR_INDEX) ; get the sector index (off in buff) + + RRC a ; MOVE BIT 0 TO BIT 7 + RRC a ; DO AGAIN - IN EFFECT MULTIPLY BY 64 + + ld d,#0 ; put result as 16 value in de, upper byte in d is 0 + + ld e,a ; put addr offset in e + + add hl,de ; multiply by 2, total mult is x 128 + + add hl,de ; cp/m sect starting addr in IDE HD sector buffer + + ; COPY CP/M SECTOR TO BDOS DMA ADDRESS BUFFER + + ld D,H ; TRANSFER HL REGISTERS TO DE + ld E,L + ld hl,(DMAAD) ; LOAD HL WITH DMA ADDRESS + ex de,hl + ld bc,#128 + ldir + +; EI ; RE-ENABLE INTERRUPTS + + ld a,#0 ; return err code read successful a=0 + ret + + + + +;------------------------------------------------------------------- + + +WRITE_HDPART1: + +; DI ; DISABLE INTERRUPTS + + ld hl,#1 ; init LBA offset sector lo word + ld (LBA_OFFSET_LO),hl + ld hl,#0 ; init LBA offset sector hi word + ld (LBA_OFFSET_HI),hl + JP WRITE_HDPARTX + + +WRITE_HDPART2: + +; DI ; DISABLE INTERRUPTS + + ld hl,#0x4001 ; init LBA offset sector lo word + ld (LBA_OFFSET_LO),hl + ld hl,#0 ; init LBA offset sector hi word + ld (LBA_OFFSET_HI),hl + JP WRITE_HDPARTX + +;------------------------------------------------------------------- + +WRITE_HDPART3: ; STUB +WRITE_HDPART4: ; STUB + RET + +;------------------------------------------------------------------- + + +WRITE_HDPARTX: + + ; BDOS TRACK PARAMETER (16 BITS) + ; BDOS SECTOR PARAMETER (16 BITS) + + ld hl,(TRACK) ; load track # (word) + ld b,l ; save lower 8 bits (tracks 0-255) + ld hl,(SECTOR) ; load sector # (word) + ld h,b ; hl is 8 bit track in h, 8 bit sector in l + + CALL CONVERT_IDE_SECTOR_CPM ; COMPUTE WHERE THE CP/M SECT IS ON THE + ; IDE PARTITION + + ; MAP COMPUTED IDE HD SECTOR TO LBA REGISTERS + ; LBA REGISTERS STORE 28 BIT VALUE OF IDE HD SECTOR ADDRESS + + ld a,(LBA_TARGET_LO) ; load LBA reg 0 with sect addr to read + ld (IDE_LBA0),a + ld a,(LBA_TARGET_LO+1) ; load LBA reg 1 with sect addr to read + ld (IDE_LBA1),a + ld a,(LBA_TARGET_HI) ; load LBA reg 2 with sect addr to read + ld (IDE_LBA2),a + ld a,(LBA_TARGET_HI+1) ; load LBA reg 3 with sect addr to read + and a,#0b00001111 ; only lower four bits are valid + add a,#0b11100000 ; enable LBA bits 5:7=111 in IDE_LBA3 + ld (IDE_LBA3),a + CALL IDE_READ_SECTOR ; READ THE IDE HARD DISK SECTOR + + ; NEED TO ADD ERROR CHECKING HERE, + ; CARRY FLAG IS SET IF IDE_READ_SECTOR SUCCESSFUL! + + ; COMPUTE STARTING ADDRESS OF CP/M SECTOR IN READ IDE HD SECTOR BUFFER + + ld hl,#SECTOR_BUFFER ; load hl with sector buffer address + + ld a,(SECTOR_INDEX) ; get the sector index (off in buffer) + + RRC a ; MOVE BIT 0 TO BIT 7 + RRC a ; DO AGAIN - IN EFFECT MULTIPLY BY 64 + + ld d,#0 ; put result as 16 bit value in de + ; UPPER BYTE IN D IS $00 + ld e,a ; put address offset in e + + add hl,de ; cp/m starting addr in buffer + + add hl,de ; *2, total mult is x128 + + ; KEEP CP/M SECTOR ADDRESS FOR LATER USE + ; COPY CP/M SECTOR FROM BDOS DMA ADDRESS BUFFER + ld (SECST),hl + + ld hl,(SECST) ; setup destination + ex de,hl ; swap for next LHLD + ld hl,(DMAAD) ; setup source + ld bc,#128 ; byte count + ldir + + ; IDE HD SECTOR IS NOW UPDATED + ; WITH CURRENT CP/M SECTOR DATA SO WRITE TO DISK + + CALL IDE_WRITE_SECTOR ; WRITE THE UPDATED IDE HARD DISK SECTOR + + ; NEED TO ADD ERROR CHECKING HERE, + ; CARRY FLAG IS SET IF IDE_WRITE_SECTOR SUCCESSFUL! + +; EI ; RE-ENABLE INTERRUPTS + + ld a,#0 ; return error code write successful a=0 + ret + +;------------------------------------------------------------------- + + +PRTMSG: + ld a,(hl) ; get char into A + cp a,#END ; test for end byte + jp z,PRTMSG1 ; jump if end byte is found + ld c,a ; put char to print in C for conout + CALL CONOUT ; SEND CHARACTER TO CONSOLE FROM REG C + inc hl ; inc ptr to next char + JP PRTMSG ; TRANSMIT LOOP +PRTMSG1: + ret + + +; +; UTILITY ROUTINE FOR SECTOR TO PAGE ADDRESS +; USES HL AND CARRY +; +SECPAGE: + ld hl,(SECTOR) + add hl,hl ; * 2 + add hl,hl ; * 4 + add hl,hl ; * 8 + add hl,hl ; * 16 + add hl,hl ; * 32 + add hl,hl ; * 64 + add hl,hl ; * 128 + ld (SECST),hl ; save sector starting address + ret + +; +; PAGER BYTE CREATION +; ASSEMBLES DRIVE AND TRACK AND SENDS IT TO PAGER PORT +; +PAGERB: + ld hl,(TRACK) + ld a,l ; or l with acc to combine track and drive +; out0 ACR+2 + .db 0xed,0x39,ACR+2 ; rom latch + ld a,#0 ; switch in the rom +; out0 ACR + .db 0xed,0x39,ACR + ld (PAGER),a ; save copy (just because) + ld (DB_PAGER),a ; save another copy for debug + RET + +; +; RESET PAGER BACK TO RAM. +; +RPAGE: + + ld a,#0x80 ; deselect rom page +; out0 ACR + .db 0xed,0x39,ACR + + ld a,#0 ; set to RAM track 0 +;dwg; STA PAGER ; SAVE COPY OF PAGER BYTE + ld (PAGER),a + + RET + + +CONVERT_IDE_SECTOR_CPM: + + ; COMPUTES WHERE THE CP/M SECTOR IS IN THE IDE PARTITION + ; IDE HD SECTORS ARE 512 BYTES EACH, CP/M SECTORS ARE 128 BYTES EACH + ; MAXIMUM SIZE OF CP/M DISK IS 8 MB = 65536 (16 BITS) X 128 BYTES PER SECTOR + ; IDE HD PARTITION CAN HAVE AT MOST 16384 IDE SECTORS -> 65536 CP/M SECTORS + ; EACH IDE HD SECTOR CONTAINS 4 ADJACENT CP/M SECTORS + ; + ; + ; INPUT: + ; IDE HD PARTITION STARTING SECTOR NUMBER (FROM PARTITION TABLE) + ; - LOWER 16 BITS STORED IN LBA_OFFSET_LO + ; - UPPER 16 BITS STORED IN LBA_OFFSET_HI + ; PARTITION OFFSET IN HL (16 BITS) + ; - A UNIQUELY COMPUTED FUNCTION BASED ON GEOMETRY OF DISKS NUMBER OF + ; CP/M TRACKS AND SECTORS SPECIFIED IN DPB + ; + ; + ; OUTPUT: + ; IDE TARGET SECTOR (SENT TO IDE HD CONTROLLER FOR READ OPERATION) + ; - LOWER 16 BITS STORED IN LBA_TARGET_LO + ; - UPPER 16 BITS STORED IN LBA_TARGET_HI + ; CP/M TO IDE HD SECTOR MAPPING PARAMETER STORED IN SECTOR_INDEX + ; - 8 BIT VALUE WITH 4 LEGAL STATES (00, 01, 02, 04) WHICH IS + ; TO BE USED TO COMPUTE STARTING ADDRESS OF 128 BYTE CP/M SECTOR ONCE + ; 512 BYTE IDE HD SECTOR READ INTO MEMORY BUFFER + ; + + ; ROTATE WITH CARRY 16 BIT TRACK,SECTOR VALUE IN HL TO GET 14 BIT IDE HD + ; TARGET SECTOR IN PARTITION + ; KEEP LAST TWO BITS IN B FOR IDE HD SECTOR TO CP/M SECTOR TRANSLATION + + ; COMPUTE SECTOR_INDEX + +;;dwg;; What is the point of this? the next inst sets A anyway?? + xor a,a ; zero accumulator + + ld a,l ; store the last 2 bits of l in b + and a,#0b00000011 + ld b,a + + ld (SECTOR_INDEX),a ; locates the 128 cpm sector in buffer + + ; COMPUTE WHICH IDE HD SECTOR TO READ TO WITHIN 4 CP/M SECTORS + ; SHIFTS 16 BIT PARTITION OFFSET TO THE RIGHT 2 BITS AND ADDS RESULT TO + ; IDE HD PARTITION STARTING SECTOR + + ; SHIFT PARTITION OFFSET RIGHT 1 BIT + + scf ; set the carry flag, so we can clear it + ccf ; Complement Carry Flag + + ld a,h ; 16 bit rotate hl with carry + rra + ld h,a ; rotate HL right 1 bit (divide by 2) + ld a,l + rra + ld l,a + + ; SHIFT PARTITION OFFSET RIGHT 1 BIT + + scf + ccf ; CLEAR CARRY FLAG + + ld a,h ; 16 bit rotate HL with carry + rra + ld H,A ; ROTATE HL RIGHT 1 BIT (DIVIDE BY 2) + ld A,L + rra + ld L,A + + ; ADD RESULTING 14 BIT VALUE TO IDE HD PARTITION STARTING SECTOR + ; STORE RESULT IN IDE HD TARGET SECTOR PARAMETER + + ld a,(LBA_OFFSET_LO) ; 16 bit add of LBA_OFFSET_LO with hl + ADD L + ld (LBA_TARGET_LO),a + ld a,(LBA_OFFSET_LO+1) + adc a,h + ld (LBA_TARGET_LO+1),a ; store overflow bit in carry + ld hl,#0 + ld a,(LBA_OFFSET_HI) ; 16 bit add w/carry of LBA_OFFSET_HI w/ + adc a,l + ld (LBA_TARGET_HI),a + ld a,(LBA_OFFSET_HI+1) + adc a,h + ld (LBA_TARGET_HI+1),a + RET + + + +;------------------------------------------------------------------------------------ +; Parallel port IDE driver +; +; +; ----------------------------------------------------------------------------- + + ;read a sector, specified by the 4 bytes in "lba", + ;Return, acc is zero on success, non-zero for an error +IDE_READ_SECTOR: + call ide_wait_not_busy ;make sure drive is ready + call wr_lba ;tell it which sector we want + + ld a,#ide_command ; select IDE reg + ld c,#ide_cmd_read + call ide_write ;ask the drive to read it + call ide_wait_drq ;wait until it's got the data +; bit 0,a +; ani 1 +; jnz get_err + + ld hl,#SECTOR_BUFFER + call read_data ;grab the data + ld a,#0 ; ? set successful return code ? + + ret + + +;----------------------------------------------------------------------------- + + + ;write a sector, specified by the 4 bytes in "lba", + ;whatever is in the buffer gets written to the drive! + ;Return, acc is zero on success, non-zero for an error +IDE_WRITE_SECTOR: + call ide_wait_not_busy ;make sure drive is ready + call wr_lba ;tell it which sector we want + + ld a,#ide_command + ld c,#ide_cmd_write + call ide_write ;tell drive to write a sector + call ide_wait_drq ;wait unit it wants the data + +; bit 0,a ; check for error returned +; ani 1 +; jnz get_err + + ld hl,#SECTOR_BUFFER + call write_data ;give the data to the drive + call ide_wait_not_busy ;wait until the write is complete + +; bit 0,a +; ani 1 +; jnz get_err + +; ld a,#0 ; SHOULD THIS BE HERE (Doug's idea) + ret + + +;----------------------------------------------------------------------------- + +;--------ide_hard_reset--------------------------------------------------------------- + ;do a hard reset on the drive, by pulsing its reset pin. + ;this should usually be followed with a call to "ide_init". +;------------------------------------------------------------------------------------------- +ide_hard_reset: + call set_ppi_rd + ld a,#ide_rst_line + out (IDECTL),a ; assert rst line on IDE interface + ld bc,#0 +rst_dly: + dec b + jp nz,rst_dly + ld a,#0 ; this could be XOR A,A (shorter) + out (IDECTL),a ; deassert RST line on IDE interface + ret + +;------------------------------------------------------------------------------ +; IDE INTERNAL SUBROUTINES +;------------------------------------------------------------------------------ + + + +;---------------------------------------------------------------------------- + ;when an error occurs, we get bit 0 of A set from a call to ide_drq + ;or ide_wait_not_busy (which read the drive's status register). If + ;that error bit is set, we should jump here to read the drive's + ;explaination of the error, to be returned to the user. If for + ;some reason the error code is zero (shouldn't happen), we'll + ;return 255, so that the main program can always depend on a + ;return of zero to indicate success. +get_err: + ld a,#ide_err + call ide_read + ld a,c + jp z,gerr2 + ret +gerr2: + ld a,#255 + ret + +;----------------------------------------------------------------------------- + +ide_wait_not_busy: + ld a,#ide_status ; wait for RDY bit to be set + call ide_read + ld a,c + and a,#0x80 ; isolate busy bit + jp nz,ide_wait_not_busy + ret + + +ide_wait_ready: + ld a,#ide_status ; wait for RDY bit to be set + call ide_read + ld a,c + and a,#0b11000000 ; mask off busy and ready bits + xor a,#0b01000000 ; we want Busy(7) to be 0 and ready(6) to be 1 + jp nz,ide_wait_ready + ret + + ;Wait for the drive to be ready to transfer data. + ;Returns the drive's status in Acc +ide_wait_drq: + ld a,#ide_status ; waut for DRQ bit to be set + call ide_read + ld a,c + and a,#0b10001000 ; mask off busy(7) and DRQ(3) + xor a,#0b00001000 ; we want busy(7) to be 0 and DRQ (3) to be 1 + jp nz,ide_wait_drq + ret + + + +;------------------------------------------------------------------------------ + + ;Read a block of 512 bytes (one sector) from the drive + ;and store it in memory @ HL +read_data: + ld b,#0 +rdblk2: + push bc + push hl + ld a,#ide_data + call ide_read ; read form data port + pop hl + ld (hl),c + inc hl + ld (hl),b + inc hl + pop bc + dec b + jp nz,rdblk2 + ret + +;----------------------------------------------------------------------------- + + ;Write a block of 512 bytes (at HL) to the drive +write_data: + ld b,#0 +wrblk2: + push bc + ld c,(hl) ; lsb + inc hl + ld b,(hl) ; msb + inc hl + push hl + ld a,#ide_data + call ide_write + pop hl + pop bc + dec b + jp nz,wrblk2 + ret + + +;----------------------------------------------------------------------------- + + ;write the logical block address to the drive's registers +wr_lba: + ld a,(IDE_LBA0+3) ; MSB + and a,#0x0f + or a,#0xe0 + ld c,a + ld a,#ide_head + call ide_write + ld a,(IDE_LBA0+2) + ld c,a + ld a,#ide_cyl_msb + call ide_write + ld a,(IDE_LBA0+1) + ld c,a + ld a,#ide_cyl_lsb + call ide_write + ld a,(IDE_LBA0) ; LSB + ld c,a + ld a,#ide_sector + call ide_write + ld c,#1 + ld a,#ide_sec_cnt + call ide_write + + ret + +;------------------------------------------------------------------------------- + +; Low Level I/O to the drive. These are the routines that talk +; directly to the drive, via the 8255 chip. Normally a main +; program would not call to these. + + ;Do a read bus cycle to the drive, using the 8255. + ;input A = ide regsiter address + ;output C = lower byte read from ide drive + ;output B = upper byte read from ide drive + +ide_read: + push af ; save register value + call set_ppi_rd ; setup for a read cycle + pop af ; restore register value + out (IDECTL),a ;drive address onto control lines + or a,#ide_rd_line ; assert RD pin + out (IDECTL),a + push af ; save register value + in a,(IDELSB) ; read lower byte + ld c,a ; save in c reg + in a,(IDEMSB) ; read upper byte + ld b,a ; save in reg b + pop af ; restore reg value + xor a,#ide_rd_line ; deassert RD signal + out (IDECTL),a + ld a,#0 ;; DWG SAYS couln't this be a 1 byter? + out (IDECTL),a ;deassert all control pins + ret + + ;Do a write bus cycle to the drive, via the 8255 + ;input A = ide register address + ;input register C = lsb to write + ;input register B = msb to write + ; + + +ide_write: + push af ; save IDE reg valure + call set_ppi_wr ; setup for a write cycle + ld a,c ; get value to be written + out (IDELSB),a + ld a,b ; get value to be written + out (IDEMSB),a + pop af ; restore saved IDE reg + out (IDECTL),a ; drive address onto control lines + or a,#ide_wr_line ; assert write pin + out (IDECTL),a + xor a,#ide_wr_line ; deasser write pin + out (IDECTL),a ;drive address onto control lines + ld a,#0 ;; DWG SAYS couldn't this be 1 byter? + out (IDECTL),a ; release bus signals + ret + + +;----------------------------------------------------------------------------------- +; ppi setup routine to configure the appropriate PPI mode +; +;------------------------------------------------------------------------------------ + +set_ppi_rd: + ld a,#rd_ide_8255 + out (PIO1CONT),a ;config 8255 chip, read mode + ret + +set_ppi_wr: + ld a,#wr_ide_8255 + out (PIO1CONT),a ;config 8255 chip, write mode + ret + +;----------------------------------------------------------------------------- +; End of PPIDE disk driver +;------------------------------------------------------------------------------------ + + +; TEXT STRINGS + +TXT_RO_ERROR: + .DB CR,LF + .ascii "ERROR: WRITE TO READ ONLY DISK" + .DB END + +TXT_STARTUP_MSG: + .DB CR,LF + .ascii "CP/M-80 VERSION 2.2C FOR THE " + .ascii "N8VEM N8" + .ascii " (PPIDE)" + .DB CR,LF + .DB END + +; +; THE REMAINDER OF THE CBIOS IS RESERVED UNINITIALIZED +; DATA AREA, AND DOES NOT NEED TO BE A PART OF THE +; SYSTEM MEMORY IMAGE +; +TRACK: .DS 2 ; TWO BYTES FOR TRACK # +SECTOR: .DS 2 ; TWO BYTES FOR SECTOR # +DMAAD: .DS 2 ; DIRECT MEMORY ADDRESS +DISKNO: .DS 1 ; DISK NUMBER 0-15 + + +PAGER: .DB 1 ; COPY OF PAGER BYTE + +DB_PAGER: .db 0xff ; copy of pager byte + +V_SECTOR: .DS 2 ; TWO BYTES FOR VIRTUAL SECTOR # +SECST: .DS 2 ; SECTOR IN ROM/RAM START ADDRESS + + +LBA_OFFSET_LO: .DW 0 ; IDE HD PART STARTING SECTOR (LOW 16 BITS) +LBA_OFFSET_HI: .DW 0 ; IDE HD PART STARTING SECTOR (HI 16 BITS, 12 USED) +LBA_TARGET_LO: .DW 0 ; IDE HD PART TARGET SECTOR (LOW 16 BITS) +LBA_TARGET_HI: .DW 0 ; IDE HD PART TARGET SECTOR (HI 16 BITS, 12 USED) + +IDE_LBA0: .DS 1 ;SET LBA 0:7 +IDE_LBA1: .DS 1 ;SET LBA 8:15 +IDE_LBA2: .DS 1 ;SET LBA 16:23 +IDE_LBA3: .DS 1 ;LOWEST 4 BITS USED ONLY TO ENABLE LBA MODE + +SECTOR_INDEX: .DB 0 ;WHERE 128 BYTE CP/M SECTOR IS IN 512 BYTE IDE HD SECTOR + + +; +; SCRATCH RAM AREA FOR BDOS USE +; +; Note: this can extend up to the beginning of the debug monitor however +; there is a limitation in the amount of space available in the EPROM +; +;BEGDAT .EQU $ ;BEGINNING OF DATA AREA +; +; + +SECTOR_BUFFER: .DS 512 ;Deblocking STORAGE FOR 512 BYTE IDE HD SECTOR + +;dwg;TMPBUF .EQU SECTOR_BUFFER +TMPBUF = SECTOR_BUFFER + +DIRBF: .DS 128 ;SCRATCH DIRECTORY AREA +ALL00: .DS 4 ;ALLOCATION VECTOR 0 (DSM/8 = 1 BIT PER BLOCK) +ALL01: .DS 32 ;ALLOCATION VECTOR 1 (225/8) +ALL02: .DS 255 ;ALLOCATION VECTOR 2 (2040/8) +ALL03: .DS 255 ;ALLOCATION VECTOR 3 (2040/8) +ALL04: .DS 64 ;ALLOCATION VECTOR 4 (511/8) +ALL05: .DS 64 ;ALLOCATION VECTOR 5 (495/8) +; +CHK00: .DS 0 ; NOT USED FOR FIXED MEDIA +CHK01: .DS 0 ; NOT USED FOR FIXED MEDIA +CHK02: .DS 0 ; NOT USED FOR FIXED MEDIA +CHK03: .DS 0 ; NOT USED FOR FIXED MEDIA +CHK04: .DS 0 ; NOT USED FOR FIXED MEDIA +CHK05: .DS 0 ; NOT USED FOR FIXED MEDIA + +; DOUG SAYS - THIS NEEDS TO BE DONE ANOTHER WAY NO ORGS IN REL SEG +; +; .ORG $F2FF +; +; F2FF - desired org +; - E600 - BIOS ORG +; ______ +; 0CFF - necessary offset in this module +; +; 0CCF ; where we want to be +; - 0AA9 ; where we are now +; ______ +; 0256 - adjustment to reach desired org in rel segment +; + + .ds 0x0256 ; THIS NEEDS TO BE ADJUSTED SO LASTBYTE IS AT 0CFF + +LASTBYTE: .DB 0xE5 ; note this is just to force out the last byte. + ; this address will actually fall within the + ; allocation vector block + +_cbioshc_end:: + .area _CODE + .area _CABS diff --git a/doug/src/cbiosn8.sym b/doug/src/cbiosn8.sym new file mode 100755 index 00000000..200d3d98 --- /dev/null +++ b/doug/src/cbiosn8.sym @@ -0,0 +1,96 @@ + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 1. + +Symbol Table + + .__.ABS.= 0000 G | ACR = 0094 | 6 AL0_0 009B R + 6 AL0_1 008C R | 6 AL0_2 00AA R | 6 AL0_3 00B9 R + 6 AL0_4 00C8 R | 6 AL0_5 00D7 R | 6 AL1_0 009C R + 6 AL1_1 008D R | 6 AL1_2 00AB R | 6 AL1_3 00BA R + 6 AL1_4 00C9 R | 6 AL1_5 00D8 R | 6 ALL00 07FC R + 6 ALL01 0800 R | 6 ALL02 0820 R | 6 ALL03 091F R + 6 ALL04 0A1E R | 6 ALL05 0A5E R | ASEXT0 = 0052 + BBR = 0079 | BDOS = DC06 | BIAS = A000 + BIOS = EA00 | 6 BLM_0 0095 R | 6 BLM_1 0086 R + 6 BLM_2 00A4 R | 6 BLM_3 00B3 R | 6 BLM_4 00C2 R + 6 BLM_5 00D1 R | 6 BOOT 00DD R | 6 BSH_0 0094 R + 6 BSH_1 0085 R | 6 BSH_2 00A3 R | 6 BSH_3 00B2 R + 6 BSH_4 00C1 R | 6 BSH_5 00D0 R | CBAR = 007A + CBR = 0078 | CCP = D400 | CDISK = 0004 + 6 CHK00 0A9E R | 6 CHK01 0A9E R | 6 CHK02 0A9E R + 6 CHK03 0A9E R | 6 CHK04 0A9E R | 6 CHK05 0A9E R + 6 CKS_0 009D R | 6 CKS_1 008E R | 6 CKS_2 00AC R + 6 CKS_3 00BB R | 6 CKS_4 00CA R | 6 CKS_5 00D9 R + CNTLA0 = 0040 | CNTLB0 = 0042 | 6 CONIN 0141 R + 6 CONOUT 0153 R | 6 CONST 012F R | 6 CONVERT_ 03C4 R + CR = 000D | 6 CRTIN 01A3 R | 6 CRTISTS 01A9 R + 6 CRTOSTS 01AC R | 6 CRTOUT 01A6 R | 6 DB_PAGER 056A R + DEFIOB = 0094 | 6 DIRBF 077C R | 6 DISKNO 0568 R + 6 DMAAD 0566 R | 6 DPBASE 0033 R | 6 DPBLK0 0083 R + 6 DPBLK1 0092 R | 6 DPBLK2 00A1 R | 6 DPBLK3 00B0 R + 6 DPBLK4 00BF R | 6 DPBLK5 00CE R | 6 DRM_0 0099 R + 6 DRM_1 008A R | 6 DRM_2 00A8 R | 6 DRM_3 00B7 R + 6 DRM_4 00C6 R | 6 DRM_5 00D5 R | 6 DSM_0 0097 R + 6 DSM_1 0088 R | 6 DSM_2 00A6 R | 6 DSM_3 00B5 R + 6 DSM_4 00C4 R | 6 DSM_5 00D3 R | END = 00FF + 6 EXM_0 0096 R | 6 EXM_1 0087 R | 6 EXM_2 00A5 R + 6 EXM_3 00B4 R | 6 EXM_4 00C3 R | 6 EXM_5 00D2 R + 6 GOCPM 010E R | HC_REG_B= 0080 | 6 HOME 01C6 R + IDECTL = 0082 | IDELSB = 0080 | IDEMSB = 0081 + 6 IDE_LBA0 0577 R | 6 IDE_LBA1 0578 R | 6 IDE_LBA2 0579 R + 6 IDE_LBA3 057A R | 6 IDE_READ 03FC R | 6 IDE_WRIT 0415 R + IOBYTE = 0003 | IO_REG_B= 0040 | 6 LASTBYTE 0CF4 R + 6 LBA_OFFS 0571 R | 6 LBA_OFFS 056F R | 6 LBA_TARG 0575 R + 6 LBA_TARG 0573 R | LF = 000A | 6 LIST 0165 R + 6 LISTST 0168 R | MEM = 003C | MOVSIZ_C= 15FF + MOVSIZ_M= 0800 | MSIZE = 003C | 6 NULLIN 0171 R + 6 NULLOUT 0174 R | 6 NULLSTS 0176 R | 6 OFF_0 009F R + 6 OFF_1 0090 R | 6 OFF_2 00AE R | 6 OFF_3 00BD R + 6 OFF_4 00CC R | 6 OFF_5 00DB R | 6 PAGER 0569 R + 6 PAGERB 03A6 R | PIO1CONT= 0083 | PPI1 = 0080 + 6 PRTMSG 0389 R | 6 PRTMSG1 0397 R | 6 PUNCH 016B R + RAMTARG_= D400 | RAMTARG_= F800 | 6 RDONLY 0226 R + RDR0 = 0048 | 6 READ 01DE R | 6 READER 016E R + 6 READ_HDP 02B6 R | 6 READ_HDP 02C5 R | 6 READ_HDP 02D4 R + 6 READ_HDP 02D4 R | 6 READ_HDP 02D5 R | 6 READ_RAM 022F R + 6 READ_ROM 025F R | RMAP = 0096 | ROMSTART= 0900 + ROMSTART= 0100 | 6 RPAGE 03B9 R | 6 SECPAGE 0398 R + 6 SECST 056D R | 6 SECTOR 0564 R | 6 SECTOR_B 057C R + 6 SECTOR_I 057B R | 6 SECTRN 01D5 R | 6 SELDSK 01AF R + 6 SETDMA 01D8 R | 6 SETSEC 01CF R | 6 SETTRK 01C9 R + 6 SPT_0 0092 R | 6 SPT_1 0083 R | 6 SPT_2 00A1 R + 6 SPT_3 00B0 R | 6 SPT_4 00BF R | 6 SPT_5 00CE R + STAT0 = 0044 | TDR0 = 0046 | 6 TMPBUF = 057C R + 6 TRACK 0562 R | 6 TTYIN 0179 R | 6 TTYISTS 0191 R + 6 TTYOSTS 019A R | 6 TTYOUT 0185 R | 6 TXT_RO_E 050F R + 6 TXT_STAR 0530 R | 6 V_SECTOR 056B R | 6 WBOOT 00F5 R + 6 WBOOTE 0003 R | 6 WRITE 0202 R | 6 WRITE_HD 031C R + 6 WRITE_HD 032B R | 6 WRITE_HD 033A R | 6 WRITE_HD 033A R + 6 WRITE_HD 033B R | 6 WRITE_RA 0286 R | 6 _cbioshc 0000 GR + 6 _cbioshc 0CF5 GR | 6 _cbioshc 0000 GR | 6 gerr2 044C R + 6 get_err 0442 R | ide_a0_l= 0001 | ide_a1_l= 0002 + ide_a2_l= 0004 | ide_asta= 0017 | ide_cmd_= 00EC + ide_cmd_= 0091 | ide_cmd_= 0020 | ide_cmd_= 0010 + ide_cmd_= 00E0 | ide_cmd_= 00E1 | ide_cmd_= 0030 + ide_comm= 000F | ide_cont= 0016 | ide_cs0_= 0008 + ide_cs1_= 0010 | ide_cyl_= 000C | ide_cyl_= 000D + ide_data= 0008 | ide_err = 0009 | 6 ide_hard 042F R + ide_head= 000E | ide_rd_l= 0040 | 6 ide_read 04CF R + ide_rst_= 0080 | ide_sec_= 000A | ide_sect= 000B + ide_stat= 000F | 6 ide_wait 0469 R | 6 ide_wait 044F R + 6 ide_wait 045B R | ide_wr_l= 0020 | 6 ide_writ 04EB R + rd_ide_8= 0092 | 6 rdblk2 0479 R | 6 read_dat 0477 R + 6 rst_dly 0439 R | 6 set_ppi_ 0505 R | 6 set_ppi_ 050A R + wr_ide_8= 0080 | 6 wr_lba 049F R | 6 wrblk2 048D R + 6 write_da 048B R + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 2. + +Area Table + + 0 _CODE size 0 flags 0 + 1 _DATA size 0 flags 0 + 2 _OVERLAY size 0 flags 0 + 3 _HOME size 0 flags 0 + 4 _GSINIT size 0 flags 0 + 5 _GSFINAL size 0 flags 0 + 6 _CBIOS size CF5 flags 0 + 7 _CABS size 0 flags 0 diff --git a/doug/src/ccpb03.arf b/doug/src/ccpb03.arf new file mode 100755 index 00000000..66b472eb --- /dev/null +++ b/doug/src/ccpb03.arf @@ -0,0 +1,6 @@ +-mjx +-i ccpb03.ihx +-k /usr/local/share/sdcc/lib/z80 +-l z80 +ccpb03.rel +-e diff --git a/doug/src/ccpb03.lst b/doug/src/ccpb03.lst new file mode 100755 index 00000000..431ca66b --- /dev/null +++ b/doug/src/ccpb03.lst @@ -0,0 +1,1375 @@ + 1 .title ccpb03.s derived from ccpb03.asm + 2 .sbttl by Douglas Goodall 5/16/2011 dwg + 3 + 4 .module ccpb03 + 5 .optsdcc -mz80 + 6 + 7 ;-------------------------------------------------------- + 8 ; Public variables in this module + 9 ;-------------------------------------------------------- + 10 .globl _ccp + 11 ;-------------------------------------------------------- + 12 ; special function registers + 13 ;-------------------------------------------------------- + 14 ;-------------------------------------------------------- + 15 ; ram data + 16 ;-------------------------------------------------------- + 17 .area _DATA + 18 ;-------------------------------------------------------- + 19 ; overlayable items in ram + 20 ;-------------------------------------------------------- + 21 .area _OVERLAY + 22 ;-------------------------------------------------------- + 23 ; external initialized ram data + 24 ;-------------------------------------------------------- + 25 ;-------------------------------------------------------- + 26 ; global & static initialisations + 27 ;-------------------------------------------------------- + 28 .area _HOME + 29 .area _GSINIT + 30 .area _GSFINAL + 31 .area _GSINIT + 32 ;-------------------------------------------------------- + 33 ; Home + 34 ;-------------------------------------------------------- + 35 .area _HOME + 36 .area _HOME + 37 ;-------------------------------------------------------- + 38 ; code + 39 ;-------------------------------------------------------- + 40 + 41 ; .area _CODE + 42 .area _CCPB03 + 43 + 0000 44 _ccp_start:: + 0000 45 _ccp: + 46 + 0001 47 MON = 1 ;ADD THE CCP MON COMMAND + 0001 48 USRDSP = 1 ;SHOW THE USER NUMBER + 0001 49 CHKU0B = 1 ;CHECK FOR TRANSIENTS ON USER 0 TOO + 0001 50 ENDFIL = 1 ;FILE FULL CCP SIZE + 51 ; + 52 ;************************************************************** + 53 ;* + 54 ;* C C P - C O N S O L E C O M M A N D P R O C E S S O R + 55 ;* + 56 ;************************************************************** + 57 ;* + 0003 58 IOBYTE = 3 ; I/O DEFINITION BYTE. + 0004 59 TDRIVE = 4 ; CURRENT DRIVE NAME AND USER NUMBER. + 0005 60 ENTRY = 5 ; ENTRY POINT FOR THE CP/M BDOS. + 005C 61 TFCB = 0x5C ; DEFAULT FILE CONTROL BLOCK. + 0080 62 TBUFF = 0x80 ; I/O BUFFER AND COMMAND LINE STORAGE. + 0100 63 TBASE = 0x0100 ; TRANSIANT PROGRAM STORAGE AREA. + FC00 64 MONADR = 0x0FC00 ;MONITOR PROGRAM + 65 ; + 66 ; SET CONTROL CHARACTER .EQUATES. + 67 ; + 0003 68 CNTRLC = 0x03 ; CONTROL-C + 0005 69 CNTRLE = 0x05 ; CONTROL-E + 0008 70 BS = 0x08 ; BACKSPACE + 0009 71 TAB = 0x09 ; TAB + 000A 72 LF = 0x0A ; LINE FEED + 000C 73 FF = 0x0C ; FORM FEED + 000D 74 CR = 0x0D ; CARRIAGE RETURN + 0010 75 CNTRLP = 0x10 ; CONTROL-P + 0012 76 CNTRLR = 0x12 ; CONTROL-R + 0013 77 CNTRLS = 0x13 ; CONTROL-S + 0015 78 CNTRLU = 0x15 ; CONTROL-U + 0018 79 CNTRLX = 0x18 ; CONTROL-X + 001A 80 CNTRLZ = 0x1A ; CONTROL-Z (END-OF-FILE MARK) + 002A 81 ASTERICK = 0x2A + 003A 82 COLON = 0x3A + 003C 83 LESSTHAN = 0x3C + 0020 84 ASCSPACE = 0x20 ; SPACE + 002E 85 PERIOD = 0x2e ; PERIOD + 003D 86 EQUAL = 0x3D + 003E 87 GREATERTHAN = 0x3E + 003F 88 QUESTION = 0x3F ;QUESTION MARK + 005F 89 UNDERSCORE = 0x5F + 007B 90 LCURLY = 0x7B ; { + 007F 91 DEL = 0x7F ; RUBOUT + 92 ; + 93 ; SET ORIGIN FOR CP/M + 94 ; + 95 + 003B 96 NK = 59 ;SYSTEM SIZE + 9C00 97 BASE = (NK*1024)-0x5000 + D000 98 CCPO = BASE+0x3400 ;CCP ORIGIN + D800 99 BDOSO = BASE+0x3C00 ;BDOS ORIGIN + E600 100 BIOSO = BASE+0x4A00 ;BIOS ORIGIN + 101 + 102 ;dwg; .ORG CCPO + 103 ; + 0000 C3r54s03 104 CBASE: JP COMMAND ; EXECUTE COMMAND PROCESSOR (CCP). + 0003 C3r50s03 105 JP CLEARBUF ; ENTRY TO EMPTY INPUT BUFFER BEFORE STARTING CCP. + 106 + 107 ; + 108 ; STANDARD CP/M CCP INPUT BUFFER. FORMAT IS (MAX LENGTH), + 109 ; (ACTUAL LENGTH), (CHAR #1), (CHAR #2), (CHAR #3), ETC. + 110 ; + 0006 7F 111 INBUFF: .DB 127 ; LENGTH OF INPUT BUFFER. + 112 + 113 ; N8VEM - if add any text after this point, change .DB 0 below to length + 114 ; and put a 0 after the text, and delete the same number of zeros after the dig + 115 ; so that inpoint ends up at the same spot + 116 ; INBUFF+1 is cleared on the next warm boot, so only runs once. + 0007 00 117 .DB 0 ;CURRENT LENGTH OF CONTENTS. + 118 + 119 + 120 ; .DB 17 ; Autoboot length of string + 121 ; .DB "SUPERSUB AUTOEXEC" + 122 ; .DB 0 ; zero at end + 123 + 124 + 0008 43 4F 50 59 52 49 125 .ascii "COPYRIGHT" + 47 48 54 + 0011 20 31 39 37 39 20 126 .ascii " 1979 (C) BY " + 28 43 29 20 42 59 + 20 + 001E 44 49 47 49 54 41 127 .ascii "DIGITAL RESEARCH " + 4C 20 52 45 53 45 + 41 52 43 48 20 20 + 20 20 + 0032 20 20 128 .ascii " " + 129 + 130 ;dwg; .ORG INBUFF+128 + 131 ;dwg; becausje org's are not allowed in rel areas, it has been + 132 ; replaced with the following array of .db's to achieve the + 133 ; same purpose + 0034 00 00 00 00 00 00 134 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + 00 00 00 00 00 00 + 00 00 00 00 + 0044 00 00 00 00 00 00 135 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + 00 00 00 00 00 00 + 00 00 00 00 + 0054 00 00 00 00 00 00 136 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + 00 00 00 00 00 00 + 00 00 00 00 + 0064 00 00 00 00 00 00 137 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + 00 00 00 00 00 00 + 00 00 00 00 + 0074 00 00 00 00 00 00 138 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + 00 00 00 00 00 00 + 00 00 00 00 + 0084 00 00 139 .db 0,0 + 140 + 141 ;; s/b d086 here + 142 + 0086r08s00 143 INPOINT:.DW INBUFF+2 ; INPUT LINE POINTER + 0088 00 00 144 NAMEPNT:.DW 0 ; INPUT LINE POINTER USED FOR ERROR MESSAGE. POINTS TO + 145 ; ;START OF NAME IN ERROR. + 146 ; + 147 ; ROUTINE TO PRINT (A) ON THE CONSOLE. ALL REGISTERS USED. + 148 ; + 008A 5F 149 PRINT: LD E,A ; SETUP BDOS CALL. + 008B 0E 02 150 LD C,#2 + 008D C3 05 00 151 JP ENTRY + 152 ; + 153 ; ROUTINE TO PRINT (A) ON THE CONSOLE AND TO SAVE (BC). + 154 ; + 0090 C5 155 PRINTB: PUSH BC + 0091 CDr8As00 156 CALL PRINT + 0094 C1 157 POP BC + 0095 C9 158 RET + 159 ; + 160 ; ROUTINE TO SEND A CARRIAGE RETURN, LINE FEED COMBINATION + 161 ; TO THE CONSOLE. + 162 ; + 0096 3E 0D 163 CRLF: LD A,#CR + 0098 CDr90s00 164 CALL PRINTB + 009B 3E 0A 165 LD A,#LF + 009D C3r90s00 166 JP PRINTB + 167 ; + 168 ; ROUTINE TO SEND ONE SPACE TO THE CONSOLE AND SAVE (BC). + 169 ; + 00A0 3E 20 170 SPACE: LD A,#ASCSPACE + 00A2 C3r90s00 171 JP PRINTB + 172 ; + 173 ; ROUTINE TO PRINT CHARACTER STRING POINTED TO BE (BC) ON THE + 174 ; CONSOLE. IT MUST TERMINATE WITH A NULL BYTE. + 175 ; + 00A5 C5 176 PLINE: PUSH BC + 00A6 CDr96s00 177 CALL #CRLF + 00A9 E1 178 POP HL + 00AA 7E 179 PLINE2: LD A,(HL) + 00AB B7 180 OR A + 00AC C8 181 RET Z + 00AD 23 182 INC HL + 00AE E5 183 PUSH HL + 00AF CDr8As00 184 CALL PRINT + 00B2 E1 185 POP HL + 00B3 C3rAAs00 186 JP PLINE2 + 187 ; + 188 ; ROUTINE TO RESET THE DISK SYSTEM. + 189 ; + 00B6 0E 0D 190 RESDSK: LD C,#13 + 00B8 C3 05 00 191 JP ENTRY + 192 ; + 193 ; ROUTINE TO SELECT DISK (A). + 194 ; + 00BB 5F 195 DSKSEL: LD E,A + 00BC 0E 0E 196 LD C,#14 + 00BE C3 05 00 197 JP ENTRY + 198 ; + 199 ; ROUTINE TO CALL BDOS AND SAVE THE RETURN CODE. THE ZERO + 200 ; FLAG IS SET ON A RETURN OF 0FFH. + 201 ; + 00C1 CD 05 00 202 ENTRY1: CALL ENTRY + 00C4 32rFAs07 203 LD (RTNCODE),A ; SAVE RETURN CODE. + 00C7 3C 204 INC A ; SET ZERO IF 0FFH RETURNED. + 00C8 C9 205 RET + 206 ; + 207 ; ROUTINE TO OPEN A FILE. (DE) MUST POINT TO THE FCB. + 208 ; + 00C9 0E 0F 209 OPEN: LD C,#15 + 00CB C3rC1s00 210 JP ENTRY1 + 211 ; + 212 ; ROUTINE TO OPEN FILE AT (FCB). + 213 ; + 00CE AF 214 OPENFCB:XOR A ; CLEAR THE RECORD NUMBER BYTE AT FCB+32 + 00CF 32rF9s07 215 LD (FCB+32),A + 00D2 11rD9s07 216 LD DE,#FCB + 00D5 C3rC9s00 217 JP OPEN + 218 ; + 219 ; ROUTINE TO CLOSE A FILE. (DE) POINTS TO FCB. + 220 ; + 00D8 0E 10 221 CLOSE: LD C,#16 + 00DA C3rC1s00 222 JP ENTRY1 + 223 ; + 224 ; ROUTINE TO SEARCH FOR THE FIRST FILE WITH AMBIGUEOUS NAME + 225 ; (DE). + 226 ; + 00DD 0E 11 227 SRCHFST:LD C,#17 + 00DF C3rC1s00 228 JP ENTRY1 + 229 ; + 230 ; SEARCH FOR THE NEXT AMBIGEOUS FILE NAME. + 231 ; + 00E2 0E 12 232 SRCHNXT:LD C,#18 + 00E4 C3rC1s00 233 JP ENTRY1 + 234 ; + 235 ; SEARCH FOR FILE AT (FCB). + 236 ; + 00E7 11rD9s07 237 SRCHFCB:LD DE,#FCB + 00EA C3rDDs00 238 JP SRCHFST + 239 ; + 240 ; ROUTINE TO DELETE A FILE POINTED TO BY (DE). + 241 ; + 00ED 0E 13 242 DELETE: LD C,#19 + 00EF C3 05 00 243 JP ENTRY + 244 ; + 245 ; ROUTINE TO CALL THE BDOS AND SET THE ZERO FLAG IF A ZERO + 246 ; STATUS IS RETURNED. + 247 ; + 00F2 CD 05 00 248 ENTRY2: CALL ENTRY + 00F5 B7 249 OR A ; SET ZERO FLAG IF APPROPRIATE. + 00F6 C9 250 RET + 251 ; + 252 ; ROUTINE TO READ THE NEXT RECORD FROM A S.EQUENTIAL FILE. + 253 ; (DE) POINTS TO THE FCB. + 254 ; + 00F7 0E 14 255 RDREC: LD C,#20 + 00F9 C3rF2s00 256 JP ENTRY2 + 257 ; + 258 ; ROUTINE TO READ FILE AT (FCB). + 259 ; + 00FC 11rD9s07 260 READFCB:LD DE,#FCB + 00FF C3rF7s00 261 JP RDREC + 262 ; + 263 ; ROUTINE TO WRITE THE NEXT RECORD OF A S.EQUENTIAL FILE. + 264 ; (DE) POINTS TO THE FCB. + 265 ; + 0102 0E 15 266 WRTREC: LD C,#21 + 0104 C3rF2s00 267 JP ENTRY2 + 268 ; + 269 ; ROUTINE TO CREATE THE FILE POINTED TO BY (DE). + 270 ; + 0107 0E 16 271 CREATE: LD C,#22 + 0109 C3rC1s00 272 JP ENTRY1 + 273 ; + 274 ; ROUTINE TO RENAME THE FILE POINTED TO BY (DE). NOTE THAT + 275 ; THE NEW NAME STARTS AT (DE+16). + 276 ; + 010C 0E 17 277 RENAM: LD C,#23 + 010E C3 05 00 278 JP ENTRY + 279 ; + 280 ; GET THE CURRENT USER CODE. + 281 ; + 0111 1E FF 282 GETUSR: LD E,#0x0FF + 283 ; + 284 ; ROUTNE TO GET OR SET THE CURRENT USER CODE. + 285 ; IF (E) IS FF THEN THIS IS A GET, ELSE IT IS A SET. + 286 ; + 0113 287 GETSETUC: + 0113 0E 20 288 LD C,#32 + 0115 C3 05 00 289 JP ENTRY + 290 ; + 291 ; ROUTINE TO SET THE CURRENT DRIVE BYTE AT (TDRIVE). + 292 ; + 0118 CDr11s01 293 SETCDRV:CALL GETUSR ; GET USER NUMBER + 011B 87 294 ADD A,A ; AND SHIFT INTO THE UPPER 4 BITS. + 011C 87 295 ADD A,A + 011D 87 296 ADD A,A + 011E 87 297 ADD A,A + 011F 21rFBs07 298 LD HL,#CDRIVE ; NOW ADD IN THE CURRENT DRIVE NUMBER. + 0122 B6 299 OR (HL) + 0123 32 04 00 300 LD (TDRIVE),A ; AND SAVE. + 0126 C9 301 RET + 302 ; + 303 ; MOVE CURRENTLY ACTIVE DRIVE DOWN TO (TDRIVE). + 304 ; + 0127 3ArFBs07 305 MOVECD: LD A,(CDRIVE) + 012A 32 04 00 306 LD (TDRIVE),A + 012D C9 307 RET + 308 ; + 309 ; ROUTINE TO CONVERT (A) INTO UPPER CASE ASCII. ONLY LETTERS + 310 ; ARE AFFECTED. + 311 ; + 012E FE 41 312 UPPER: CP #0x41 ; CHECK FOR LETTERS IN THE RANGE OF 'A' TO 'Z'. + 0130 D8 313 RET C + 0131 FE 7B 314 CP #LCURLY + 0133 D0 315 RET NC + 0134 E6 5F 316 AND #0x5F ; CONVERT IT IF FOUND. + 0136 C9 317 RET + 318 ; + 319 ; ROUTINE TO GET A LINE OF INPUT. WE MUST CHECK TO SEE IF THE + 320 ; USER IS IN (BATCH) MODE. IF SO, THEN READ THE INPUT FROM FILE + 321 ; ($$$.SUB). AT THE END, RESET TO CONSOLE INPUT. + 322 ; + 0137 3ArB7s07 323 GETINP: LD A,(BATCH) ; IF =0, THEN USE CONSOLE INPUT. + 013A B7 324 OR A + 013B CAr94s01 325 JP Z,GETINP1 + 326 ; + 327 ; USE THE SUBMIT FILE ($$$.SUB) WHICH IS PREPARED BY A + 328 ; SUBMIT RUN. IT MUST BE ON DRIVE (A) AND IT WILL BE DELETED + 329 ; IF AND ERROR OCCURES (LIKE EOF). + 330 ; + 013E 3ArFBs07 331 LD A,(CDRIVE) ; SELECT DRIVE 0 IF NEED BE. + 0141 B7 332 OR A + 0142 3E 00 333 LD A,#0 ; ALWAYS USE DRIVE A FOR SUBMIT. + 0144 C4rBBs00 334 CALL NZ,DSKSEL ; SELECT IT IF R.EQUIRED. + 0147 11rB8s07 335 LD DE,#BATCHFCB + 014A CDrC9s00 336 CALL OPEN ; LOOK FOR IT. + 014D CAr94s01 337 JP Z,GETINP1 ; IF NOT THERE, USE NORMAL INPUT. + 0150 3ArC7s07 338 LD A,(BATCHFCB+15) ; GET LAST RECORD NUMBER+1. + 0153 3D 339 DEC A + 0154 32rD8s07 340 LD (BATCHFCB+32),A + 0157 11rB8s07 341 LD DE,#BATCHFCB + 015A CDrF7s00 342 CALL RDREC ; READ LAST RECORD. + 015D C2r94s01 343 JP NZ,GETINP1 ; QUIT ON END OF FILE. + 344 ; + 345 ; MOVE THIS RECORD INTO INPUT BUFFER. + 346 ; + 0160 11r07s00 347 LD DE,#INBUFF+1 + 0163 21 80 00 348 LD HL,#TBUFF ; DATA WAS READ INTO BUFFER HERE. + 0166 06 80 349 LD B,#128 ; ALL 128 CHARACTERS MAY BE USED. + 0168 CDr38s04 350 CALL HL2DE ; (HL) TO (DE), (B) BYTES. + 016B 21rC6s07 351 LD HL,#BATCHFCB+14 + 016E 36 00 352 LD (HL),#0 ; ZERO OUT THE 'S2' BYTE. + 0170 23 353 INC HL ; AND DECREMENT THE RECORD COUNT. + 0171 35 354 DEC (HL) + 0172 11rB8s07 355 LD DE,#BATCHFCB ; CLOSE THE BATCH FILE NOW. + 0175 CDrD8s00 356 CALL CLOSE + 0178 CAr94s01 357 JP Z,GETINP1 ; QUIT ON AN ERROR. + 017B 3ArFBs07 358 LD A,(CDRIVE) ; RE-SELECT PREVIOUS DRIVE IF NEED BE. + 017E B7 359 OR A + 017F C4rBBs00 360 CALL NZ,DSKSEL ; DON'T DO NEEDLESS SELECTS. + 361 ; + 362 ; PRINT LINE JUST READ ON CONSOLE. + 363 ; + 0182 21r08s00 364 LD HL,#INBUFF+2 + 0185 CDrAAs00 365 CALL PLINE2 + 0188 CDrC0s01 366 CALL CHKCON ; CHECK CONSOLE, QUIT ON A KEY. + 018B CArA5s01 367 JP Z,GETINP2 ; JUMP IF NO KEY IS PRESSED. + 368 ; + 369 ; TERMINATE THE SUBMIT JOB ON ANY KEYBOARD INPUT. DELETE THIS + 370 ; FILE SUCH THAT IT IS NOT RE-STARTED AND JUMP TO NORMAL KEYBOARD + 371 ; INPUT SECTION. + 372 ; + 018E CDrDBs01 373 CALL DELBATCH ; DELETE THE BATCH FILE. + 0191 C3r7As03 374 JP CMMND1 ; AND RESTART COMMAND INPUT. + 375 ; + 376 ; GET HERE FOR NORMAL KEYBOARD INPUT. DELETE THE SUBMIT FILE + 377 ; INCASE THERE WAS ONE. + 378 ; + 0194 CDrDBs01 379 GETINP1:CALL DELBATCH ; DELETE FILE ($$$.SUB). + 0197 CDr18s01 380 CALL SETCDRV ; RESET ACTIVE DISK. + 019A 0E 0A 381 LD C,#10 ; GET LINE FROM CONSOLE DEVICE. + 019C 11r06s00 382 LD DE,#INBUFF + 019F CD 05 00 383 CALL ENTRY + 01A2 CDr27s01 384 CALL MOVECD ; RESET CURRENT DRIVE (AGAIN). + 385 ; + 386 ; CONVERT INPUT LINE TO UPPER CASE. + 387 ; + 01A5 21r07s00 388 GETINP2:LD HL,#INBUFF+1 + 01A8 46 389 LD B,(HL) ; (B)=CHARACTER COUNTER. + 01A9 23 390 GETINP3:INC HL + 01AA 78 391 LD A,B ; END OF THE LINE? + 01AB B7 392 OR A + 01AC CArB8s01 393 JP Z,GETINP4 + 01AF 7E 394 LD A,(HL) ; CONVERT TO UPPER CASE. + 01B0 CDr2Es01 395 CALL UPPER + 01B3 77 396 LD (HL),A + 01B4 05 397 DEC B ; ADJUST CHARACTER COUNT. + 01B5 C3rA9s01 398 JP GETINP3 + 01B8 77 399 GETINP4:LD (HL),A ; ADD TRAILING NULL. + 01B9 21r08s00 400 LD HL,#INBUFF+2 + 01BC 22r86s00 401 LD (INPOINT),HL ; RESET INPUT LINE POINTER. + 01BF C9 402 RET + 403 ; + 404 ; ROUTINE TO CHECK THE CONSOLE FOR A KEY PRESSED. THE ZERO + 405 ; FLAG IS SET IS NONE, ELSE THE CHARACTER IS RETURNED IN (A). + 406 ; + 01C0 0E 0B 407 CHKCON: LD C,#11 ; CHECK CONSOLE. + 01C2 CD 05 00 408 CALL ENTRY + 01C5 B7 409 OR A + 01C6 C8 410 RET Z ; RETURN IF NOTHING. + 01C7 0E 01 411 LD C,#1 ; ELSE GET CHARACTER. + 01C9 CD 05 00 412 CALL ENTRY + 01CC B7 413 OR A ; CLEAR ZERO FLAG AND RETURN. + 01CD C9 414 RET + 415 ; + 416 ; ROUTINE TO GET THE CURRENTLY ACTIVE DRIVE NUMBER. + 417 ; + 01CE 0E 19 418 GETDSK: LD C,#25 + 01D0 C3 05 00 419 JP ENTRY + 420 ; + 421 ; SET THE STABDARD DMA ADDRESS. + 422 ; + 01D3 11 80 00 423 STDDMA: LD DE,#TBUFF + 424 ; + 425 ; ROUTINE TO SET THE DMA ADDRESS TO (DE). + 426 ; + 01D6 0E 1A 427 DMASET: LD C,#26 + 01D8 C3 05 00 428 JP ENTRY + 429 ; + 430 ; DELETE THE BATCH FILE CREATED BY SUBMIT. + 431 ; + 01DB 432 DELBATCH: + 01DB 21rB7s07 433 LD HL,#BATCH ; IS BATCH ACTIVE? + 01DE 7E 434 LD A,(HL) + 01DF B7 435 OR A + 01E0 C8 436 RET Z + 01E1 36 00 437 LD (HL),#0 ; YES, DE-ACTIVATE IT. + 01E3 AF 438 XOR A + 01E4 CDrBBs00 439 CALL DSKSEL ; SELECT DRIVE 0 FOR SURE. + 01E7 11rB8s07 440 LD DE,#BATCHFCB ; AND DELETE THIS FILE. + 01EA CDrEDs00 441 CALL DELETE + 01ED 3ArFBs07 442 LD A,(CDRIVE) ; RESET CURRENT DRIVE. + 01F0 C3rBBs00 443 JP DSKSEL + 444 ; + 445 ; PRINT BACK FILE NAME WITH A '?' TO INDICATE A SYNTAX ERROR. + 446 ; + 01F3 CDr96s00 447 SYNERR: CALL CRLF ; END CURRENT LINE. + 01F6 2Ar88s00 448 LD HL,(NAMEPNT) ; THIS POINTS TO NAME IN ERROR. + 01F9 7E 449 SYNERR1:LD A,(HL) ; PRINT IT UNTIL A SPACE OR NULL IS FOUND. + 01FA FE 20 450 CP #ASCSPACE + 01FC CAr0Cs02 451 JP Z,SYNERR2 + 01FF B7 452 OR A + 0200 CAr0Cs02 453 JP Z,SYNERR2 + 0203 E5 454 PUSH HL + 0204 CDr8As00 455 CALL PRINT + 0207 E1 456 POP HL + 0208 23 457 INC HL + 0209 C3rF9s01 458 JP SYNERR1 + 020C 3E 3F 459 SYNERR2:LD A,#QUESTION ; ADD TRAILING '?'. + 020E CDr8As00 460 CALL PRINT + 0211 CDr96s00 461 CALL CRLF + 0214 CDrDBs01 462 CALL DELBATCH ; DELETE ANY BATCH FILE. + 0217 C3r7As03 463 JP CMMND1 ; AND RESTART FROM CONSOLE INPUT. + 464 ; + 465 ; CHECK CHARACTER AT (DE) FOR LEGAL COMMAND INPUT. NOTE THAT THE + 466 ; ZERO FLAG IS SET IF THE CHARACTER IS A DELIMITER. + 467 ; + 021A 1A 468 CHECK: LD A,(DE) + 021B B7 469 OR A + 021C C8 470 RET Z + 021D FE 20 471 CP #ASCSPACE ; CONTROL CHARACTERS ARE NOT LEGAL HERE. + 021F DArF3s01 472 JP C,SYNERR + 0222 C8 473 RET Z ; CHECK FOR VALID DELIMITER. + 0223 FE 3D 474 CP #EQUAL + 0225 C8 475 RET Z + 0226 FE 5F 476 CP #UNDERSCORE + 0228 C8 477 RET Z + 0229 FE 2E 478 CP #PERIOD + 022B C8 479 RET Z + 022C FE 3A 480 CP #COLON + 022E C8 481 RET Z + 022F FE 3B 482 CP #0x3b + 0231 C8 483 RET Z + 0232 FE 3C 484 CP #LESSTHAN + 0234 C8 485 RET Z + 0235 FE 3E 486 CP #GREATERTHAN + 0237 C8 487 RET Z + 0238 C9 488 RET + 489 ; + 490 ; GET THE NEXT NON-BLANK CHARACTER FROM (DE). + 491 ; + 0239 492 NONBLANK: + 0239 1A 493 LD A,(DE) + 023A B7 494 OR A ; STRING ENDS WITH A NULL. + 023B C8 495 RET Z + 023C FE 20 496 CP #ASCSPACE + 023E C0 497 RET NZ + 023F 13 498 INC DE + 0240 C3r39s02 499 JP NONBLANK + 500 ; + 501 ; ADD (HL)=(HL)+(A) + 502 ; + 0243 85 503 ADDHL: ADD A,L + 0244 6F 504 LD L,A + 0245 D0 505 RET NC ; TAKE CARE OF ANY CARRY. + 0246 24 506 INC H + 0247 C9 507 RET + 508 ; + 509 ; CONVERT THE FIRST NAME IN (FCB). + 510 ; + 0248 3E 00 511 CONVFST:LD A,#0 + 512 ; + 513 ; FORMAT A FILE NAME (CONVERT * TO '?', ETC.). ON RETURN, + 514 ; (A)=0 IS AN UNAMBIGEOUS NAME WAS SPECIFIED. ENTER WITH (A) .EQUAL TO + 515 ; THE POSITION WITHIN THE FCB FOR THE NAME (EITHER 0 OR 16). + 516 ; + 024A 21rD9s07 517 CONVERT:LD HL,#FCB + 024D CDr43s02 518 CALL ADDHL + 0250 E5 519 PUSH HL + 0251 E5 520 PUSH HL + 0252 AF 521 XOR A + 0253 32rFCs07 522 LD (CHGDRV),A ; INITIALIZE DRIVE CHANGE FLAG. + 0256 2Ar86s00 523 LD HL,(INPOINT) ; SET (HL) AS POINTER INTO INPUT LINE. + 0259 EB 524 EX DE,HL + 025A CDr39s02 525 CALL NONBLANK ; GET NEXT NON-BLANK CHARACTER. + 025D EB 526 EX DE,HL + 025E 22r88s00 527 LD (NAMEPNT),HL ; SAVE POINTER HERE FOR ANY ERROR MESSAGE. + 0261 EB 528 EX DE,HL + 0262 E1 529 POP HL + 0263 1A 530 LD A,(DE) ; GET FIRST CHARACTER. + 0264 B7 531 OR A + 0265 CAr73s02 532 JP Z,CONVRT1 + 0268 DE 40 533 SBC A,#0x41-1 ; MIGHT BE A DRIVE NAME, CONVERT TO BINARY. + 026A 47 534 LD B,A ; AND SAVE. + 026B 13 535 INC DE ; CHECK NEXT CHARACTER FOR A ':'. + 026C 1A 536 LD A,(DE) + 026D FE 3A 537 CP #COLON + 026F CAr7As02 538 JP Z,CONVRT2 + 0272 1B 539 DEC DE ; NOPE, MOVE POINTER BACK TO THE START OF THE LINE. + 0273 3ArFBs07 540 CONVRT1:LD A,(CDRIVE) + 0276 77 541 LD (HL),A + 0277 C3r80s02 542 JP CONVRT3 + 027A 78 543 CONVRT2:LD A,B + 027B 32rFCs07 544 LD (CHGDRV),A ; SET CHANGE IN DRIVES FLAG. + 027E 70 545 LD (HL),B + 027F 13 546 INC DE + 547 ; + 548 ; CONVERT THE BASIC FILE NAME. + 549 ; + 0280 06 08 550 CONVRT3:LD B,#8 + 0282 CDr1As02 551 CONVRT4:CALL CHECK + 0285 CArA3s02 552 JP Z,CONVRT8 + 0288 23 553 INC HL + 0289 FE 2A 554 CP #ASTERICK ; NOTE THAT AN '*' WILL FILL THE REMAINING + 028B C2r93s02 555 JP NZ,CONVRT5 ; FIELD WITH '?'. + 028E 36 3F 556 LD (HL),#QUESTION + 0290 C3r95s02 557 JP CONVRT6 + 0293 77 558 CONVRT5:LD (HL),A + 0294 13 559 INC DE + 0295 05 560 CONVRT6:DEC B + 0296 C2r82s02 561 JP NZ,CONVRT4 + 0299 CDr1As02 562 CONVRT7:CALL CHECK ; GET NEXT DELIMITER. + 029C CArAAs02 563 JP Z,GETEXT + 029F 13 564 INC DE + 02A0 C3r99s02 565 JP CONVRT7 + 02A3 23 566 CONVRT8:INC HL ; BLANK FILL THE FILE NAME. + 02A4 36 20 567 LD (HL),#ASCSPACE + 02A6 05 568 DEC B + 02A7 C2rA3s02 569 JP NZ,CONVRT8 + 570 ; + 571 ; GET THE EXTENSION AND CONVERT IT. + 572 ; + 02AA 06 03 573 GETEXT: LD B,#3 + 02AC FE 2E 574 CP #PERIOD + 02AE C2rD3s02 575 JP NZ,GETEXT5 + 02B1 13 576 INC DE + 02B2 CDr1As02 577 GETEXT1:CALL CHECK + 02B5 CArD3s02 578 JP Z,GETEXT5 + 02B8 23 579 INC HL + 02B9 FE 2A 580 CP #ASTERICK + 02BB C2rC3s02 581 JP NZ,GETEXT2 + 02BE 36 3F 582 LD (HL),#QUESTION + 02C0 C3rC5s02 583 JP GETEXT3 + 02C3 77 584 GETEXT2:LD (HL),A + 02C4 13 585 INC DE + 02C5 05 586 GETEXT3:DEC B + 02C6 C2rB2s02 587 JP NZ,GETEXT1 + 02C9 CDr1As02 588 GETEXT4:CALL CHECK + 02CC CArDAs02 589 JP Z,GETEXT6 + 02CF 13 590 INC DE + 02D0 C3rC9s02 591 JP GETEXT4 + 02D3 23 592 GETEXT5:INC HL + 02D4 36 20 593 LD (HL),#ASCSPACE + 02D6 05 594 DEC B + 02D7 C2rD3s02 595 JP NZ,GETEXT5 + 02DA 06 03 596 GETEXT6:LD B,#3 + 02DC 23 597 GETEXT7:INC HL + 02DD 36 00 598 LD (HL),#0 + 02DF 05 599 DEC B + 02E0 C2rDCs02 600 JP NZ,GETEXT7 + 02E3 EB 601 EX DE,HL + 02E4 22r86s00 602 LD (INPOINT),HL ; SAVE INPUT LINE POINTER. + 02E7 E1 603 POP HL + 604 ; + 605 ; CHECK TO SEE IF THIS IS AN AMBIGEOUS FILE NAME SPECIFICATION. + 606 ; SET THE (A) REGISTER TO NON ZERO IF IT IS. + 607 ; + 02E8 01 0B 00 608 LD BC,#11 ; SET NAME LENGTH. + 02EB 23 609 GETEXT8:INC HL + 02EC 7E 610 LD A,(HL) + 02ED FE 3F 611 CP #QUESTION ; ANY QUESTION MARKS? + 02EF C2rF3s02 612 JP NZ,GETEXT9 + 02F2 04 613 INC B ; COUNT THEM. + 02F3 0D 614 GETEXT9:DEC C + 02F4 C2rEBs02 615 JP NZ,GETEXT8 + 02F7 78 616 LD A,B + 02F8 B7 617 OR A + 02F9 C9 618 RET + 619 ; + 620 ; CP/M COMMAND TABLE. NOTE COMMANDS CAN BE EITHER 3 OR 4 CHARACTERS LONG. + 621 ; + 0001 622 .if MON + 0007 623 NUMCMDS = 7 ; NUMBER OF COMMANDS + 624 .else + 625 NUMCMDS = 6 ; NUMBER OF COMMANDS + 626 .endif + 627 + 02FA 44 49 52 20 628 CMDTBL: .ascii "DIR " + 02FE 45 52 41 20 629 .ascii "ERA " + 0302 54 59 50 45 630 .ascii "TYPE" + 0306 53 41 56 45 631 .ascii "SAVE" + 030A 52 45 4E 20 632 .ascii "REN " + 030E 55 53 45 52 633 .ascii "USER" + 0001 634 .if MON + 0312 4D 4F 4E 20 635 .ascii "MON " + 636 .ENDIF + 637 + 0316r70s04 638 CMDADR: .DW DIRECT + 0318r18s05 639 .DW ERASE + 031Ar56s05 640 .DW TYPE + 031CrA6s05 641 .DW SAVE + 031Er09s06 642 .DW RENAME + 0320r87s06 643 .DW USER + 0001 644 .IF MON + 0322r6Ds04 645 .DW MONITOR + 646 .ENDIF + 0324r9Es06 647 .DW UNKNOWN + 648 ; + 649 ; SEARCH THE COMMAND TABLE FOR A MATCH WITH WHAT HAS JUST + 650 ; BEEN ENTERED. IF A MATCH IS FOUND, THEN WE JUMP TO THE + 651 ; PROPER SECTION. ELSE JUMP TO (UNKNOWN). + 652 ; ON RETURN, THE (C) REGISTER IS SET TO THE COMMAND NUMBER + 653 ; THAT MATCHED (OR NUMCMDS+1 IF NO MATCH). + 654 ; + 0326 21rFAs02 655 SEARCH: LD HL,#CMDTBL + 0329 0E 00 656 LD C,#0 + 032B 79 657 SEARCH1:LD A,C + 032C FE 07 658 CP #NUMCMDS ; THIS COMMANDS EXISTS. + 032E D0 659 RET NC + 032F 11rDAs07 660 LD DE,#FCB+1 ; CHECK THIS ONE. + 0332 06 04 661 LD B,#4 ; MAX COMMAND LENGTH. + 0334 1A 662 SEARCH2:LD A,(DE) + 0335 BE 663 CP (HL) + 0336 C2r47s03 664 JP NZ,SEARCH3 ; NOT A MATCH. + 0339 13 665 INC DE + 033A 23 666 INC HL + 033B 05 667 DEC B + 033C C2r34s03 668 JP NZ,SEARCH2 + 033F 1A 669 LD A,(DE) ; ALLOW A 3 CHARACTER COMMAND TO MATCH. + 0340 FE 20 670 CP #ASCSPACE + 0342 C2r4Cs03 671 JP NZ,SEARCH4 + 0345 79 672 LD A,C ; SET RETURN REGISTER FOR THIS COMMAND. + 0346 C9 673 RET + 0347 23 674 SEARCH3:INC HL + 0348 05 675 DEC B + 0349 C2r47s03 676 JP NZ,SEARCH3 + 034C 0C 677 SEARCH4:INC C + 034D C3r2Bs03 678 JP SEARCH1 + 679 ; + 680 ; SET THE INPUT BUFFER TO EMPTY AND THEN START THE COMMAND + 681 ; PROCESSOR (CCP). + 682 ; + 0350 683 CLEARBUF: + 0350 AF 684 XOR A + 0351 32r07s00 685 LD (INBUFF+1),A ; SECOND BYTE IS ACTUAL LENGTH. + 0354 31rB7s07 686 COMMAND:LD SP,#CCPSTACK ; SETUP STACK AREA. + 0357 C5 687 PUSH BC ; NOTE THAT (C) SHOULD BE .EQUAL TO: + 0358 79 688 LD A,C ; (UUUUDDDD) WHERE 'UUUU' IS THE USER NUMBER + 0359 1F 689 RRA ; AND 'DDDD' IS THE DRIVE NUMBER. + 035A 1F 690 RRA + 035B 1F 691 RRA + 035C 1F 692 RRA + 035D E6 0F 693 AND #0x0F ; ISOLATE THE USER NUMBER. + 035F 5F 694 LD E,A + 0360 CDr13s01 695 CALL GETSETUC ; AND SET IT. + 0363 CDrB6s00 696 CALL RESDSK ; RESET THE DISK SYSTEM. + 0366 32rB7s07 697 LD (BATCH),A ; CLEAR BATCH MODE FLAG. + 0369 C1 698 POP BC + 036A 79 699 LD A,C + 036B E6 0F 700 AND #0x0F ; ISOLATE THE DRIVE NUMBER. + 036D 32rFBs07 701 LD (CDRIVE),A ; AND SAVE. + 0370 CDrBBs00 702 CALL DSKSEL ; ...AND SELECT. + 0373 3Ar07s00 703 LD A,(INBUFF+1) + 0376 B7 704 OR A ; ANYTHING IN INPUT BUFFER ALREADY? + 0377 C2rA6s03 705 JP NZ,CMMND2 ; YES, WE JUST PROCESS IT. + 706 ; + 707 ; ENTRY POINT TO GET A COMMAND LINE FROM THE CONSOLE. + 708 ; + 037A 31rB7s07 709 CMMND1: LD SP,#CCPSTACK ; SET STACK STRAIGHT. + 037D CDr96s00 710 CALL CRLF ; START A NEW LINE ON THE SCREEN. + 0380 CDrCEs01 711 CALL GETDSK ; GET CURRENT DRIVE. + 0383 C6 41 712 ADD A,#0x41 + 0385 CDr8As00 713 CALL PRINT ; PRINT CURRENT DRIVE. + 0001 714 .IF USRDSP + 0388 CDr11s01 715 CALL GETUSR ;GET CURRENT USER NUMBER + 038B FE 0A 716 CP #10 ;TWO DIGITS? + 038D 38 0A 717 JR C,CMMND3 ;NO + 038F 3E 31 718 LD A,#0x31 ;PRINT LEADING '1' + 0391 CDr8As00 719 CALL PRINT + 0394 CDr11s01 720 CALL GETUSR ;GET CURRENT USER NUMBER + 0397 D6 0A 721 SUB #10 ;SUBTRACT 10 + 0399 C6 30 722 CMMND3: ADD A,#0x30 + 039B CDr8As00 723 CALL PRINT + 724 .ENDIF + 039E 3E 3E 725 LD A,#GREATERTHAN + 03A0 CDr8As00 726 CALL PRINT ; AND ADD PROMPT. + 03A3 CDr37s01 727 CALL GETINP ; GET LINE FROM USER. + 728 ; + 729 ; PROCESS COMMAND LINE HERE. + 730 ; + 03A6 11 80 00 731 CMMND2: LD DE,#TBUFF + 03A9 CDrD6s01 732 CALL DMASET ; SET STANDARD DMA ADDRESS. + 03AC CDrCEs01 733 CALL GETDSK + 03AF 32rFBs07 734 LD (CDRIVE),A ; SET CURRENT DRIVE. + 03B2 CDr48s02 735 CALL CONVFST ; CONVERT NAME TYPED IN. + 03B5 C4rF3s01 736 CALL NZ,SYNERR ; WILD CARDS ARE NOT ALLOWED. + 03B8 3ArFCs07 737 LD A,(CHGDRV) ; IF A CHANGE IN DRIVES WAS INDICATED, + 03BB B7 738 OR A ; THEN TREAT THIS AS AN UNKNOWN COMMAND + 03BC C2r9Es06 739 JP NZ,UNKNOWN ; WHICH GETS EXECUTED. + 03BF CDr26s03 740 CALL SEARCH ; ELSE SEARCH COMMAND TABLE FOR A MATCH. + 741 ; + 742 ; NOTE THAT AN UNKNOWN COMMAND RETURNS + 743 ; WITH (A) POINTING TO THE LAST ADDRESS + 744 ; IN OUR TABLE WHICH IS (UNKNOWN). + 745 ; + 03C2 21r16s03 746 LD HL,#CMDADR ; NOW, LOOK THRU OUR ADDRESS TABLE FOR COMMAND (A). + 03C5 5F 747 LD E,A ; SET (DE) TO COMMAND NUMBER. + 03C6 16 00 748 LD D,#0 + 03C8 19 749 ADD HL,DE + 03C9 19 750 ADD HL,DE ; (HL)=(CMDADR)+2*(COMMAND NUMBER). + 03CA 7E 751 LD A,(HL) ; NOW PICK OUT THIS ADDRESS. + 03CB 23 752 INC HL + 03CC 66 753 LD H,(HL) + 03CD 6F 754 LD L,A + 03CE E9 755 JP (HL) ; NOW EXECUTE IT. + 756 ; + 757 ; READ ERROR WHILE TYPEING A FILE. + 758 ; + 03CF 01rD5s03 759 RDERROR:LD BC,#RDERR + 03D2 C3rA5s00 760 JP PLINE + 03D5 52 65 61 64 20 45 761 RDERR: .asciz "Read Error" + 72 72 6F 72 00 + 762 + 763 ; + 764 ; R.EQUIRED FILE WAS NOT LOCATED. + 765 ; + 03E0 01rE6s03 766 NONE: LD BC,#NOFILE + 03E3 C3rA5s00 767 JP PLINE + 03E6 4E 6F 20 46 69 6C 768 NOFILE: .asciz "No File" + 65 00 + 769 ; + 770 ; DECODE A COMMAND OF THE FORM 'A>FILENAME NUMBER{ FILENAME}. + 771 ; NOTE THAT A DRIVE SPECIFIER IS NOT ALLOWED ON THE FIRST FILE + 772 ; NAME. ON RETURN, THE NUMBER IS IN REGISTER (A). ANY ERROR + 773 ; CAUSES 'FILENAME?' TO BE PRINTED AND THE COMMAND IS ABORTED. + 774 ; + 03EE CDr48s02 775 DECODE: CALL CONVFST ; CONVERT FILENAME. + 03F1 3ArFCs07 776 LD A,(CHGDRV) ; DO NOT ALLOW A DRIVE TO BE SPECIFIED. + 03F4 B7 777 OR A + 03F5 C2rF3s01 778 JP NZ,SYNERR + 03F8 21rDAs07 779 LD HL,#FCB+1 ; CONVERT NUMBER NOW. + 03FB 01 0B 00 780 LD BC,#11 ; (B)=SUM REGISTER, (C)=MAX DIGIT COUNT. + 03FE 7E 781 DECODE1:LD A,(HL) + 03FF FE 20 782 CP #ASCSPACE ; A SPACE TERMINATES THE NUMERAL. + 0401 CAr29s04 783 JP Z,DECODE3 + 0404 23 784 INC HL + 0405 D6 30 785 SUB #0x30 ; MAKE BINARY FROM ASCII. + 0407 FE 0A 786 CP #10 ; LEGAL DIGIT? + 0409 D2rF3s01 787 JP NC,SYNERR + 040C 57 788 LD D,A ; YES, SAVE IT IN (D). + 040D 78 789 LD A,B ; COMPUTE (B)=(B)*10 AND CHECK FOR OVERFLOW. + 040E E6 E0 790 AND #0x0E0 + 0410 C2rF3s01 791 JP NZ,SYNERR + 0413 78 792 LD A,B + 0414 07 793 RLCA + 0415 07 794 RLCA + 0416 07 795 RLCA ; (A)=(B)*8 + 0417 80 796 ADD A,B ; .......*9 + 0418 DArF3s01 797 JP C,SYNERR + 041B 80 798 ADD A,B ; .......*10 + 041C DArF3s01 799 JP C,SYNERR + 041F 82 800 ADD A,D ; ADD IN NEW DIGIT NOW. + 0420 DArF3s01 801 DECODE2:JP C,SYNERR + 0423 47 802 LD B,A ; AND SAVE RESULT. + 0424 0D 803 DEC C ; ONLY LOOK AT 11 DIGITS. + 0425 C2rFEs03 804 JP NZ,DECODE1 + 0428 C9 805 RET + 0429 7E 806 DECODE3:LD A,(HL) ; SPACES MUST FOLLOW (WHY?). + 042A FE 20 807 CP #ASCSPACE + 042C C2rF3s01 808 JP NZ,SYNERR + 042F 23 809 INC HL + 0430 0D 810 DECODE4:DEC C + 0431 C2r29s04 811 JP NZ,DECODE3 + 0434 78 812 LD A,B ; SET (A)=THE NUMERIC VALUE ENTERED. + 0435 C9 813 RET + 814 ; + 815 ; MOVE 3 BYTES FROM (HL) TO (DE). NOTE THAT THERE IS ONLY + 816 ; ONE REFERENCE TO THIS AT (A2D5H). + 817 ; + 0436 06 03 818 MOVE3: LD B,#3 + 819 ; + 820 ; MOVE (B) BYTES FROM (HL) TO (DE). + 821 ; + 0438 7E 822 HL2DE: LD A,(HL) + 0439 12 823 LD (DE),A + 043A 23 824 INC HL + 043B 13 825 INC DE + 043C 05 826 DEC B + 043D C2r38s04 827 JP NZ,HL2DE + 0440 C9 828 RET + 829 ; + 830 ; COMPUTE (HL)=(TBUFF)+(A)+(C) AND GET THE BYTE THAT'S HERE. + 831 ; + 0441 21 80 00 832 EXTRACT:LD HL,#TBUFF + 0444 81 833 ADD A,C + 0445 CDr43s02 834 CALL ADDHL + 0448 7E 835 LD A,(HL) + 0449 C9 836 RET + 837 ; + 838 ; CHECK DRIVE SPECIFIED. IF IT MEANS A CHANGE, THEN THE NEW + 839 ; DRIVE WILL BE SELECTED. IN ANY CASE, THE DRIVE BYTE OF THE + 840 ; FCB WILL BE SET TO NULL (MEANS USE CURRENT DRIVE). + 841 ; + 044A AF 842 DSELECT:XOR A ; NULL OUT FIRST BYTE OF FCB. + 044B 32rD9s07 843 LD (FCB),A + 044E 3ArFCs07 844 LD A,(CHGDRV) ; A DRIVE CHANGE INDICATED? + 0451 B7 845 OR A + 0452 C8 846 RET Z + 0453 3D 847 DEC A ; YES, IS IT THE SAME AS THE CURRENT DRIVE? + 0454 21rFBs07 848 LD HL,#CDRIVE + 0457 BE 849 CP (HL) + 0458 C8 850 RET Z + 0459 C3rBBs00 851 JP DSKSEL ; NO. SELECT IT THEN. + 852 ; + 853 ; CHECK THE DRIVE SELECTION AND RESET IT TO THE PREVIOUS + 854 ; DRIVE IF IT WAS CHANGED FOR THE PRECEEDING COMMAND. + 855 ; + 045C 3ArFCs07 856 RESETDR:LD A,(CHGDRV) ; DRIVE CHANGE INDICATED? + 045F B7 857 OR A + 0460 C8 858 RET Z + 0461 3D 859 DEC A ; YES, WAS IT A DIFFERENT DRIVE? + 0462 21rFBs07 860 LD HL,#CDRIVE + 0465 BE 861 CP (HL) + 0466 C8 862 RET Z + 0467 3ArFBs07 863 LD A,(CDRIVE) ; YES, RE-SELECT OUR OLD DRIVE. + 046A C3rBBs00 864 JP DSKSEL + 865 + 0001 866 .IF MON + 867 ; + 868 ;************************************************************** + 869 ;* + 870 ;* M O N I T O R C O M M A N D + 871 ;* + 872 ;************************************************************** + 873 ; + 046D C3 00 FC 874 MONITOR: JP MONADR + 875 .ENDIF + 876 + 877 ; + 878 ;************************************************************** + 879 ;* + 880 ;* D I R E C T O R Y C O M M A N D + 881 ;* + 882 ;************************************************************** + 883 ; + 0470 CDr48s02 884 DIRECT: CALL CONVFST ; CONVERT FILE NAME. + 0473 CDr4As04 885 CALL DSELECT ; SELECT INDICATED DRIVE. + 0476 21rDAs07 886 LD HL,#FCB+1 ; WAS ANY FILE INDICATED? + 0479 7E 887 LD A,(HL) + 047A FE 20 888 CP #ASCSPACE + 047C C2r88s04 889 JP NZ,DIRECT2 + 047F 06 0B 890 LD B,#11 ; NO. FILL FIELD WITH '?' - SAME AS *.*. + 0481 36 3F 891 DIRECT1:LD (HL),#QUESTION + 0483 23 892 INC HL + 0484 05 893 DEC B + 0485 C2r81s04 894 JP NZ,DIRECT1 + 0488 1E 00 895 DIRECT2:LD E,#0 ; SET INITIAL CURSOR POSITION. + 048A D5 896 PUSH DE + 048B CDrE7s00 897 CALL SRCHFCB ; GET FIRST FILE NAME. + 048E CCrE0s03 898 CALL Z,NONE ; NONE FOUND AT ALL? + 0491 CAr14s05 899 DIRECT3:JP Z,DIRECT9 ; TERMINATE IF NO MORE NAMES. + 0494 3ArFAs07 900 LD A,(RTNCODE) ; GET FILE'S POSITION IN SEGMENT (0-3). + 0497 0F 901 RRCA + 0498 0F 902 RRCA + 0499 0F 903 RRCA + 049A E6 60 904 AND #0x60 ; (A)=POSITION*32 + 049C 4F 905 LD C,A + 049D 3E 0A 906 LD A,#10 + 049F CDr41s04 907 CALL EXTRACT ; EXTRACT THE TENTH ENTRY IN FCB. + 04A2 17 908 RLA ; CHECK SYSTEM FILE STATUS BIT. + 04A3 DAr08s05 909 JP C,DIRECT8 ; WE DON'T LIST THEM. + 04A6 D1 910 POP DE + 04A7 7B 911 LD A,E ; BUMP NAME COUNT. + 04A8 1C 912 INC E + 04A9 D5 913 PUSH DE + 04AA E6 03 914 AND #3 ; AT END OF LINE? + 04AC F5 915 PUSH AF + 04AD C2rC5s04 916 JP NZ,DIRECT4 + 04B0 CDr96s00 917 CALL CRLF ; YES, END THIS LINE AND START ANOTHER. + 04B3 C5 918 PUSH BC + 04B4 CDrCEs01 919 CALL GETDSK ; START LINE WITH ('A:'). + 04B7 C1 920 POP BC + 04B8 C6 41 921 ADD A,#0x41 + 04BA CDr90s00 922 CALL PRINTB + 04BD 3E 3A 923 LD A,#COLON + 04BF CDr90s00 924 CALL PRINTB + 04C2 C3rCDs04 925 JP DIRECT5 + 04C5 CDrA0s00 926 DIRECT4:CALL SPACE ; ADD SEPERATOR BETWEEN FILE NAMES. + 04C8 3E 3A 927 LD A,#COLON + 04CA CDr90s00 928 CALL PRINTB + 04CD CDrA0s00 929 DIRECT5:CALL SPACE + 04D0 06 01 930 LD B,#1 ; 'EXTRACT' EACH FILE NAME CHARACTER AT A TIME. + 04D2 78 931 DIRECT6:LD A,B + 04D3 CDr41s04 932 CALL EXTRACT + 04D6 E6 7F 933 AND #0x7F ; STRIP BIT 7 (STATUS BIT). + 04D8 FE 20 934 CP #ASCSPACE ; ARE WE AT THE END OF THE NAME? + 04DA C2rF2s04 935 JP NZ,DRECT65 + 04DD F1 936 POP AF ; YES, DON'T PRINT SPACES AT THE END OF A LINE. + 04DE F5 937 PUSH AF + 04DF FE 03 938 CP #3 + 04E1 C2rF0s04 939 JP NZ,DRECT63 + 04E4 3E 09 940 LD A,#9 ; FIRST CHECK FOR NO EXTENSION. + 04E6 CDr41s04 941 CALL EXTRACT + 04E9 E6 7F 942 AND #0x7F + 04EB FE 20 943 CP #ASCSPACE + 04ED CAr07s05 944 JP Z,DIRECT7 ; DON'T PRINT SPACES. + 04F0 3E 20 945 DRECT63:LD A,#ASCSPACE ; ELSE PRINT THEM. + 04F2 CDr90s00 946 DRECT65:CALL PRINTB + 04F5 04 947 INC B ; BUMP TO NEXT CHARACTER PSOITION. + 04F6 78 948 LD A,B + 04F7 FE 0C 949 CP #12 ; END OF THE NAME? + 04F9 D2r07s05 950 JP NC,DIRECT7 + 04FC FE 09 951 CP #9 ; NOPE, STARTING EXTENSION? + 04FE C2rD2s04 952 JP NZ,DIRECT6 + 0501 CDrA0s00 953 CALL SPACE ; YES, ADD SEPERATING SPACE. + 0504 C3rD2s04 954 JP DIRECT6 + 0507 F1 955 DIRECT7:POP AF ; GET THE NEXT FILE NAME. + 0508 CDrC0s01 956 DIRECT8:CALL CHKCON ; FIRST CHECK CONSOLE, QUIT ON ANYTHING. + 050B C2r14s05 957 JP NZ,DIRECT9 + 050E CDrE2s00 958 CALL SRCHNXT ; GET NEXT NAME. + 0511 C3r91s04 959 JP DIRECT3 ; AND CONTINUE WITH OUR LIST. + 0514 D1 960 DIRECT9:POP DE ; RESTORE THE STACK AND RETURN TO COMMAND LEVEL. + 0515 C3r92s07 961 JP GETBACK + 962 ; + 963 ;************************************************************** + 964 ;* + 965 ;* E R A S E C O M M A N D + 966 ;* + 967 ;************************************************************** + 968 ; + 0518 CDr48s02 969 ERASE: CALL CONVFST ; CONVERT FILE NAME. + 051B FE 0B 970 CP #11 ; WAS '*.*' ENTERED? + 051D C2r3Bs05 971 JP NZ,ERASE1 + 0520 01r4Bs05 972 LD BC,#YESNO ; YES, ASK FOR CONFIRMATION. + 0523 CDrA5s00 973 CALL PLINE + 0526 CDr37s01 974 CALL GETINP + 0529 21r07s00 975 LD HL,#INBUFF+1 + 052C 35 976 DEC (HL) ; MUST BE EXACTLY 'Y'. + 052D C2r7As03 977 JP NZ,CMMND1 + 0530 23 978 INC HL + 0531 7E 979 LD A,(HL) + 0532 FE 59 980 CP #0x59 + 0534 C2r7As03 981 JP NZ,CMMND1 + 0537 23 982 INC HL + 0538 22r86s00 983 LD (INPOINT),HL ; SAVE INPUT LINE POINTER. + 053B CDr4As04 984 ERASE1: CALL DSELECT ; SELECT DESIRED DISK. + 053E 11rD9s07 985 LD DE,#FCB + 0541 CDrEDs00 986 CALL DELETE ; DELETE THE FILE. + 0544 3C 987 INC A + 0545 CCrE0s03 988 CALL Z,NONE ; NOT THERE? + 0548 C3r92s07 989 JP GETBACK ; RETURN TO COMMAND LEVEL NOW. + 054B 41 6C 6C 20 28 59 990 YESNO: .asciz "All (Y/N)?" + 2F 4E 29 3F 00 + 991 ; + 992 ;************************************************************** + 993 ;* + 994 ;* T Y P E C O M M A N D + 995 ;* + 996 ;************************************************************** + 997 ; + 0556 CDr48s02 998 TYPE: CALL CONVFST ; CONVERT FILE NAME. + 0559 C2rF3s01 999 JP NZ,SYNERR ; WILD CARDS NOT ALLOWED. + 055C CDr4As04 1000 CALL DSELECT ; SELECT INDICATED DRIVE. + 055F CDrCEs00 1001 CALL OPENFCB ; OPEN THE FILE. + 0562 CArA0s05 1002 JP Z,TYPE5 ; NOT THERE? + 0565 CDr96s00 1003 CALL CRLF ; OK, START A NEW LINE ON THE SCREEN. + 0568 21rFDs07 1004 LD HL,#NBYTES ; INITIALIZE BYTE COUNTER. + 056B 36 FF 1005 LD (HL),#0x0FF ; SET TO READ FIRST SECTOR. + 056D 21rFDs07 1006 TYPE1: LD HL,#NBYTES + 0570 7E 1007 TYPE2: LD A,(HL) ; HAVE WE WRITTEN THE ENTIRE SECTOR? + 0571 FE 80 1008 CP #128 + 0573 DAr80s05 1009 JP C,TYPE3 + 0576 E5 1010 PUSH HL ; YES, READ IN THE NEXT ONE. + 0577 CDrFCs00 1011 CALL READFCB + 057A E1 1012 POP HL + 057B C2r99s05 1013 JP NZ,TYPE4 ; END OR ERROR? + 057E AF 1014 XOR A ; OK, CLEAR BYTE COUNTER. + 057F 77 1015 LD (HL),A + 0580 34 1016 TYPE3: INC (HL) ; COUNT THIS BYTE. + 0581 21 80 00 1017 LD HL,#TBUFF ; AND GET THE (A)TH ONE FROM THE BUFFER (TBUFF). + 0584 CDr43s02 1018 CALL ADDHL + 0587 7E 1019 LD A,(HL) + 0588 FE 1A 1020 CP #CNTRLZ ; END OF FILE MARK? + 058A CAr92s07 1021 JP Z,GETBACK + 058D CDr8As00 1022 CALL PRINT ; NO, PRINT IT. + 0590 CDrC0s01 1023 CALL CHKCON ; CHECK CONSOLE, QUIT IF ANYTHING READY. + 0593 C2r92s07 1024 JP NZ,GETBACK + 0596 C3r6Ds05 1025 JP TYPE1 + 1026 ; + 1027 ; GET HERE ON AN END OF FILE OR READ ERROR. + 1028 ; + 0599 3D 1029 TYPE4: DEC A ; READ ERROR? + 059A CAr92s07 1030 JP Z,GETBACK + 059D CDrCFs03 1031 CALL RDERROR ; YES, PRINT MESSAGE. + 05A0 CDr5Cs04 1032 TYPE5: CALL RESETDR ; AND RESET PROPER DRIVE + 05A3 C3rF3s01 1033 JP SYNERR ; NOW PRINT FILE NAME WITH PROBLEM. + 1034 ; + 1035 ;************************************************************** + 1036 ;* + 1037 ;* S A V E C O M M A N D + 1038 ;* + 1039 ;************************************************************** + 1040 ; + 05A6 CDrEEs03 1041 SAVE: CALL DECODE ; GET NUMERIC NUMBER THAT FOLLOWS SAVE. + 05A9 F5 1042 PUSH AF ; SAVE NUMBER OF PAGES TO WRITE. + 05AA CDr48s02 1043 CALL CONVFST ; CONVERT FILE NAME. + 05AD C2rF3s01 1044 JP NZ,SYNERR ; WILD CARDS NOT ALLOWED. + 05B0 CDr4As04 1045 CALL DSELECT ; SELECT SPECIFIED DRIVE. + 05B3 11rD9s07 1046 LD DE,#FCB ; NOW DELETE THIS FILE. + 05B6 D5 1047 PUSH DE + 05B7 CDrEDs00 1048 CALL DELETE + 05BA D1 1049 POP DE + 05BB CDr07s01 1050 CALL CREATE ; AND CREATE IT AGAIN. + 05BE CArF4s05 1051 JP Z,SAVE3 ; CAN'T CREATE? + 05C1 AF 1052 XOR A ; CLEAR RECORD NUMBER BYTE. + 05C2 32rF9s07 1053 LD (FCB+32),A + 05C5 F1 1054 POP AF ; CONVERT PAGES TO SECTORS. + 05C6 6F 1055 LD L,A + 05C7 26 00 1056 LD H,#0 + 05C9 29 1057 ADD HL,HL ; (HL)=NUMBER OF SECTORS TO WRITE. + 05CA 11 00 01 1058 LD DE,#TBASE ; AND WE START FROM HERE. + 05CD 7C 1059 SAVE1: LD A,H ; DONE YET? + 05CE B5 1060 OR L + 05CF CArEAs05 1061 JP Z,SAVE2 + 05D2 2B 1062 DEC HL ; NOPE, COUNT THIS AND COMPUTE THE START + 05D3 E5 1063 PUSH HL ; OF THE NEXT 128 BYTE SECTOR. + 05D4 21 80 00 1064 LD HL,#128 + 05D7 19 1065 ADD HL,DE + 05D8 E5 1066 PUSH HL ; SAVE IT AND SET THE TRANSFER ADDRESS. + 05D9 CDrD6s01 1067 CALL DMASET + 05DC 11rD9s07 1068 LD DE,#FCB ; WRITE OUT THIS SECTOR NOW. + 05DF CDr02s01 1069 CALL WRTREC + 05E2 D1 1070 POP DE ; RESET (DE) TO THE START OF THE LAST SECTOR. + 05E3 E1 1071 POP HL ; RESTORE SECTOR COUNT. + 05E4 C2rF4s05 1072 JP NZ,SAVE3 ; WRITE ERROR? + 05E7 C3rCDs05 1073 JP SAVE1 + 1074 ; + 1075 ; GET HERE AFTER WRITING ALL OF THE FILE. + 1076 ; + 05EA 11rD9s07 1077 SAVE2: LD DE,#FCB ; NOW CLOSE THE FILE. + 05ED CDrD8s00 1078 CALL CLOSE + 05F0 3C 1079 INC A ; DID IT CLOSE OK? + 05F1 C2rFAs05 1080 JP NZ,SAVE4 + 1081 ; + 1082 ; PRINT OUT ERROR MESSAGE (NO SPACE). + 1083 ; + 05F4 01r00s06 1084 SAVE3: LD BC,#NOSPACE + 05F7 CDrA5s00 1085 CALL PLINE + 05FA CDrD3s01 1086 SAVE4: CALL STDDMA ; RESET THE STANDARD DMA ADDRESS. + 05FD C3r92s07 1087 JP GETBACK + 1088 + 0600 4E 6F 20 53 70 61 1089 NOSPACE: .asciz "No Space" + 63 65 00 + 1090 ; + 1091 ;************************************************************** + 1092 ;* + 1093 ;* R E N A M E C O M M A N D + 1094 ;* + 1095 ;************************************************************** + 1096 ; + 0609 CDr48s02 1097 RENAME: CALL CONVFST ; CONVERT FIRST FILE NAME. + 060C C2rF3s01 1098 JP NZ,SYNERR ; WILD CARDS NOT ALLOWED. + 060F 3ArFCs07 1099 LD A,(CHGDRV) ; REMEMBER ANY CHANGE IN DRIVES SPECIFIED. + 0612 F5 1100 PUSH AF + 0613 CDr4As04 1101 CALL DSELECT ; AND SELECT THIS DRIVE. + 0616 CDrE7s00 1102 CALL SRCHFCB ; IS THIS FILE PRESENT? + 0619 C2r72s06 1103 JP NZ,RENAME6 ; YES, PRINT ERROR MESSAGE. + 061C 21rD9s07 1104 LD HL,#FCB ; YES, MOVE THIS NAME INTO SECOND SLOT. + 061F 11rE9s07 1105 LD DE,#FCB+16 + 0622 06 10 1106 LD B,#16 + 0624 CDr38s04 1107 CALL HL2DE + 0627 2Ar86s00 1108 LD HL,(INPOINT) ; GET INPUT POINTER. + 062A EB 1109 EX DE,HL + 062B CDr39s02 1110 CALL NONBLANK ; GET NEXT NON BLANK CHARACTER. + 062E FE 3D 1111 CP #EQUAL ; ONLY ALLOW AN '=' OR '_' SEPERATOR. + 0630 CAr38s06 1112 JP Z,RENAME1 + 0633 FE 20 1113 CP #ASCSPACE + 0635 C2r6Cs06 1114 JP NZ,RENAME5 + 0638 EB 1115 RENAME1:EX DE,HL + 0639 23 1116 INC HL ; OK, SKIP SEPERATOR. + 063A 22r86s00 1117 LD (INPOINT),HL ; SAVE INPUT LINE POINTER. + 063D CDr48s02 1118 CALL CONVFST ; CONVERT THIS SECOND FILE NAME NOW. + 0640 C2r6Cs06 1119 JP NZ,RENAME5 ; AGAIN, NO WILD CARDS. + 0643 F1 1120 POP AF ; IF A DRIVE WAS SPECIFIED, THEN IT + 0644 47 1121 LD B,A ; MUST BE THE SAME AS BEFORE. + 0645 21rFCs07 1122 LD HL,#CHGDRV + 0648 7E 1123 LD A,(HL) + 0649 B7 1124 OR A + 064A CAr52s06 1125 JP Z,RENAME2 + 064D B8 1126 CP B + 064E 70 1127 LD (HL),B + 064F C2r6Cs06 1128 JP NZ,RENAME5 ; THEY WERE DIFFERENT, ERROR. + 0652 70 1129 RENAME2:LD (HL),B ; RESET AS PER THE FIRST FILE SPECIFICATION. + 0653 AF 1130 XOR A + 0654 32rD9s07 1131 LD (FCB),A ; CLEAR THE DRIVE BYTE OF THE FCB. + 0657 CDrE7s00 1132 RENAME3:CALL SRCHFCB ; AND GO LOOK FOR SECOND FILE. + 065A CAr66s06 1133 JP Z,RENAME4 ; DOESN'T EXIST? + 065D 11rD9s07 1134 LD DE,#FCB + 0660 CDr0Cs01 1135 CALL RENAM ; OK, RENAME THE FILE. + 0663 C3r92s07 1136 JP GETBACK + 1137 ; + 1138 ; PROCESS RENAME ERRORS HERE. + 1139 ; + 0666 CDrE0s03 1140 RENAME4:CALL NONE ; FILE NOT THERE. + 0669 C3r92s07 1141 JP GETBACK + 066C CDr5Cs04 1142 RENAME5:CALL RESETDR ; BAD COMMAND FORMAT. + 066F C3rF3s01 1143 JP SYNERR + 0672 01r7Bs06 1144 RENAME6:LD BC,#EXISTS ; DESTINATION FILE ALREADY EXISTS. + 0675 CDrA5s00 1145 CALL PLINE + 0678 C3r92s07 1146 JP GETBACK + 067B 46 69 6C 65 20 45 1147 EXISTS: .asciz "File Exists" + 78 69 73 74 73 00 + 1148 ; + 1149 ;************************************************************** + 1150 ;* + 1151 ;* U S E R C O M M A N D + 1152 ;* + 1153 ;************************************************************** + 1154 ; + 0687 CDrEEs03 1155 USER: CALL DECODE ; GET NUMERIC VALUE FOLLOWING COMMAND. + 068A FE 10 1156 CP #16 ; LEGAL USER NUMBER? + 068C D2rF3s01 1157 JP NC,SYNERR + 068F 5F 1158 LD E,A ; YES BUT IS THERE ANYTHING ELSE? + 0690 3ArDAs07 1159 LD A,(FCB+1) + 0693 FE 20 1160 CP #ASCSPACE + 0695 CArF3s01 1161 JP Z,SYNERR ; YES, THAT IS NOT ALLOWED. + 0698 CDr13s01 1162 CALL GETSETUC ; OK, SET USER CODE. + 069B C3r95s07 1163 JP GETBACK1 + 1164 ; + 1165 ;************************************************************** + 1166 ;* + 1167 ;* T R A N S I A N T P R O G R A M C O M M A N D + 1168 ;* + 1169 ;************************************************************** + 1170 ; + 069E 3ArDAs07 1171 UNKNOWN:LD A,(FCB+1) ; ANYTHING TO EXECUTE? + 06A1 FE 20 1172 CP #ASCSPACE + 06A3 C2rBAs06 1173 JP NZ,UNKWN1 + 06A6 3ArFCs07 1174 LD A,(CHGDRV) ; NOPE, ONLY A DRIVE CHANGE? + 06A9 B7 1175 OR A + 06AA CAr95s07 1176 JP Z,GETBACK1 ; NEITHER??? + 06AD 3D 1177 DEC A + 06AE 32rFBs07 1178 LD (CDRIVE),A ; OK, STORE NEW DRIVE. + 06B1 CDr27s01 1179 CALL MOVECD ; SET (TDRIVE) ALSO. + 06B4 CDrBBs00 1180 CALL DSKSEL ; AND SELECT THIS DRIVE. + 06B7 C3r95s07 1181 JP GETBACK1 ; THEN RETURN. + 1182 ; + 1183 ; HERE A FILE NAME WAS TYPED. PREPARE TO EXECUTE IT. + 1184 ; + 06BA 11rE2s07 1185 UNKWN1: LD DE,#FCB+9 ; AN EXTENSION SPECIFIED? + 06BD 1A 1186 LD A,(DE) + 06BE FE 20 1187 CP #ASCSPACE + 06C0 C2rF3s01 1188 JP NZ,SYNERR ; YES, NOT ALLOWED. + 06C3 D5 1189 UNKWN2: PUSH DE + 06C4 CDr4As04 1190 CALL DSELECT ; SELECT SPECIFIED DRIVE. + 06C7 D1 1191 POP DE + 06C8 21r8Fs07 1192 LD HL,#COMFILE ; SET THE EXTENSION TO 'COM'. LD HL,COMFILE + 06CB CDr36s04 1193 CALL MOVE3 ; move 3 bytes from (HL) to (DE) to add .COM + 06CE CDrCEs00 1194 CALL OPENFCB ; AND OPEN THIS FILE. + 06D1 C2rEAs06 1195 JP NZ,UNKWNA ;GOT IT + 0001 1196 .IF CHKU0B + 06D4 1E 00 1197 LD E,#0 ;TRY USER 0, THIS DRIVE + 06D6 CDr13s01 1198 CALL GETSETUC ; OK, SET USER CODE. + 06D9 CDrCEs00 1199 CALL OPENFCB + 06DC C2rEAs06 1200 JP NZ,UNKWNA ;GOT IT + 06DF 21rD9s07 1201 LD HL,#FCB ;SEE IF ON DRIVE B, USER 0 + 06E2 36 02 1202 LD (HL),#2 + 06E4 CDrCEs00 1203 CALL OPENFCB + 06E7 CAr77s07 1204 JP Z,UNKWN9 ;NOPE + 1205 .ENDIF + 1206 ; + 1207 ; LOAD IN THE PROGRAM. + 1208 ; + 06EA 21 00 01 1209 UNKWNA: LD HL,#TBASE ; STORE THE PROGRAM STARTING HERE. + 06ED E5 1210 UNKWN3: PUSH HL + 06EE EB 1211 EX DE,HL + 06EF CDrD6s01 1212 CALL DMASET ; SET TRANSFER ADDRESS. + 06F2 11rD9s07 1213 LD DE,#FCB ; AND READ THE NEXT RECORD. + 06F5 CDrF7s00 1214 CALL RDREC + 06F8 C2r0Ds07 1215 JP NZ,UNKWN4 ; END OF FILE OR READ ERROR? + 06FB E1 1216 POP HL ; NOPE, BUMP POINTER FOR NEXT SECTOR. + 06FC 11 80 00 1217 LD DE,#128 + 06FF 19 1218 ADD HL,DE + 0700 11r00s00 1219 LD DE,#CBASE ; ENOUGH ROOM FOR THE WHOLE FILE? + 0703 7D 1220 LD A,L + 0704 93 1221 SUB E + 0705 7C 1222 LD A,H + 0706 9A 1223 SBC A,D + 0707 D2r7Ds07 1224 JP NC,UNKWN0 ; NO, IT CAN'T FIT. + 070A C3rEDs06 1225 JP UNKWN3 + 1226 ; + 1227 ; GET HERE AFTER FINISHED READING. + 1228 ; + 070D E1 1229 UNKWN4: POP HL + 070E 3D 1230 DEC A ; NORMAL END OF FILE? + 070F C2r7Ds07 1231 JP NZ,UNKWN0 + 0712 CDr5Cs04 1232 CALL RESETDR ; YES, RESET PREVIOUS DRIVE. + 0715 CDr48s02 1233 CALL CONVFST ; CONVERT THE FIRST FILE NAME THAT FOLLOWS + 0718 21rFCs07 1234 LD HL,#CHGDRV ; COMMAND NAME. + 071B E5 1235 PUSH HL + 071C 7E 1236 LD A,(HL) ; SET DRIVE CODE IN DEFAULT FCB. + 071D 32rD9s07 1237 LD (FCB),A + 0720 3E 10 1238 LD A,#16 ; PUT SECOND NAME 16 BYTES LATER. + 0722 CDr4As02 1239 CALL CONVERT ; CONVERT SECOND FILE NAME. + 0725 E1 1240 POP HL + 0726 7E 1241 LD A,(HL) ; AND SET THE DRIVE FOR THIS SECOND FILE. + 0727 32rE9s07 1242 LD (FCB+16),A + 072A AF 1243 XOR A ; CLEAR RECORD BYTE IN FCB. + 072B 32rF9s07 1244 LD (FCB+32),A + 072E 11 5C 00 1245 LD DE,#TFCB ; MOVE IT INTO PLACE AT(005CH). + 0731 21rD9s07 1246 LD HL,#FCB + 0734 06 21 1247 LD B,#33 + 0736 CDr38s04 1248 CALL HL2DE + 0739 21r08s00 1249 LD HL,#INBUFF+2 ; NOW MOVE THE REMAINDER OF THE INPUT + 073C 7E 1250 UNKWN5: LD A,(HL) ; LINE DOWN TO (0080H). LOOK FOR A NON BLANK. + 073D B7 1251 OR A ; OR A NULL. + 073E CAr4As07 1252 JP Z,UNKWN6 + 0741 FE 20 1253 CP #ASCSPACE + 0743 CAr4As07 1254 JP Z,UNKWN6 + 0746 23 1255 INC HL + 0747 C3r3Cs07 1256 JP UNKWN5 + 1257 ; + 1258 ; DO THE LINE MOVE NOW. IT ENDS IN A NULL BYTE. + 1259 ; + 074A 06 00 1260 UNKWN6: LD B,#0 ; KEEP A CHARACTER COUNT. + 074C 11 81 00 1261 LD DE,#TBUFF+1 ; DATA GETS PUT HERE. + 074F 7E 1262 UNKWN7: LD A,(HL) ; MOVE IT NOW. + 0750 12 1263 LD (DE),A + 0751 B7 1264 OR A + 0752 CAr5Bs07 1265 JP Z,UNKWN8 + 0755 04 1266 INC B + 0756 23 1267 INC HL + 0757 13 1268 INC DE + 0758 C3r4Fs07 1269 JP UNKWN7 + 075B 78 1270 UNKWN8: LD A,B ; NOW STORE THE CHARACTER COUNT. + 075C 32 80 00 1271 LD (TBUFF),A + 075F CDr96s00 1272 CALL CRLF ; CLEAN UP THE SCREEN. + 0762 CDrD3s01 1273 CALL STDDMA ; SET STANDARD TRANSFER ADDRESS. + 0765 CDr18s01 1274 CALL SETCDRV ; RESET CURRENT DRIVE. + 0768 CD 00 01 1275 CALL TBASE ; AND EXECUTE THE PROGRAM. + 1276 ; + 1277 ; TRANSIANT PROGRAMS RETURN HERE (OR REBOOT). + 1278 ; + 076B 31rB7s07 1279 LD SP,#BATCH ; SET STACK FIRST OFF. + 076E CDr27s01 1280 CALL MOVECD ; MOVE CURRENT DRIVE INTO PLACE (TDRIVE). + 0771 CDrBBs00 1281 CALL DSKSEL ; AND RESELECT IT. + 0774 C3r7As03 1282 JP CMMND1 ; BACK TO COMAND MODE. + 1283 ; + 1284 ; GET HERE IF SOME ERROR OCCURED. + 1285 ; + 0777 CDr5Cs04 1286 UNKWN9: CALL RESETDR ; INPROPER FORMAT. + 077A C3rF3s01 1287 JP SYNERR + 077D 01r86s07 1288 UNKWN0: LD BC,#BADLOAD ; READ ERROR OR WON'T FIT. + 0780 CDrA5s00 1289 CALL PLINE + 0783 C3r92s07 1290 JP GETBACK + 0786 42 61 64 20 4C 6F 1291 BADLOAD:.asciz "Bad Load" + 61 64 00 + 078F 43 4F 4D 1292 COMFILE:.ascii "COM" ; COMMAND FILE EXTENSION. + 1293 ; + 1294 ; GET HERE TO RETURN TO COMMAND LEVEL. WE WILL RESET THE + 1295 ; PREVIOUS ACTIVE DRIVE AND THEN EITHER RETURN TO COMMAND + 1296 ; LEVEL DIRECTLY OR PRINT ERROR MESSAGE AND THEN RETURN. + 1297 ; + 0792 CDr5Cs04 1298 GETBACK:CALL RESETDR ; RESET PREVIOUS DRIVE. + 0795 1299 GETBACK1: + 0795 CDr48s02 1300 CALL CONVFST ; CONVERT FIRST NAME IN (FCB). + 0798 3ArDAs07 1301 LD A,(FCB+1) ; IF THIS WAS JUST A DRIVE CHANGE R.EQUEST, + 079B D6 20 1302 SUB #ASCSPACE ; MAKE SURE IT WAS VALID. + 079D 21rFCs07 1303 LD HL,#CHGDRV + 07A0 B6 1304 OR (HL) + 07A1 C2rF3s01 1305 JP NZ,SYNERR + 07A4 C3r7As03 1306 JP CMMND1 ; OK, RETURN TO COMMAND LEVEL. + 1307 ; + 1308 ; CCP STACK AREA. + 1309 ; + 07A7 00 00 00 00 00 00 1310 .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + 00 00 00 00 00 00 + 00 00 00 00 + 07B7 1311 CCPSTACK: + 1312 ;dwg; .EQU $ ;END OF CCP STACK AREA. + 1313 + 1314 ; + 1315 ; BATCH (OR SUBMIT) PROCESSING INFORMATION STORAGE. + 1316 ; + 07B7 00 1317 BATCH: .DB 0 ; BATCH MODE FLAG (0=NOT ACTIVE). + 07B8 00 1318 BATCHFCB:.DB 0 + 07B9 24 24 24 20 20 20 1319 .ascii "$$$ SUB" + 20 20 53 55 42 + 07C4 00 00 00 00 00 00 1320 .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 + 1321 ; + 1322 ; FILE CONTROL BLOCK SETUP BY THE CCP. + 1323 ; + 07D9 00 1324 FCB: .DB 0 + 07DA 20 20 20 20 20 20 1325 .asciz " " + 20 20 20 20 20 00 + 07E6 00 00 00 00 1326 .DB 0,0,0,0 + 1327 + 07EA 20 20 20 20 20 20 1328 .asciz " " + 20 20 20 20 20 00 + 07F6 00 00 00 00 1329 .DB 0,0,0,0 + 1330 + 07FA 00 1331 RTNCODE:.DB 0 ; STATUS RETURNED FROM BDOS CALL. + 07FB 00 1332 CDRIVE: .DB 0 ; CURRENTLY ACTIVE DRIVE. + 07FC 00 1333 CHGDRV: .DB 0 ; CHANGE IN DRIVES FLAG (0=NO CHANGE). + 07FD 00 00 1334 NBYTES: .DW 0 ; BYTE COUNTER USED BY TYPE. + 1335 + 1336 ;dwg; .IF ENDFIL + 1337 ;dwg; .ORG CCPO+07FFH + 1338 ;dwg; .DB 055H + 1339 ;dwg; .ENDIF + 1340 ;dwg; .END + 1341 + 1342 + 07FF 1343 _ccp_end:: + 1344 .area _CODE + 1345 .area _CABS diff --git a/doug/src/ccpb03.rel b/doug/src/ccpb03.rel new file mode 100755 index 00000000..ef0c91b2 --- /dev/null +++ b/doug/src/ccpb03.rel @@ -0,0 +1,368 @@ +XL +H 8 areas 4 global symbols +M ccpb03 +O -mz80 +S .__.ABS. Def0000 +A _CODE size 0 flags 0 addr 0 +A _DATA size 0 flags 0 addr 0 +A _OVERLAY size 0 flags 0 addr 0 +A _HOME size 0 flags 0 addr 0 +A _GSINIT size 0 flags 0 addr 0 +A _GSFINAL size 0 flags 0 addr 0 +A _CCPB03 size 7FF flags 0 addr 0 +S _ccp Def0000 +S _ccp_start Def0000 +S _ccp_end Def07FF +A _CABS size 0 flags 0 addr 0 +T 00 00 +R 00 00 06 00 +T 00 00 +R 00 00 06 00 +T 00 00 C3 54 03 C3 50 03 7F 00 43 4F 50 59 52 49 +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 0E 00 47 48 54 20 31 39 37 39 20 28 43 29 20 42 +R 00 00 06 00 +T 1C 00 59 20 44 49 47 49 54 41 4C 20 52 45 53 45 +R 00 00 06 00 +T 2A 00 41 52 43 48 20 20 20 20 20 20 00 00 00 00 +R 00 00 06 00 +T 38 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 46 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 62 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T 7E 00 00 00 00 00 00 00 00 00 08 00 00 00 5F 0E +R 00 00 06 00 00 0A 06 00 +T 8C 00 02 C3 05 00 C5 CD 8A 00 C1 C9 3E 0D CD +R 00 00 06 00 00 08 06 00 +T 99 00 90 00 3E 0A C3 90 00 3E 20 C3 90 00 C5 CD +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0C 06 00 +T A7 00 96 00 E1 7E B7 C8 23 E5 CD 8A 00 E1 C3 +R 00 00 06 00 00 02 06 00 00 0B 06 00 +T B4 00 AA 00 0E 0D C3 05 00 5F 0E 0E C3 05 00 CD +R 00 00 06 00 00 02 06 00 +T C2 00 05 00 32 FA 07 3C C9 0E 0F C3 C1 00 AF 32 +R 00 00 06 00 00 05 06 00 00 0C 06 00 +T D0 00 F9 07 11 D9 07 C3 C9 00 0E 10 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T DB 00 C1 00 0E 11 C3 C1 00 0E 12 C3 C1 00 11 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0C 06 00 +T E8 00 D9 07 C3 DD 00 0E 13 C3 05 00 CD 05 00 B7 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T F6 00 C9 0E 14 C3 F2 00 11 D9 07 C3 F7 00 0E 15 +R 00 00 06 00 00 06 06 00 00 09 06 00 00 0C 06 00 +T 04 01 C3 F2 00 0E 16 C3 C1 00 0E 17 C3 05 00 1E +R 00 00 06 00 00 03 06 00 00 08 06 00 +T 12 01 FF +R 00 00 06 00 +T 13 01 +R 00 00 06 00 +T 13 01 0E 20 C3 05 00 CD 11 01 87 87 87 87 21 +R 00 00 06 00 00 08 06 00 +T 20 01 FB 07 B6 32 04 00 C9 3A FB 07 32 04 00 C9 +R 00 00 06 00 00 02 06 00 00 0A 06 00 +T 2E 01 FE 41 D8 FE 7B D0 E6 5F C9 3A B7 07 B7 CA +R 00 00 06 00 00 0C 06 00 +T 3C 01 94 01 3A FB 07 B7 3E 00 C4 BB 00 11 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0B 06 00 +T 48 01 B8 07 CD C9 00 CA 94 01 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 51 01 C7 07 3D 32 D8 07 11 B8 07 CD +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T 5B 01 F7 00 C2 94 01 11 07 00 21 80 00 06 80 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 69 01 38 04 21 C6 07 36 00 23 35 11 B8 07 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0C 06 00 +T 76 01 D8 00 CA 94 01 3A FB 07 B7 C4 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 80 01 BB 00 21 08 00 CD AA 00 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 89 01 C0 01 CA A5 01 CD DB 01 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 92 01 7A 03 CD DB 01 CD 18 01 0E 0A 11 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 9D 01 06 00 CD 05 00 CD 27 01 21 07 00 46 23 78 +R 00 00 06 00 00 02 06 00 00 08 06 00 00 0B 06 00 +T AB 01 B7 CA B8 01 7E CD 2E 01 77 05 C3 A9 01 77 +R 00 00 06 00 00 04 06 00 00 08 06 00 00 0D 06 00 +T B9 01 21 08 00 22 86 00 C9 0E 0B CD 05 00 B7 C8 +R 00 00 06 00 00 03 06 00 00 06 06 00 +T C7 01 0E 01 CD 05 00 B7 C9 0E 19 C3 05 00 11 +R 00 00 06 00 +T D4 01 80 00 0E 1A C3 05 00 +R 00 00 06 00 +T DB 01 +R 00 00 06 00 +T DB 01 21 B7 07 7E B7 C8 36 00 AF CD BB 00 11 +R 00 00 06 00 00 03 06 00 00 0C 06 00 +T E8 01 B8 07 CD ED 00 3A FB 07 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T F1 01 BB 00 CD 96 00 2A 88 00 7E FE 20 CA +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T FD 01 0C 02 B7 CA 0C 02 E5 CD 8A 00 E1 23 C3 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0A 06 00 +T 0A 02 F9 01 3E 3F CD 8A 00 CD 96 00 CD +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T 15 02 DB 01 C3 7A 03 1A B7 C8 FE 20 DA F3 01 C8 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0D 06 00 +T 23 02 FE 3D C8 FE 5F C8 FE 2E C8 FE 3A C8 FE 3B +R 00 00 06 00 +T 31 02 C8 FE 3C C8 FE 3E C8 C9 +R 00 00 06 00 +T 39 02 +R 00 00 06 00 +T 39 02 1A B7 C8 FE 20 C0 13 C3 39 02 85 6F D0 24 +R 00 00 06 00 00 0A 06 00 +T 47 02 C9 3E 00 21 D9 07 CD 43 02 E5 E5 AF 32 +R 00 00 06 00 00 06 06 00 00 09 06 00 +T 54 02 FC 07 2A 86 00 EB CD 39 02 EB 22 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T 5F 02 88 00 EB E1 1A B7 CA 73 02 DE 40 47 13 1A +R 00 00 06 00 00 02 06 00 00 09 06 00 +T 6D 02 FE 3A CA 7A 02 1B 3A FB 07 77 C3 80 02 78 +R 00 00 06 00 00 05 06 00 00 09 06 00 00 0D 06 00 +T 7B 02 32 FC 07 70 13 06 08 CD 1A 02 CA A3 02 23 +R 00 00 06 00 00 03 06 00 00 0A 06 00 00 0D 06 00 +T 89 02 FE 2A C2 93 02 36 3F C3 95 02 77 13 05 C2 +R 00 00 06 00 00 05 06 00 00 0A 06 00 +T 97 02 82 02 CD 1A 02 CA AA 02 13 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T A1 02 99 02 23 36 20 05 C2 A3 02 06 03 FE 2E C2 +R 00 00 06 00 00 02 06 00 00 09 06 00 +T AF 02 D3 02 13 CD 1A 02 CA D3 02 23 FE 2A C2 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T BC 02 C3 02 36 3F C3 C5 02 77 13 05 C2 B2 02 CD +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0D 06 00 +T CA 02 1A 02 CA DA 02 13 C3 C9 02 23 36 20 05 C2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T D8 02 D3 02 06 03 23 36 00 05 C2 DC 02 EB 22 +R 00 00 06 00 00 02 06 00 00 0B 06 00 +T E5 02 86 00 E1 01 0B 00 23 7E FE 3F C2 F3 02 04 +R 00 00 06 00 00 02 06 00 00 0D 06 00 +T F3 02 0D C2 EB 02 78 B7 C9 44 49 52 20 45 52 41 +R 00 00 06 00 00 04 06 00 +T 01 03 20 54 59 50 45 53 41 56 45 52 45 4E 20 55 +R 00 00 06 00 +T 0F 03 53 45 52 4D 4F 4E 20 70 04 18 05 56 05 +R 00 00 06 00 00 09 06 00 00 0B 06 00 00 0D 06 00 +T 1C 03 A6 05 09 06 87 06 +R 00 00 06 00 00 02 06 00 00 04 06 00 00 06 06 00 +T 22 03 6D 04 9E 06 21 FA 02 0E 00 79 FE 07 D0 11 +R 00 00 06 00 00 02 06 00 00 04 06 00 00 07 06 00 +T 30 03 DA 07 06 04 1A BE C2 47 03 13 23 05 C2 +R 00 00 06 00 00 02 06 00 00 09 06 00 +T 3D 03 34 03 1A FE 20 C2 4C 03 79 C9 23 05 C2 +R 00 00 06 00 00 02 06 00 00 08 06 00 +T 4A 03 47 03 0C C3 2B 03 +R 00 00 06 00 00 02 06 00 00 06 06 00 +T 50 03 +R 00 00 06 00 +T 50 03 AF 32 07 00 31 B7 07 C5 79 1F 1F 1F 1F E6 +R 00 00 06 00 00 04 06 00 00 07 06 00 +T 5E 03 0F 5F CD 13 01 CD B6 00 32 B7 07 C1 79 E6 +R 00 00 06 00 00 05 06 00 00 08 06 00 00 0B 06 00 +T 6C 03 0F 32 FB 07 CD BB 00 3A 07 00 B7 C2 +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T 78 03 A6 03 31 B7 07 CD 96 00 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 81 03 CE 01 C6 41 CD 8A 00 CD 11 01 FE 0A 38 0A +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T 8F 03 3E 31 CD 8A 00 CD 11 01 D6 0A C6 30 CD +R 00 00 06 00 00 05 06 00 00 08 06 00 +T 9C 03 8A 00 3E 3E CD 8A 00 CD 37 01 11 80 00 CD +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T AA 03 D6 01 CD CE 01 32 FB 07 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T B3 03 48 02 C4 F3 01 3A FC 07 B7 C2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T BD 03 9E 06 CD 26 03 21 16 03 5F 16 00 19 19 7E +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T CB 03 23 66 6F E9 01 D5 03 C3 A5 00 52 65 61 64 +R 00 00 06 00 00 07 06 00 00 0A 06 00 +T D9 03 20 45 72 72 6F 72 00 01 E6 03 C3 A5 00 4E +R 00 00 06 00 00 0A 06 00 00 0D 06 00 +T E7 03 6F 20 46 69 6C 65 00 CD 48 02 3A FC 07 B7 +R 00 00 06 00 00 0A 06 00 00 0D 06 00 +T F5 03 C2 F3 01 21 DA 07 01 0B 00 7E FE 20 CA +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 02 04 29 04 23 D6 30 FE 0A D2 F3 01 57 78 E6 E0 +R 00 00 06 00 00 02 06 00 00 0A 06 00 +T 10 04 C2 F3 01 78 07 07 07 80 DA F3 01 80 DA +R 00 00 06 00 00 03 06 00 00 0B 06 00 +T 1D 04 F3 01 82 DA F3 01 47 0D C2 FE 03 C9 7E FE +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0B 06 00 +T 2B 04 20 C2 F3 01 23 0D C2 29 04 78 C9 06 03 7E +R 00 00 06 00 00 04 06 00 00 09 06 00 +T 39 04 12 23 13 05 C2 38 04 C9 21 80 00 81 CD +R 00 00 06 00 00 07 06 00 +T 46 04 43 02 7E C9 AF 32 D9 07 3A FC 07 B7 C8 3D +R 00 00 06 00 00 02 06 00 00 08 06 00 00 0B 06 00 +T 54 04 21 FB 07 BE C8 C3 BB 00 3A FC 07 B7 C8 3D +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0B 06 00 +T 62 04 21 FB 07 BE C8 3A FB 07 C3 BB 00 C3 00 FC +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0B 06 00 +T 70 04 CD 48 02 CD 4A 04 21 DA 07 7E FE 20 C2 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 7D 04 88 04 06 0B 36 3F 23 05 C2 81 04 1E 00 D5 +R 00 00 06 00 00 02 06 00 00 0B 06 00 +T 8B 04 CD E7 00 CC E0 03 CA 14 05 3A +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 95 04 FA 07 0F 0F 0F E6 60 4F 3E 0A CD 41 04 17 +R 00 00 06 00 00 02 06 00 00 0D 06 00 +T A3 04 DA 08 05 D1 7B 1C D5 E6 03 F5 C2 C5 04 CD +R 00 00 06 00 00 03 06 00 00 0D 06 00 +T B1 04 96 00 C5 CD CE 01 C1 C6 41 CD 90 00 3E 3A +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0C 06 00 +T BF 04 CD 90 00 C3 CD 04 CD A0 00 3E 3A CD +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T CB 04 90 00 CD A0 00 06 01 78 CD 41 04 E6 7F FE +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0B 06 00 +T D9 04 20 C2 F2 04 F1 F5 FE 03 C2 F0 04 3E 09 CD +R 00 00 06 00 00 04 06 00 00 0B 06 00 +T E7 04 41 04 E6 7F FE 20 CA 07 05 3E 20 CD 90 00 +R 00 00 06 00 00 02 06 00 00 09 06 00 00 0E 06 00 +T F5 04 04 78 FE 0C D2 07 05 FE 09 C2 D2 04 CD +R 00 00 06 00 00 07 06 00 00 0C 06 00 +T 02 05 A0 00 C3 D2 04 F1 CD C0 01 C2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T 0C 05 14 05 CD E2 00 C3 91 04 D1 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 16 05 92 07 CD 48 02 FE 0B C2 3B 05 01 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T 21 05 4B 05 CD A5 00 CD 37 01 21 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 2A 05 07 00 35 C2 7A 03 23 7E FE 59 C2 7A 03 23 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0D 06 00 +T 38 05 22 86 00 CD 4A 04 11 D9 07 CD +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 42 05 ED 00 3C CC E0 03 C3 92 07 41 6C 6C 20 28 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T 50 05 59 2F 4E 29 3F 00 CD 48 02 C2 F3 01 CD +R 00 00 06 00 00 09 06 00 00 0C 06 00 +T 5D 05 4A 04 CD CE 00 CA A0 05 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 66 05 96 00 21 FD 07 36 FF 21 FD 07 7E FE 80 DA +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T 74 05 80 05 E5 CD FC 00 E1 C2 99 05 AF 77 34 21 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0A 06 00 +T 82 05 80 00 CD 43 02 7E FE 1A CA 92 07 CD 8A 00 +R 00 00 06 00 00 05 06 00 00 0B 06 00 00 0E 06 00 +T 90 05 CD C0 01 C2 92 07 C3 6D 05 3D CA +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 9B 05 92 07 CD CF 03 CD 5C 04 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T A4 05 F3 01 CD EE 03 F5 CD 48 02 C2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T AE 05 F3 01 CD 4A 04 11 D9 07 D5 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T B8 05 ED 00 D1 CD 07 01 CA F4 05 AF 32 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T C3 05 F9 07 F1 6F 26 00 29 11 00 01 7C B5 CA +R 00 00 06 00 00 02 06 00 +T D0 05 EA 05 2B E5 21 80 00 19 E5 CD D6 01 11 +R 00 00 06 00 00 02 06 00 00 0C 06 00 +T DD 05 D9 07 CD 02 01 D1 E1 C2 F4 05 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T E8 05 CD 05 11 D9 07 CD D8 00 3C C2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T F2 05 FA 05 01 00 06 CD A5 00 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T FB 05 D3 01 C3 92 07 4E 6F 20 53 70 61 63 65 00 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 09 06 CD 48 02 C2 F3 01 3A FC 07 F5 CD +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 14 06 4A 04 CD E7 00 C2 72 06 21 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 1D 06 D9 07 11 E9 07 06 10 CD 38 04 2A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T 28 06 86 00 EB CD 39 02 FE 3D CA 38 06 FE 20 C2 +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0B 06 00 +T 36 06 6C 06 EB 23 22 86 00 CD 48 02 C2 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T 41 06 6C 06 F1 47 21 FC 07 7E B7 CA 52 06 B8 70 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0C 06 00 +T 4F 06 C2 6C 06 70 AF 32 D9 07 CD E7 00 CA +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0B 06 00 +T 5B 06 66 06 11 D9 07 CD 0C 01 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 64 06 92 07 CD E0 03 C3 92 07 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 6D 06 5C 04 C3 F3 01 01 7B 06 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 76 06 A5 00 C3 92 07 46 69 6C 65 20 45 78 69 73 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 84 06 74 73 00 CD EE 03 FE 10 D2 F3 01 5F 3A +R 00 00 06 00 00 06 06 00 00 0B 06 00 +T 91 06 DA 07 FE 20 CA F3 01 CD 13 01 C3 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T 9C 06 95 07 3A DA 07 FE 20 C2 BA 06 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T A7 06 FC 07 B7 CA 95 07 3D 32 FB 07 CD +R 00 00 06 00 00 02 06 00 00 06 06 00 00 0A 06 00 +T B2 06 27 01 CD BB 00 C3 95 07 11 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T BB 06 E2 07 1A FE 20 C2 F3 01 D5 CD 4A 04 D1 21 +R 00 00 06 00 00 02 06 00 00 08 06 00 00 0C 06 00 +T C9 06 8F 07 CD 36 04 CD CE 00 C2 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T D2 06 EA 06 1E 00 CD 13 01 CD CE 00 C2 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T DD 06 EA 06 21 D9 07 36 02 CD CE 00 CA +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T E8 06 77 07 21 00 01 E5 EB CD D6 01 11 D9 07 CD +R 00 00 06 00 00 02 06 00 00 0A 06 00 00 0D 06 00 +T F6 06 F7 00 C2 0D 07 E1 11 80 00 19 11 00 00 7D +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0D 06 00 +T 04 07 93 7C 9A D2 7D 07 C3 ED 06 E1 3D C2 7D 07 +R 00 00 06 00 00 06 06 00 00 09 06 00 00 0E 06 00 +T 12 07 CD 5C 04 CD 48 02 21 FC 07 E5 7E 32 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 1E 07 D9 07 3E 10 CD 4A 02 E1 7E 32 E9 07 AF 32 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0C 06 00 +T 2C 07 F9 07 11 5C 00 21 D9 07 06 21 CD 38 04 21 +R 00 00 06 00 00 02 06 00 00 08 06 00 00 0D 06 00 +T 3A 07 08 00 7E B7 CA 4A 07 FE 20 CA 4A 07 23 C3 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0C 06 00 +T 48 07 3C 07 06 00 11 81 00 7E 12 B7 CA 5B 07 04 +R 00 00 06 00 00 02 06 00 00 0D 06 00 +T 56 07 23 13 C3 4F 07 78 32 80 00 CD 96 00 CD +R 00 00 06 00 00 05 06 00 00 0C 06 00 +T 63 07 D3 01 CD 18 01 CD 00 01 31 B7 07 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0B 06 00 +T 6F 07 27 01 CD BB 00 C3 7A 03 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 78 07 5C 04 C3 F3 01 01 86 07 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 81 07 A5 00 C3 92 07 42 61 64 20 4C 6F 61 64 00 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 8F 07 43 4F 4D CD 5C 04 +R 00 00 06 00 00 06 06 00 +T 95 07 +R 00 00 06 00 +T 95 07 CD 48 02 3A DA 07 D6 20 21 FC 07 B6 C2 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0B 06 00 +T A2 07 F3 01 C3 7A 03 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T B0 07 00 00 00 00 00 00 00 +R 00 00 06 00 +T B7 07 +R 00 00 06 00 +T B7 07 00 00 24 24 24 20 20 20 20 20 53 55 42 00 +R 00 00 06 00 +T C5 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T D3 07 00 00 00 00 00 00 00 20 20 20 20 20 20 20 +R 00 00 06 00 +T E1 07 20 20 20 20 00 00 00 00 00 20 20 20 20 20 +R 00 00 06 00 +T EF 07 20 20 20 20 20 20 00 00 00 00 00 00 00 00 +R 00 00 06 00 +T FD 07 00 00 +R 00 00 06 00 +T FF 07 +R 00 00 06 00 diff --git a/doug/src/ccpb03.s b/doug/src/ccpb03.s new file mode 100755 index 00000000..67ddec45 --- /dev/null +++ b/doug/src/ccpb03.s @@ -0,0 +1,1345 @@ + .title ccpb03.s derived from ccpb03.asm + .sbttl by Douglas Goodall 5/16/2011 dwg + + .module ccpb03 + .optsdcc -mz80 + +;-------------------------------------------------------- +; Public variables in this module +;-------------------------------------------------------- + .globl _ccp +;-------------------------------------------------------- +; special function registers +;-------------------------------------------------------- +;-------------------------------------------------------- +; ram data +;-------------------------------------------------------- + .area _DATA +;-------------------------------------------------------- +; overlayable items in ram +;-------------------------------------------------------- + .area _OVERLAY +;-------------------------------------------------------- +; external initialized ram data +;-------------------------------------------------------- +;-------------------------------------------------------- +; global & static initialisations +;-------------------------------------------------------- + .area _HOME + .area _GSINIT + .area _GSFINAL + .area _GSINIT +;-------------------------------------------------------- +; Home +;-------------------------------------------------------- + .area _HOME + .area _HOME +;-------------------------------------------------------- +; code +;-------------------------------------------------------- + +; .area _CODE + .area _CCPB03 + +_ccp_start:: +_ccp: + +MON = 1 ;ADD THE CCP MON COMMAND +USRDSP = 1 ;SHOW THE USER NUMBER +CHKU0B = 1 ;CHECK FOR TRANSIENTS ON USER 0 TOO +ENDFIL = 1 ;FILE FULL CCP SIZE +; +;************************************************************** +;* +;* C C P - C O N S O L E C O M M A N D P R O C E S S O R +;* +;************************************************************** +;* +IOBYTE = 3 ; I/O DEFINITION BYTE. +TDRIVE = 4 ; CURRENT DRIVE NAME AND USER NUMBER. +ENTRY = 5 ; ENTRY POINT FOR THE CP/M BDOS. +TFCB = 0x5C ; DEFAULT FILE CONTROL BLOCK. +TBUFF = 0x80 ; I/O BUFFER AND COMMAND LINE STORAGE. +TBASE = 0x0100 ; TRANSIANT PROGRAM STORAGE AREA. +MONADR = 0x0FC00 ;MONITOR PROGRAM +; +; SET CONTROL CHARACTER .EQUATES. +; +CNTRLC = 0x03 ; CONTROL-C +CNTRLE = 0x05 ; CONTROL-E +BS = 0x08 ; BACKSPACE +TAB = 0x09 ; TAB +LF = 0x0A ; LINE FEED +FF = 0x0C ; FORM FEED +CR = 0x0D ; CARRIAGE RETURN +CNTRLP = 0x10 ; CONTROL-P +CNTRLR = 0x12 ; CONTROL-R +CNTRLS = 0x13 ; CONTROL-S +CNTRLU = 0x15 ; CONTROL-U +CNTRLX = 0x18 ; CONTROL-X +CNTRLZ = 0x1A ; CONTROL-Z (END-OF-FILE MARK) +ASTERICK = 0x2A +COLON = 0x3A +LESSTHAN = 0x3C +ASCSPACE = 0x20 ; SPACE +PERIOD = 0x2e ; PERIOD +EQUAL = 0x3D +GREATERTHAN = 0x3E +QUESTION = 0x3F ;QUESTION MARK +UNDERSCORE = 0x5F +LCURLY = 0x7B ; { +DEL = 0x7F ; RUBOUT +; +; SET ORIGIN FOR CP/M +; + +NK = 59 ;SYSTEM SIZE +BASE = (NK*1024)-0x5000 +CCPO = BASE+0x3400 ;CCP ORIGIN +BDOSO = BASE+0x3C00 ;BDOS ORIGIN +BIOSO = BASE+0x4A00 ;BIOS ORIGIN + +;dwg; .ORG CCPO +; +CBASE: JP COMMAND ; EXECUTE COMMAND PROCESSOR (CCP). + JP CLEARBUF ; ENTRY TO EMPTY INPUT BUFFER BEFORE STARTING CCP. + +; +; STANDARD CP/M CCP INPUT BUFFER. FORMAT IS (MAX LENGTH), +; (ACTUAL LENGTH), (CHAR #1), (CHAR #2), (CHAR #3), ETC. +; +INBUFF: .DB 127 ; LENGTH OF INPUT BUFFER. + +; N8VEM - if add any text after this point, change .DB 0 below to length +; and put a 0 after the text, and delete the same number of zeros after the dig +; so that inpoint ends up at the same spot +; INBUFF+1 is cleared on the next warm boot, so only runs once. + .DB 0 ;CURRENT LENGTH OF CONTENTS. + + +; .DB 17 ; Autoboot length of string +; .DB "SUPERSUB AUTOEXEC" +; .DB 0 ; zero at end + + + .ascii "COPYRIGHT" + .ascii " 1979 (C) BY " + .ascii "DIGITAL RESEARCH " + .ascii " " + +;dwg; .ORG INBUFF+128 +;dwg; becausje org's are not allowed in rel areas, it has been +; replaced with the following array of .db's to achieve the +; same purpose + .db 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 + .db 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 + .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + .db 0,0 + +;; s/b d086 here + +INPOINT:.DW INBUFF+2 ; INPUT LINE POINTER +NAMEPNT:.DW 0 ; INPUT LINE POINTER USED FOR ERROR MESSAGE. POINTS TO +; ;START OF NAME IN ERROR. +; +; ROUTINE TO PRINT (A) ON THE CONSOLE. ALL REGISTERS USED. +; +PRINT: LD E,A ; SETUP BDOS CALL. + LD C,#2 + JP ENTRY +; +; ROUTINE TO PRINT (A) ON THE CONSOLE AND TO SAVE (BC). +; +PRINTB: PUSH BC + CALL PRINT + POP BC + RET +; +; ROUTINE TO SEND A CARRIAGE RETURN, LINE FEED COMBINATION +; TO THE CONSOLE. +; +CRLF: LD A,#CR + CALL PRINTB + LD A,#LF + JP PRINTB +; +; ROUTINE TO SEND ONE SPACE TO THE CONSOLE AND SAVE (BC). +; +SPACE: LD A,#ASCSPACE + JP PRINTB +; +; ROUTINE TO PRINT CHARACTER STRING POINTED TO BE (BC) ON THE +; CONSOLE. IT MUST TERMINATE WITH A NULL BYTE. +; +PLINE: PUSH BC + CALL #CRLF + POP HL +PLINE2: LD A,(HL) + OR A + RET Z + INC HL + PUSH HL + CALL PRINT + POP HL + JP PLINE2 +; +; ROUTINE TO RESET THE DISK SYSTEM. +; +RESDSK: LD C,#13 + JP ENTRY +; +; ROUTINE TO SELECT DISK (A). +; +DSKSEL: LD E,A + LD C,#14 + JP ENTRY +; +; ROUTINE TO CALL BDOS AND SAVE THE RETURN CODE. THE ZERO +; FLAG IS SET ON A RETURN OF 0FFH. +; +ENTRY1: CALL ENTRY + LD (RTNCODE),A ; SAVE RETURN CODE. + INC A ; SET ZERO IF 0FFH RETURNED. + RET +; +; ROUTINE TO OPEN A FILE. (DE) MUST POINT TO THE FCB. +; +OPEN: LD C,#15 + JP ENTRY1 +; +; ROUTINE TO OPEN FILE AT (FCB). +; +OPENFCB:XOR A ; CLEAR THE RECORD NUMBER BYTE AT FCB+32 + LD (FCB+32),A + LD DE,#FCB + JP OPEN +; +; ROUTINE TO CLOSE A FILE. (DE) POINTS TO FCB. +; +CLOSE: LD C,#16 + JP ENTRY1 +; +; ROUTINE TO SEARCH FOR THE FIRST FILE WITH AMBIGUEOUS NAME +; (DE). +; +SRCHFST:LD C,#17 + JP ENTRY1 +; +; SEARCH FOR THE NEXT AMBIGEOUS FILE NAME. +; +SRCHNXT:LD C,#18 + JP ENTRY1 +; +; SEARCH FOR FILE AT (FCB). +; +SRCHFCB:LD DE,#FCB + JP SRCHFST +; +; ROUTINE TO DELETE A FILE POINTED TO BY (DE). +; +DELETE: LD C,#19 + JP ENTRY +; +; ROUTINE TO CALL THE BDOS AND SET THE ZERO FLAG IF A ZERO +; STATUS IS RETURNED. +; +ENTRY2: CALL ENTRY + OR A ; SET ZERO FLAG IF APPROPRIATE. + RET +; +; ROUTINE TO READ THE NEXT RECORD FROM A S.EQUENTIAL FILE. +; (DE) POINTS TO THE FCB. +; +RDREC: LD C,#20 + JP ENTRY2 +; +; ROUTINE TO READ FILE AT (FCB). +; +READFCB:LD DE,#FCB + JP RDREC +; +; ROUTINE TO WRITE THE NEXT RECORD OF A S.EQUENTIAL FILE. +; (DE) POINTS TO THE FCB. +; +WRTREC: LD C,#21 + JP ENTRY2 +; +; ROUTINE TO CREATE THE FILE POINTED TO BY (DE). +; +CREATE: LD C,#22 + JP ENTRY1 +; +; ROUTINE TO RENAME THE FILE POINTED TO BY (DE). NOTE THAT +; THE NEW NAME STARTS AT (DE+16). +; +RENAM: LD C,#23 + JP ENTRY +; +; GET THE CURRENT USER CODE. +; +GETUSR: LD E,#0x0FF +; +; ROUTNE TO GET OR SET THE CURRENT USER CODE. +; IF (E) IS FF THEN THIS IS A GET, ELSE IT IS A SET. +; +GETSETUC: + LD C,#32 + JP ENTRY +; +; ROUTINE TO SET THE CURRENT DRIVE BYTE AT (TDRIVE). +; +SETCDRV:CALL GETUSR ; GET USER NUMBER + ADD A,A ; AND SHIFT INTO THE UPPER 4 BITS. + ADD A,A + ADD A,A + ADD A,A + LD HL,#CDRIVE ; NOW ADD IN THE CURRENT DRIVE NUMBER. + OR (HL) + LD (TDRIVE),A ; AND SAVE. + RET +; +; MOVE CURRENTLY ACTIVE DRIVE DOWN TO (TDRIVE). +; +MOVECD: LD A,(CDRIVE) + LD (TDRIVE),A + RET +; +; ROUTINE TO CONVERT (A) INTO UPPER CASE ASCII. ONLY LETTERS +; ARE AFFECTED. +; +UPPER: CP #0x41 ; CHECK FOR LETTERS IN THE RANGE OF 'A' TO 'Z'. + RET C + CP #LCURLY + RET NC + AND #0x5F ; CONVERT IT IF FOUND. + RET +; +; ROUTINE TO GET A LINE OF INPUT. WE MUST CHECK TO SEE IF THE +; USER IS IN (BATCH) MODE. IF SO, THEN READ THE INPUT FROM FILE +; ($$$.SUB). AT THE END, RESET TO CONSOLE INPUT. +; +GETINP: LD A,(BATCH) ; IF =0, THEN USE CONSOLE INPUT. + OR A + JP Z,GETINP1 +; +; USE THE SUBMIT FILE ($$$.SUB) WHICH IS PREPARED BY A +; SUBMIT RUN. IT MUST BE ON DRIVE (A) AND IT WILL BE DELETED +; IF AND ERROR OCCURES (LIKE EOF). +; + LD A,(CDRIVE) ; SELECT DRIVE 0 IF NEED BE. + OR A + LD A,#0 ; ALWAYS USE DRIVE A FOR SUBMIT. + CALL NZ,DSKSEL ; SELECT IT IF R.EQUIRED. + LD DE,#BATCHFCB + CALL OPEN ; LOOK FOR IT. + JP Z,GETINP1 ; IF NOT THERE, USE NORMAL INPUT. + LD A,(BATCHFCB+15) ; GET LAST RECORD NUMBER+1. + DEC A + LD (BATCHFCB+32),A + LD DE,#BATCHFCB + CALL RDREC ; READ LAST RECORD. + JP NZ,GETINP1 ; QUIT ON END OF FILE. +; +; MOVE THIS RECORD INTO INPUT BUFFER. +; + LD DE,#INBUFF+1 + LD HL,#TBUFF ; DATA WAS READ INTO BUFFER HERE. + LD B,#128 ; ALL 128 CHARACTERS MAY BE USED. + CALL HL2DE ; (HL) TO (DE), (B) BYTES. + LD HL,#BATCHFCB+14 + LD (HL),#0 ; ZERO OUT THE 'S2' BYTE. + INC HL ; AND DECREMENT THE RECORD COUNT. + DEC (HL) + LD DE,#BATCHFCB ; CLOSE THE BATCH FILE NOW. + CALL CLOSE + JP Z,GETINP1 ; QUIT ON AN ERROR. + LD A,(CDRIVE) ; RE-SELECT PREVIOUS DRIVE IF NEED BE. + OR A + CALL NZ,DSKSEL ; DON'T DO NEEDLESS SELECTS. +; +; PRINT LINE JUST READ ON CONSOLE. +; + LD HL,#INBUFF+2 + CALL PLINE2 + CALL CHKCON ; CHECK CONSOLE, QUIT ON A KEY. + JP Z,GETINP2 ; JUMP IF NO KEY IS PRESSED. +; +; TERMINATE THE SUBMIT JOB ON ANY KEYBOARD INPUT. DELETE THIS +; FILE SUCH THAT IT IS NOT RE-STARTED AND JUMP TO NORMAL KEYBOARD +; INPUT SECTION. +; + CALL DELBATCH ; DELETE THE BATCH FILE. + JP CMMND1 ; AND RESTART COMMAND INPUT. +; +; GET HERE FOR NORMAL KEYBOARD INPUT. DELETE THE SUBMIT FILE +; INCASE THERE WAS ONE. +; +GETINP1:CALL DELBATCH ; DELETE FILE ($$$.SUB). + CALL SETCDRV ; RESET ACTIVE DISK. + LD C,#10 ; GET LINE FROM CONSOLE DEVICE. + LD DE,#INBUFF + CALL ENTRY + CALL MOVECD ; RESET CURRENT DRIVE (AGAIN). +; +; CONVERT INPUT LINE TO UPPER CASE. +; +GETINP2:LD HL,#INBUFF+1 + LD B,(HL) ; (B)=CHARACTER COUNTER. +GETINP3:INC HL + LD A,B ; END OF THE LINE? + OR A + JP Z,GETINP4 + LD A,(HL) ; CONVERT TO UPPER CASE. + CALL UPPER + LD (HL),A + DEC B ; ADJUST CHARACTER COUNT. + JP GETINP3 +GETINP4:LD (HL),A ; ADD TRAILING NULL. + LD HL,#INBUFF+2 + LD (INPOINT),HL ; RESET INPUT LINE POINTER. + RET +; +; ROUTINE TO CHECK THE CONSOLE FOR A KEY PRESSED. THE ZERO +; FLAG IS SET IS NONE, ELSE THE CHARACTER IS RETURNED IN (A). +; +CHKCON: LD C,#11 ; CHECK CONSOLE. + CALL ENTRY + OR A + RET Z ; RETURN IF NOTHING. + LD C,#1 ; ELSE GET CHARACTER. + CALL ENTRY + OR A ; CLEAR ZERO FLAG AND RETURN. + RET +; +; ROUTINE TO GET THE CURRENTLY ACTIVE DRIVE NUMBER. +; +GETDSK: LD C,#25 + JP ENTRY +; +; SET THE STABDARD DMA ADDRESS. +; +STDDMA: LD DE,#TBUFF +; +; ROUTINE TO SET THE DMA ADDRESS TO (DE). +; +DMASET: LD C,#26 + JP ENTRY +; +; DELETE THE BATCH FILE CREATED BY SUBMIT. +; +DELBATCH: + LD HL,#BATCH ; IS BATCH ACTIVE? + LD A,(HL) + OR A + RET Z + LD (HL),#0 ; YES, DE-ACTIVATE IT. + XOR A + CALL DSKSEL ; SELECT DRIVE 0 FOR SURE. + LD DE,#BATCHFCB ; AND DELETE THIS FILE. + CALL DELETE + LD A,(CDRIVE) ; RESET CURRENT DRIVE. + JP DSKSEL +; +; PRINT BACK FILE NAME WITH A '?' TO INDICATE A SYNTAX ERROR. +; +SYNERR: CALL CRLF ; END CURRENT LINE. + LD HL,(NAMEPNT) ; THIS POINTS TO NAME IN ERROR. +SYNERR1:LD A,(HL) ; PRINT IT UNTIL A SPACE OR NULL IS FOUND. + CP #ASCSPACE + JP Z,SYNERR2 + OR A + JP Z,SYNERR2 + PUSH HL + CALL PRINT + POP HL + INC HL + JP SYNERR1 +SYNERR2:LD A,#QUESTION ; ADD TRAILING '?'. + CALL PRINT + CALL CRLF + CALL DELBATCH ; DELETE ANY BATCH FILE. + JP CMMND1 ; AND RESTART FROM CONSOLE INPUT. +; +; CHECK CHARACTER AT (DE) FOR LEGAL COMMAND INPUT. NOTE THAT THE +; ZERO FLAG IS SET IF THE CHARACTER IS A DELIMITER. +; +CHECK: LD A,(DE) + OR A + RET Z + CP #ASCSPACE ; CONTROL CHARACTERS ARE NOT LEGAL HERE. + JP C,SYNERR + RET Z ; CHECK FOR VALID DELIMITER. + CP #EQUAL + RET Z + CP #UNDERSCORE + RET Z + CP #PERIOD + RET Z + CP #COLON + RET Z + CP #0x3b + RET Z + CP #LESSTHAN + RET Z + CP #GREATERTHAN + RET Z + RET +; +; GET THE NEXT NON-BLANK CHARACTER FROM (DE). +; +NONBLANK: + LD A,(DE) + OR A ; STRING ENDS WITH A NULL. + RET Z + CP #ASCSPACE + RET NZ + INC DE + JP NONBLANK +; +; ADD (HL)=(HL)+(A) +; +ADDHL: ADD A,L + LD L,A + RET NC ; TAKE CARE OF ANY CARRY. + INC H + RET +; +; CONVERT THE FIRST NAME IN (FCB). +; +CONVFST:LD A,#0 +; +; FORMAT A FILE NAME (CONVERT * TO '?', ETC.). ON RETURN, +; (A)=0 IS AN UNAMBIGEOUS NAME WAS SPECIFIED. ENTER WITH (A) .EQUAL TO +; THE POSITION WITHIN THE FCB FOR THE NAME (EITHER 0 OR 16). +; +CONVERT:LD HL,#FCB + CALL ADDHL + PUSH HL + PUSH HL + XOR A + LD (CHGDRV),A ; INITIALIZE DRIVE CHANGE FLAG. + LD HL,(INPOINT) ; SET (HL) AS POINTER INTO INPUT LINE. + EX DE,HL + CALL NONBLANK ; GET NEXT NON-BLANK CHARACTER. + EX DE,HL + LD (NAMEPNT),HL ; SAVE POINTER HERE FOR ANY ERROR MESSAGE. + EX DE,HL + POP HL + LD A,(DE) ; GET FIRST CHARACTER. + OR A + JP Z,CONVRT1 + SBC A,#0x41-1 ; MIGHT BE A DRIVE NAME, CONVERT TO BINARY. + LD B,A ; AND SAVE. + INC DE ; CHECK NEXT CHARACTER FOR A ':'. + LD A,(DE) + CP #COLON + JP Z,CONVRT2 + DEC DE ; NOPE, MOVE POINTER BACK TO THE START OF THE LINE. +CONVRT1:LD A,(CDRIVE) + LD (HL),A + JP CONVRT3 +CONVRT2:LD A,B + LD (CHGDRV),A ; SET CHANGE IN DRIVES FLAG. + LD (HL),B + INC DE +; +; CONVERT THE BASIC FILE NAME. +; +CONVRT3:LD B,#8 +CONVRT4:CALL CHECK + JP Z,CONVRT8 + INC HL + CP #ASTERICK ; NOTE THAT AN '*' WILL FILL THE REMAINING + JP NZ,CONVRT5 ; FIELD WITH '?'. + LD (HL),#QUESTION + JP CONVRT6 +CONVRT5:LD (HL),A + INC DE +CONVRT6:DEC B + JP NZ,CONVRT4 +CONVRT7:CALL CHECK ; GET NEXT DELIMITER. + JP Z,GETEXT + INC DE + JP CONVRT7 +CONVRT8:INC HL ; BLANK FILL THE FILE NAME. + LD (HL),#ASCSPACE + DEC B + JP NZ,CONVRT8 +; +; GET THE EXTENSION AND CONVERT IT. +; +GETEXT: LD B,#3 + CP #PERIOD + JP NZ,GETEXT5 + INC DE +GETEXT1:CALL CHECK + JP Z,GETEXT5 + INC HL + CP #ASTERICK + JP NZ,GETEXT2 + LD (HL),#QUESTION + JP GETEXT3 +GETEXT2:LD (HL),A + INC DE +GETEXT3:DEC B + JP NZ,GETEXT1 +GETEXT4:CALL CHECK + JP Z,GETEXT6 + INC DE + JP GETEXT4 +GETEXT5:INC HL + LD (HL),#ASCSPACE + DEC B + JP NZ,GETEXT5 +GETEXT6:LD B,#3 +GETEXT7:INC HL + LD (HL),#0 + DEC B + JP NZ,GETEXT7 + EX DE,HL + LD (INPOINT),HL ; SAVE INPUT LINE POINTER. + POP HL +; +; CHECK TO SEE IF THIS IS AN AMBIGEOUS FILE NAME SPECIFICATION. +; SET THE (A) REGISTER TO NON ZERO IF IT IS. +; + LD BC,#11 ; SET NAME LENGTH. +GETEXT8:INC HL + LD A,(HL) + CP #QUESTION ; ANY QUESTION MARKS? + JP NZ,GETEXT9 + INC B ; COUNT THEM. +GETEXT9:DEC C + JP NZ,GETEXT8 + LD A,B + OR A + RET +; +; CP/M COMMAND TABLE. NOTE COMMANDS CAN BE EITHER 3 OR 4 CHARACTERS LONG. +; + .if MON +NUMCMDS = 7 ; NUMBER OF COMMANDS + .else +NUMCMDS = 6 ; NUMBER OF COMMANDS + .endif + +CMDTBL: .ascii "DIR " + .ascii "ERA " + .ascii "TYPE" + .ascii "SAVE" + .ascii "REN " + .ascii "USER" + .if MON + .ascii "MON " + .ENDIF + +CMDADR: .DW DIRECT + .DW ERASE + .DW TYPE + .DW SAVE + .DW RENAME + .DW USER + .IF MON + .DW MONITOR + .ENDIF + .DW UNKNOWN +; +; SEARCH THE COMMAND TABLE FOR A MATCH WITH WHAT HAS JUST +; BEEN ENTERED. IF A MATCH IS FOUND, THEN WE JUMP TO THE +; PROPER SECTION. ELSE JUMP TO (UNKNOWN). +; ON RETURN, THE (C) REGISTER IS SET TO THE COMMAND NUMBER +; THAT MATCHED (OR NUMCMDS+1 IF NO MATCH). +; +SEARCH: LD HL,#CMDTBL + LD C,#0 +SEARCH1:LD A,C + CP #NUMCMDS ; THIS COMMANDS EXISTS. + RET NC + LD DE,#FCB+1 ; CHECK THIS ONE. + LD B,#4 ; MAX COMMAND LENGTH. +SEARCH2:LD A,(DE) + CP (HL) + JP NZ,SEARCH3 ; NOT A MATCH. + INC DE + INC HL + DEC B + JP NZ,SEARCH2 + LD A,(DE) ; ALLOW A 3 CHARACTER COMMAND TO MATCH. + CP #ASCSPACE + JP NZ,SEARCH4 + LD A,C ; SET RETURN REGISTER FOR THIS COMMAND. + RET +SEARCH3:INC HL + DEC B + JP NZ,SEARCH3 +SEARCH4:INC C + JP SEARCH1 +; +; SET THE INPUT BUFFER TO EMPTY AND THEN START THE COMMAND +; PROCESSOR (CCP). +; +CLEARBUF: + XOR A + LD (INBUFF+1),A ; SECOND BYTE IS ACTUAL LENGTH. +COMMAND:LD SP,#CCPSTACK ; SETUP STACK AREA. + PUSH BC ; NOTE THAT (C) SHOULD BE .EQUAL TO: + LD A,C ; (UUUUDDDD) WHERE 'UUUU' IS THE USER NUMBER + RRA ; AND 'DDDD' IS THE DRIVE NUMBER. + RRA + RRA + RRA + AND #0x0F ; ISOLATE THE USER NUMBER. + LD E,A + CALL GETSETUC ; AND SET IT. + CALL RESDSK ; RESET THE DISK SYSTEM. + LD (BATCH),A ; CLEAR BATCH MODE FLAG. + POP BC + LD A,C + AND #0x0F ; ISOLATE THE DRIVE NUMBER. + LD (CDRIVE),A ; AND SAVE. + CALL DSKSEL ; ...AND SELECT. + LD A,(INBUFF+1) + OR A ; ANYTHING IN INPUT BUFFER ALREADY? + JP NZ,CMMND2 ; YES, WE JUST PROCESS IT. +; +; ENTRY POINT TO GET A COMMAND LINE FROM THE CONSOLE. +; +CMMND1: LD SP,#CCPSTACK ; SET STACK STRAIGHT. + CALL CRLF ; START A NEW LINE ON THE SCREEN. + CALL GETDSK ; GET CURRENT DRIVE. + ADD A,#0x41 + CALL PRINT ; PRINT CURRENT DRIVE. + .IF USRDSP + CALL GETUSR ;GET CURRENT USER NUMBER + CP #10 ;TWO DIGITS? + JR C,CMMND3 ;NO + LD A,#0x31 ;PRINT LEADING '1' + CALL PRINT + CALL GETUSR ;GET CURRENT USER NUMBER + SUB #10 ;SUBTRACT 10 +CMMND3: ADD A,#0x30 + CALL PRINT + .ENDIF + LD A,#GREATERTHAN + CALL PRINT ; AND ADD PROMPT. + CALL GETINP ; GET LINE FROM USER. +; +; PROCESS COMMAND LINE HERE. +; +CMMND2: LD DE,#TBUFF + CALL DMASET ; SET STANDARD DMA ADDRESS. + CALL GETDSK + LD (CDRIVE),A ; SET CURRENT DRIVE. + CALL CONVFST ; CONVERT NAME TYPED IN. + CALL NZ,SYNERR ; WILD CARDS ARE NOT ALLOWED. + LD A,(CHGDRV) ; IF A CHANGE IN DRIVES WAS INDICATED, + OR A ; THEN TREAT THIS AS AN UNKNOWN COMMAND + JP NZ,UNKNOWN ; WHICH GETS EXECUTED. + CALL SEARCH ; ELSE SEARCH COMMAND TABLE FOR A MATCH. +; +; NOTE THAT AN UNKNOWN COMMAND RETURNS +; WITH (A) POINTING TO THE LAST ADDRESS +; IN OUR TABLE WHICH IS (UNKNOWN). +; + LD HL,#CMDADR ; NOW, LOOK THRU OUR ADDRESS TABLE FOR COMMAND (A). + LD E,A ; SET (DE) TO COMMAND NUMBER. + LD D,#0 + ADD HL,DE + ADD HL,DE ; (HL)=(CMDADR)+2*(COMMAND NUMBER). + LD A,(HL) ; NOW PICK OUT THIS ADDRESS. + INC HL + LD H,(HL) + LD L,A + JP (HL) ; NOW EXECUTE IT. +; +; READ ERROR WHILE TYPEING A FILE. +; +RDERROR:LD BC,#RDERR + JP PLINE +RDERR: .asciz "Read Error" + +; +; R.EQUIRED FILE WAS NOT LOCATED. +; +NONE: LD BC,#NOFILE + JP PLINE +NOFILE: .asciz "No File" +; +; DECODE A COMMAND OF THE FORM 'A>FILENAME NUMBER{ FILENAME}. +; NOTE THAT A DRIVE SPECIFIER IS NOT ALLOWED ON THE FIRST FILE +; NAME. ON RETURN, THE NUMBER IS IN REGISTER (A). ANY ERROR +; CAUSES 'FILENAME?' TO BE PRINTED AND THE COMMAND IS ABORTED. +; +DECODE: CALL CONVFST ; CONVERT FILENAME. + LD A,(CHGDRV) ; DO NOT ALLOW A DRIVE TO BE SPECIFIED. + OR A + JP NZ,SYNERR + LD HL,#FCB+1 ; CONVERT NUMBER NOW. + LD BC,#11 ; (B)=SUM REGISTER, (C)=MAX DIGIT COUNT. +DECODE1:LD A,(HL) + CP #ASCSPACE ; A SPACE TERMINATES THE NUMERAL. + JP Z,DECODE3 + INC HL + SUB #0x30 ; MAKE BINARY FROM ASCII. + CP #10 ; LEGAL DIGIT? + JP NC,SYNERR + LD D,A ; YES, SAVE IT IN (D). + LD A,B ; COMPUTE (B)=(B)*10 AND CHECK FOR OVERFLOW. + AND #0x0E0 + JP NZ,SYNERR + LD A,B + RLCA + RLCA + RLCA ; (A)=(B)*8 + ADD A,B ; .......*9 + JP C,SYNERR + ADD A,B ; .......*10 + JP C,SYNERR + ADD A,D ; ADD IN NEW DIGIT NOW. +DECODE2:JP C,SYNERR + LD B,A ; AND SAVE RESULT. + DEC C ; ONLY LOOK AT 11 DIGITS. + JP NZ,DECODE1 + RET +DECODE3:LD A,(HL) ; SPACES MUST FOLLOW (WHY?). + CP #ASCSPACE + JP NZ,SYNERR + INC HL +DECODE4:DEC C + JP NZ,DECODE3 + LD A,B ; SET (A)=THE NUMERIC VALUE ENTERED. + RET +; +; MOVE 3 BYTES FROM (HL) TO (DE). NOTE THAT THERE IS ONLY +; ONE REFERENCE TO THIS AT (A2D5H). +; +MOVE3: LD B,#3 +; +; MOVE (B) BYTES FROM (HL) TO (DE). +; +HL2DE: LD A,(HL) + LD (DE),A + INC HL + INC DE + DEC B + JP NZ,HL2DE + RET +; +; COMPUTE (HL)=(TBUFF)+(A)+(C) AND GET THE BYTE THAT'S HERE. +; +EXTRACT:LD HL,#TBUFF + ADD A,C + CALL ADDHL + LD A,(HL) + RET +; +; CHECK DRIVE SPECIFIED. IF IT MEANS A CHANGE, THEN THE NEW +; DRIVE WILL BE SELECTED. IN ANY CASE, THE DRIVE BYTE OF THE +; FCB WILL BE SET TO NULL (MEANS USE CURRENT DRIVE). +; +DSELECT:XOR A ; NULL OUT FIRST BYTE OF FCB. + LD (FCB),A + LD A,(CHGDRV) ; A DRIVE CHANGE INDICATED? + OR A + RET Z + DEC A ; YES, IS IT THE SAME AS THE CURRENT DRIVE? + LD HL,#CDRIVE + CP (HL) + RET Z + JP DSKSEL ; NO. SELECT IT THEN. +; +; CHECK THE DRIVE SELECTION AND RESET IT TO THE PREVIOUS +; DRIVE IF IT WAS CHANGED FOR THE PRECEEDING COMMAND. +; +RESETDR:LD A,(CHGDRV) ; DRIVE CHANGE INDICATED? + OR A + RET Z + DEC A ; YES, WAS IT A DIFFERENT DRIVE? + LD HL,#CDRIVE + CP (HL) + RET Z + LD A,(CDRIVE) ; YES, RE-SELECT OUR OLD DRIVE. + JP DSKSEL + + .IF MON +; +;************************************************************** +;* +;* M O N I T O R C O M M A N D +;* +;************************************************************** +; +MONITOR: JP MONADR + .ENDIF + +; +;************************************************************** +;* +;* D I R E C T O R Y C O M M A N D +;* +;************************************************************** +; +DIRECT: CALL CONVFST ; CONVERT FILE NAME. + CALL DSELECT ; SELECT INDICATED DRIVE. + LD HL,#FCB+1 ; WAS ANY FILE INDICATED? + LD A,(HL) + CP #ASCSPACE + JP NZ,DIRECT2 + LD B,#11 ; NO. FILL FIELD WITH '?' - SAME AS *.*. +DIRECT1:LD (HL),#QUESTION + INC HL + DEC B + JP NZ,DIRECT1 +DIRECT2:LD E,#0 ; SET INITIAL CURSOR POSITION. + PUSH DE + CALL SRCHFCB ; GET FIRST FILE NAME. + CALL Z,NONE ; NONE FOUND AT ALL? +DIRECT3:JP Z,DIRECT9 ; TERMINATE IF NO MORE NAMES. + LD A,(RTNCODE) ; GET FILE'S POSITION IN SEGMENT (0-3). + RRCA + RRCA + RRCA + AND #0x60 ; (A)=POSITION*32 + LD C,A + LD A,#10 + CALL EXTRACT ; EXTRACT THE TENTH ENTRY IN FCB. + RLA ; CHECK SYSTEM FILE STATUS BIT. + JP C,DIRECT8 ; WE DON'T LIST THEM. + POP DE + LD A,E ; BUMP NAME COUNT. + INC E + PUSH DE + AND #3 ; AT END OF LINE? + PUSH AF + JP NZ,DIRECT4 + CALL CRLF ; YES, END THIS LINE AND START ANOTHER. + PUSH BC + CALL GETDSK ; START LINE WITH ('A:'). + POP BC + ADD A,#0x41 + CALL PRINTB + LD A,#COLON + CALL PRINTB + JP DIRECT5 +DIRECT4:CALL SPACE ; ADD SEPERATOR BETWEEN FILE NAMES. + LD A,#COLON + CALL PRINTB +DIRECT5:CALL SPACE + LD B,#1 ; 'EXTRACT' EACH FILE NAME CHARACTER AT A TIME. +DIRECT6:LD A,B + CALL EXTRACT + AND #0x7F ; STRIP BIT 7 (STATUS BIT). + CP #ASCSPACE ; ARE WE AT THE END OF THE NAME? + JP NZ,DRECT65 + POP AF ; YES, DON'T PRINT SPACES AT THE END OF A LINE. + PUSH AF + CP #3 + JP NZ,DRECT63 + LD A,#9 ; FIRST CHECK FOR NO EXTENSION. + CALL EXTRACT + AND #0x7F + CP #ASCSPACE + JP Z,DIRECT7 ; DON'T PRINT SPACES. +DRECT63:LD A,#ASCSPACE ; ELSE PRINT THEM. +DRECT65:CALL PRINTB + INC B ; BUMP TO NEXT CHARACTER PSOITION. + LD A,B + CP #12 ; END OF THE NAME? + JP NC,DIRECT7 + CP #9 ; NOPE, STARTING EXTENSION? + JP NZ,DIRECT6 + CALL SPACE ; YES, ADD SEPERATING SPACE. + JP DIRECT6 +DIRECT7:POP AF ; GET THE NEXT FILE NAME. +DIRECT8:CALL CHKCON ; FIRST CHECK CONSOLE, QUIT ON ANYTHING. + JP NZ,DIRECT9 + CALL SRCHNXT ; GET NEXT NAME. + JP DIRECT3 ; AND CONTINUE WITH OUR LIST. +DIRECT9:POP DE ; RESTORE THE STACK AND RETURN TO COMMAND LEVEL. + JP GETBACK +; +;************************************************************** +;* +;* E R A S E C O M M A N D +;* +;************************************************************** +; +ERASE: CALL CONVFST ; CONVERT FILE NAME. + CP #11 ; WAS '*.*' ENTERED? + JP NZ,ERASE1 + LD BC,#YESNO ; YES, ASK FOR CONFIRMATION. + CALL PLINE + CALL GETINP + LD HL,#INBUFF+1 + DEC (HL) ; MUST BE EXACTLY 'Y'. + JP NZ,CMMND1 + INC HL + LD A,(HL) + CP #0x59 + JP NZ,CMMND1 + INC HL + LD (INPOINT),HL ; SAVE INPUT LINE POINTER. +ERASE1: CALL DSELECT ; SELECT DESIRED DISK. + LD DE,#FCB + CALL DELETE ; DELETE THE FILE. + INC A + CALL Z,NONE ; NOT THERE? + JP GETBACK ; RETURN TO COMMAND LEVEL NOW. +YESNO: .asciz "All (Y/N)?" +; +;************************************************************** +;* +;* T Y P E C O M M A N D +;* +;************************************************************** +; +TYPE: CALL CONVFST ; CONVERT FILE NAME. + JP NZ,SYNERR ; WILD CARDS NOT ALLOWED. + CALL DSELECT ; SELECT INDICATED DRIVE. + CALL OPENFCB ; OPEN THE FILE. + JP Z,TYPE5 ; NOT THERE? + CALL CRLF ; OK, START A NEW LINE ON THE SCREEN. + LD HL,#NBYTES ; INITIALIZE BYTE COUNTER. + LD (HL),#0x0FF ; SET TO READ FIRST SECTOR. +TYPE1: LD HL,#NBYTES +TYPE2: LD A,(HL) ; HAVE WE WRITTEN THE ENTIRE SECTOR? + CP #128 + JP C,TYPE3 + PUSH HL ; YES, READ IN THE NEXT ONE. + CALL READFCB + POP HL + JP NZ,TYPE4 ; END OR ERROR? + XOR A ; OK, CLEAR BYTE COUNTER. + LD (HL),A +TYPE3: INC (HL) ; COUNT THIS BYTE. + LD HL,#TBUFF ; AND GET THE (A)TH ONE FROM THE BUFFER (TBUFF). + CALL ADDHL + LD A,(HL) + CP #CNTRLZ ; END OF FILE MARK? + JP Z,GETBACK + CALL PRINT ; NO, PRINT IT. + CALL CHKCON ; CHECK CONSOLE, QUIT IF ANYTHING READY. + JP NZ,GETBACK + JP TYPE1 +; +; GET HERE ON AN END OF FILE OR READ ERROR. +; +TYPE4: DEC A ; READ ERROR? + JP Z,GETBACK + CALL RDERROR ; YES, PRINT MESSAGE. +TYPE5: CALL RESETDR ; AND RESET PROPER DRIVE + JP SYNERR ; NOW PRINT FILE NAME WITH PROBLEM. +; +;************************************************************** +;* +;* S A V E C O M M A N D +;* +;************************************************************** +; +SAVE: CALL DECODE ; GET NUMERIC NUMBER THAT FOLLOWS SAVE. + PUSH AF ; SAVE NUMBER OF PAGES TO WRITE. + CALL CONVFST ; CONVERT FILE NAME. + JP NZ,SYNERR ; WILD CARDS NOT ALLOWED. + CALL DSELECT ; SELECT SPECIFIED DRIVE. + LD DE,#FCB ; NOW DELETE THIS FILE. + PUSH DE + CALL DELETE + POP DE + CALL CREATE ; AND CREATE IT AGAIN. + JP Z,SAVE3 ; CAN'T CREATE? + XOR A ; CLEAR RECORD NUMBER BYTE. + LD (FCB+32),A + POP AF ; CONVERT PAGES TO SECTORS. + LD L,A + LD H,#0 + ADD HL,HL ; (HL)=NUMBER OF SECTORS TO WRITE. + LD DE,#TBASE ; AND WE START FROM HERE. +SAVE1: LD A,H ; DONE YET? + OR L + JP Z,SAVE2 + DEC HL ; NOPE, COUNT THIS AND COMPUTE THE START + PUSH HL ; OF THE NEXT 128 BYTE SECTOR. + LD HL,#128 + ADD HL,DE + PUSH HL ; SAVE IT AND SET THE TRANSFER ADDRESS. + CALL DMASET + LD DE,#FCB ; WRITE OUT THIS SECTOR NOW. + CALL WRTREC + POP DE ; RESET (DE) TO THE START OF THE LAST SECTOR. + POP HL ; RESTORE SECTOR COUNT. + JP NZ,SAVE3 ; WRITE ERROR? + JP SAVE1 +; +; GET HERE AFTER WRITING ALL OF THE FILE. +; +SAVE2: LD DE,#FCB ; NOW CLOSE THE FILE. + CALL CLOSE + INC A ; DID IT CLOSE OK? + JP NZ,SAVE4 +; +; PRINT OUT ERROR MESSAGE (NO SPACE). +; +SAVE3: LD BC,#NOSPACE + CALL PLINE +SAVE4: CALL STDDMA ; RESET THE STANDARD DMA ADDRESS. + JP GETBACK + +NOSPACE: .asciz "No Space" +; +;************************************************************** +;* +;* R E N A M E C O M M A N D +;* +;************************************************************** +; +RENAME: CALL CONVFST ; CONVERT FIRST FILE NAME. + JP NZ,SYNERR ; WILD CARDS NOT ALLOWED. + LD A,(CHGDRV) ; REMEMBER ANY CHANGE IN DRIVES SPECIFIED. + PUSH AF + CALL DSELECT ; AND SELECT THIS DRIVE. + CALL SRCHFCB ; IS THIS FILE PRESENT? + JP NZ,RENAME6 ; YES, PRINT ERROR MESSAGE. + LD HL,#FCB ; YES, MOVE THIS NAME INTO SECOND SLOT. + LD DE,#FCB+16 + LD B,#16 + CALL HL2DE + LD HL,(INPOINT) ; GET INPUT POINTER. + EX DE,HL + CALL NONBLANK ; GET NEXT NON BLANK CHARACTER. + CP #EQUAL ; ONLY ALLOW AN '=' OR '_' SEPERATOR. + JP Z,RENAME1 + CP #ASCSPACE + JP NZ,RENAME5 +RENAME1:EX DE,HL + INC HL ; OK, SKIP SEPERATOR. + LD (INPOINT),HL ; SAVE INPUT LINE POINTER. + CALL CONVFST ; CONVERT THIS SECOND FILE NAME NOW. + JP NZ,RENAME5 ; AGAIN, NO WILD CARDS. + POP AF ; IF A DRIVE WAS SPECIFIED, THEN IT + LD B,A ; MUST BE THE SAME AS BEFORE. + LD HL,#CHGDRV + LD A,(HL) + OR A + JP Z,RENAME2 + CP B + LD (HL),B + JP NZ,RENAME5 ; THEY WERE DIFFERENT, ERROR. +RENAME2:LD (HL),B ; RESET AS PER THE FIRST FILE SPECIFICATION. + XOR A + LD (FCB),A ; CLEAR THE DRIVE BYTE OF THE FCB. +RENAME3:CALL SRCHFCB ; AND GO LOOK FOR SECOND FILE. + JP Z,RENAME4 ; DOESN'T EXIST? + LD DE,#FCB + CALL RENAM ; OK, RENAME THE FILE. + JP GETBACK +; +; PROCESS RENAME ERRORS HERE. +; +RENAME4:CALL NONE ; FILE NOT THERE. + JP GETBACK +RENAME5:CALL RESETDR ; BAD COMMAND FORMAT. + JP SYNERR +RENAME6:LD BC,#EXISTS ; DESTINATION FILE ALREADY EXISTS. + CALL PLINE + JP GETBACK +EXISTS: .asciz "File Exists" +; +;************************************************************** +;* +;* U S E R C O M M A N D +;* +;************************************************************** +; +USER: CALL DECODE ; GET NUMERIC VALUE FOLLOWING COMMAND. + CP #16 ; LEGAL USER NUMBER? + JP NC,SYNERR + LD E,A ; YES BUT IS THERE ANYTHING ELSE? + LD A,(FCB+1) + CP #ASCSPACE + JP Z,SYNERR ; YES, THAT IS NOT ALLOWED. + CALL GETSETUC ; OK, SET USER CODE. + JP GETBACK1 +; +;************************************************************** +;* +;* T R A N S I A N T P R O G R A M C O M M A N D +;* +;************************************************************** +; +UNKNOWN:LD A,(FCB+1) ; ANYTHING TO EXECUTE? + CP #ASCSPACE + JP NZ,UNKWN1 + LD A,(CHGDRV) ; NOPE, ONLY A DRIVE CHANGE? + OR A + JP Z,GETBACK1 ; NEITHER??? + DEC A + LD (CDRIVE),A ; OK, STORE NEW DRIVE. + CALL MOVECD ; SET (TDRIVE) ALSO. + CALL DSKSEL ; AND SELECT THIS DRIVE. + JP GETBACK1 ; THEN RETURN. +; +; HERE A FILE NAME WAS TYPED. PREPARE TO EXECUTE IT. +; +UNKWN1: LD DE,#FCB+9 ; AN EXTENSION SPECIFIED? + LD A,(DE) + CP #ASCSPACE + JP NZ,SYNERR ; YES, NOT ALLOWED. +UNKWN2: PUSH DE + CALL DSELECT ; SELECT SPECIFIED DRIVE. + POP DE + LD HL,#COMFILE ; SET THE EXTENSION TO 'COM'. LD HL,COMFILE + CALL MOVE3 ; move 3 bytes from (HL) to (DE) to add .COM + CALL OPENFCB ; AND OPEN THIS FILE. + JP NZ,UNKWNA ;GOT IT + .IF CHKU0B + LD E,#0 ;TRY USER 0, THIS DRIVE + CALL GETSETUC ; OK, SET USER CODE. + CALL OPENFCB + JP NZ,UNKWNA ;GOT IT + LD HL,#FCB ;SEE IF ON DRIVE B, USER 0 + LD (HL),#2 + CALL OPENFCB + JP Z,UNKWN9 ;NOPE + .ENDIF +; +; LOAD IN THE PROGRAM. +; +UNKWNA: LD HL,#TBASE ; STORE THE PROGRAM STARTING HERE. +UNKWN3: PUSH HL + EX DE,HL + CALL DMASET ; SET TRANSFER ADDRESS. + LD DE,#FCB ; AND READ THE NEXT RECORD. + CALL RDREC + JP NZ,UNKWN4 ; END OF FILE OR READ ERROR? + POP HL ; NOPE, BUMP POINTER FOR NEXT SECTOR. + LD DE,#128 + ADD HL,DE + LD DE,#CBASE ; ENOUGH ROOM FOR THE WHOLE FILE? + LD A,L + SUB E + LD A,H + SBC A,D + JP NC,UNKWN0 ; NO, IT CAN'T FIT. + JP UNKWN3 +; +; GET HERE AFTER FINISHED READING. +; +UNKWN4: POP HL + DEC A ; NORMAL END OF FILE? + JP NZ,UNKWN0 + CALL RESETDR ; YES, RESET PREVIOUS DRIVE. + CALL CONVFST ; CONVERT THE FIRST FILE NAME THAT FOLLOWS + LD HL,#CHGDRV ; COMMAND NAME. + PUSH HL + LD A,(HL) ; SET DRIVE CODE IN DEFAULT FCB. + LD (FCB),A + LD A,#16 ; PUT SECOND NAME 16 BYTES LATER. + CALL CONVERT ; CONVERT SECOND FILE NAME. + POP HL + LD A,(HL) ; AND SET THE DRIVE FOR THIS SECOND FILE. + LD (FCB+16),A + XOR A ; CLEAR RECORD BYTE IN FCB. + LD (FCB+32),A + LD DE,#TFCB ; MOVE IT INTO PLACE AT(005CH). + LD HL,#FCB + LD B,#33 + CALL HL2DE + LD HL,#INBUFF+2 ; NOW MOVE THE REMAINDER OF THE INPUT +UNKWN5: LD A,(HL) ; LINE DOWN TO (0080H). LOOK FOR A NON BLANK. + OR A ; OR A NULL. + JP Z,UNKWN6 + CP #ASCSPACE + JP Z,UNKWN6 + INC HL + JP UNKWN5 +; +; DO THE LINE MOVE NOW. IT ENDS IN A NULL BYTE. +; +UNKWN6: LD B,#0 ; KEEP A CHARACTER COUNT. + LD DE,#TBUFF+1 ; DATA GETS PUT HERE. +UNKWN7: LD A,(HL) ; MOVE IT NOW. + LD (DE),A + OR A + JP Z,UNKWN8 + INC B + INC HL + INC DE + JP UNKWN7 +UNKWN8: LD A,B ; NOW STORE THE CHARACTER COUNT. + LD (TBUFF),A + CALL CRLF ; CLEAN UP THE SCREEN. + CALL STDDMA ; SET STANDARD TRANSFER ADDRESS. + CALL SETCDRV ; RESET CURRENT DRIVE. + CALL TBASE ; AND EXECUTE THE PROGRAM. +; +; TRANSIANT PROGRAMS RETURN HERE (OR REBOOT). +; + LD SP,#BATCH ; SET STACK FIRST OFF. + CALL MOVECD ; MOVE CURRENT DRIVE INTO PLACE (TDRIVE). + CALL DSKSEL ; AND RESELECT IT. + JP CMMND1 ; BACK TO COMAND MODE. +; +; GET HERE IF SOME ERROR OCCURED. +; +UNKWN9: CALL RESETDR ; INPROPER FORMAT. + JP SYNERR +UNKWN0: LD BC,#BADLOAD ; READ ERROR OR WON'T FIT. + CALL PLINE + JP GETBACK +BADLOAD:.asciz "Bad Load" +COMFILE:.ascii "COM" ; COMMAND FILE EXTENSION. +; +; GET HERE TO RETURN TO COMMAND LEVEL. WE WILL RESET THE +; PREVIOUS ACTIVE DRIVE AND THEN EITHER RETURN TO COMMAND +; LEVEL DIRECTLY OR PRINT ERROR MESSAGE AND THEN RETURN. +; +GETBACK:CALL RESETDR ; RESET PREVIOUS DRIVE. +GETBACK1: + CALL CONVFST ; CONVERT FIRST NAME IN (FCB). + LD A,(FCB+1) ; IF THIS WAS JUST A DRIVE CHANGE R.EQUEST, + SUB #ASCSPACE ; MAKE SURE IT WAS VALID. + LD HL,#CHGDRV + OR (HL) + JP NZ,SYNERR + JP CMMND1 ; OK, RETURN TO COMMAND LEVEL. +; +; CCP STACK AREA. +; + .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +CCPSTACK: +;dwg; .EQU $ ;END OF CCP STACK AREA. + +; +; BATCH (OR SUBMIT) PROCESSING INFORMATION STORAGE. +; +BATCH: .DB 0 ; BATCH MODE FLAG (0=NOT ACTIVE). +BATCHFCB:.DB 0 + .ascii "$$$ SUB" + .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +; +; FILE CONTROL BLOCK SETUP BY THE CCP. +; +FCB: .DB 0 + .asciz " " + .DB 0,0,0,0 + + .asciz " " + .DB 0,0,0,0 + +RTNCODE:.DB 0 ; STATUS RETURNED FROM BDOS CALL. +CDRIVE: .DB 0 ; CURRENTLY ACTIVE DRIVE. +CHGDRV: .DB 0 ; CHANGE IN DRIVES FLAG (0=NO CHANGE). +NBYTES: .DW 0 ; BYTE COUNTER USED BY TYPE. + +;dwg; .IF ENDFIL +;dwg; .ORG CCPO+07FFH +;dwg; .DB 055H +;dwg; .ENDIF +;dwg; .END + + +_ccp_end:: + .area _CODE + .area _CABS diff --git a/doug/src/ccpb03.sym b/doug/src/ccpb03.sym new file mode 100755 index 00000000..3c421d12 --- /dev/null +++ b/doug/src/ccpb03.sym @@ -0,0 +1,83 @@ + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 1. +ccpb03.s derived from ccpb03.asm +Symbol Table + + .__.ABS.= 0000 G | 6 ADDHL 0243 R | ASCSPACE= 0020 + ASTERICK= 002A | 6 BADLOAD 0786 R | BASE = 9C00 + 6 BATCH 07B7 R | 6 BATCHFCB 07B8 R | BDOSO = D800 + BIOSO = E600 | BS = 0008 | 6 CBASE 0000 R + CCPO = D000 | 6 CCPSTACK 07B7 R | 6 CDRIVE 07FB R + 6 CHECK 021A R | 6 CHGDRV 07FC R | 6 CHKCON 01C0 R + CHKU0B = 0001 | 6 CLEARBUF 0350 R | 6 CLOSE 00D8 R + 6 CMDADR 0316 R | 6 CMDTBL 02FA R | 6 CMMND1 037A R + 6 CMMND2 03A6 R | 6 CMMND3 0399 R | CNTRLC = 0003 + CNTRLE = 0005 | CNTRLP = 0010 | CNTRLR = 0012 + CNTRLS = 0013 | CNTRLU = 0015 | CNTRLX = 0018 + CNTRLZ = 001A | COLON = 003A | 6 COMFILE 078F R + 6 COMMAND 0354 R | 6 CONVERT 024A R | 6 CONVFST 0248 R + 6 CONVRT1 0273 R | 6 CONVRT2 027A R | 6 CONVRT3 0280 R + 6 CONVRT4 0282 R | 6 CONVRT5 0293 R | 6 CONVRT6 0295 R + 6 CONVRT7 0299 R | 6 CONVRT8 02A3 R | CR = 000D + 6 CREATE 0107 R | 6 CRLF 0096 R | 6 DECODE 03EE R + 6 DECODE1 03FE R | 6 DECODE2 0420 R | 6 DECODE3 0429 R + 6 DECODE4 0430 R | DEL = 007F | 6 DELBATCH 01DB R + 6 DELETE 00ED R | 6 DIRECT 0470 R | 6 DIRECT1 0481 R + 6 DIRECT2 0488 R | 6 DIRECT3 0491 R | 6 DIRECT4 04C5 R + 6 DIRECT5 04CD R | 6 DIRECT6 04D2 R | 6 DIRECT7 0507 R + 6 DIRECT8 0508 R | 6 DIRECT9 0514 R | 6 DMASET 01D6 R + 6 DRECT63 04F0 R | 6 DRECT65 04F2 R | 6 DSELECT 044A R + 6 DSKSEL 00BB R | ENDFIL = 0001 | ENTRY = 0005 + 6 ENTRY1 00C1 R | 6 ENTRY2 00F2 R | EQUAL = 003D + 6 ERASE 0518 R | 6 ERASE1 053B R | 6 EXISTS 067B R + 6 EXTRACT 0441 R | 6 FCB 07D9 R | FF = 000C + 6 GETBACK 0792 R | 6 GETBACK1 0795 R | 6 GETDSK 01CE R + 6 GETEXT 02AA R | 6 GETEXT1 02B2 R | 6 GETEXT2 02C3 R + 6 GETEXT3 02C5 R | 6 GETEXT4 02C9 R | 6 GETEXT5 02D3 R + 6 GETEXT6 02DA R | 6 GETEXT7 02DC R | 6 GETEXT8 02EB R + 6 GETEXT9 02F3 R | 6 GETINP 0137 R | 6 GETINP1 0194 R + 6 GETINP2 01A5 R | 6 GETINP3 01A9 R | 6 GETINP4 01B8 R + 6 GETSETUC 0113 R | 6 GETUSR 0111 R | GREATERT= 003E + 6 HL2DE 0438 R | 6 INBUFF 0006 R | 6 INPOINT 0086 R + IOBYTE = 0003 | LCURLY = 007B | LESSTHAN= 003C + LF = 000A | MON = 0001 | MONADR = FC00 + 6 MONITOR 046D R | 6 MOVE3 0436 R | 6 MOVECD 0127 R + 6 NAMEPNT 0088 R | 6 NBYTES 07FD R | NK = 003B + 6 NOFILE 03E6 R | 6 NONBLANK 0239 R | 6 NONE 03E0 R + 6 NOSPACE 0600 R | NUMCMDS = 0007 | 6 OPEN 00C9 R + 6 OPENFCB 00CE R | PERIOD = 002E | 6 PLINE 00A5 R + 6 PLINE2 00AA R | 6 PRINT 008A R | 6 PRINTB 0090 R + QUESTION= 003F | 6 RDERR 03D5 R | 6 RDERROR 03CF R + 6 RDREC 00F7 R | 6 READFCB 00FC R | 6 RENAM 010C R + 6 RENAME 0609 R | 6 RENAME1 0638 R | 6 RENAME2 0652 R + 6 RENAME3 0657 R | 6 RENAME4 0666 R | 6 RENAME5 066C R + 6 RENAME6 0672 R | 6 RESDSK 00B6 R | 6 RESETDR 045C R + 6 RTNCODE 07FA R | 6 SAVE 05A6 R | 6 SAVE1 05CD R + 6 SAVE2 05EA R | 6 SAVE3 05F4 R | 6 SAVE4 05FA R + 6 SEARCH 0326 R | 6 SEARCH1 032B R | 6 SEARCH2 0334 R + 6 SEARCH3 0347 R | 6 SEARCH4 034C R | 6 SETCDRV 0118 R + 6 SPACE 00A0 R | 6 SRCHFCB 00E7 R | 6 SRCHFST 00DD R + 6 SRCHNXT 00E2 R | 6 STDDMA 01D3 R | 6 SYNERR 01F3 R + 6 SYNERR1 01F9 R | 6 SYNERR2 020C R | TAB = 0009 + TBASE = 0100 | TBUFF = 0080 | TDRIVE = 0004 + TFCB = 005C | 6 TYPE 0556 R | 6 TYPE1 056D R + 6 TYPE2 0570 R | 6 TYPE3 0580 R | 6 TYPE4 0599 R + 6 TYPE5 05A0 R | UNDERSCO= 005F | 6 UNKNOWN 069E R + 6 UNKWN0 077D R | 6 UNKWN1 06BA R | 6 UNKWN2 06C3 R + 6 UNKWN3 06ED R | 6 UNKWN4 070D R | 6 UNKWN5 073C R + 6 UNKWN6 074A R | 6 UNKWN7 074F R | 6 UNKWN8 075B R + 6 UNKWN9 0777 R | 6 UNKWNA 06EA R | 6 UPPER 012E R + 6 USER 0687 R | USRDSP = 0001 | 6 WRTREC 0102 R + 6 YESNO 054B R | 6 _ccp 0000 GR | 6 _ccp_end 07FF GR + 6 _ccp_sta 0000 GR + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 2. +ccpb03.s derived from ccpb03.asm +Area Table + + 0 _CODE size 0 flags 0 + 1 _DATA size 0 flags 0 + 2 _OVERLAY size 0 flags 0 + 3 _HOME size 0 flags 0 + 4 _GSINIT size 0 flags 0 + 5 _GSFINAL size 0 flags 0 + 6 _CCPB03 size 7FF flags 0 + 7 _CABS size 0 flags 0 diff --git a/doug/src/copyfile.arf b/doug/src/copyfile.arf new file mode 100755 index 00000000..1d3cdcc2 --- /dev/null +++ b/doug/src/copyfile.arf @@ -0,0 +1,9 @@ +-mjx +-i copyfile.ihx +-k /usr/local/share/sdcc/lib/z80 +-l z80 +cpm0.rel +copyfile.rel +cpmbdos.rel +cprintf.rel +-e diff --git a/doug/src/copyfile.c b/doug/src/copyfile.c new file mode 100755 index 00000000..c2ef45c4 --- /dev/null +++ b/doug/src/copyfile.c @@ -0,0 +1,79 @@ +/* + * copyfile.c 5/11/2011 dwg - + * Main C module uses cpmbdos.h bindings to access system services + * Copyright (C) Douglas Goodall All Rights Reserved + * For non-commercial use by N8VEM Community +*/ + +#include +#include +#include +#include "stdlib.h" +#include "cpmbdos.h" +#include "cprintf.h" + +char sine[] = "copyfile.c(com) 5/11/2011 dwg - $"; + +struct FCB * prifcb = (struct FCB *)0x5c; +struct FCB * secfcb = (struct FCB *)0x6c; + +struct FCB srcfcb; +struct FCB dstfcb; + +struct BDOSCALL writestr = { C_WRITESTR, { (unsigned int)&sine } }; +struct BDOSCALL makedst = { F_MAKE, { (unsigned int)&dstfcb } }; +struct BDOSCALL opensrc = { F_OPEN, { (unsigned int)&srcfcb } }; +struct BDOSCALL readsrc = { F_READ, { (unsigned int)&srcfcb } }; +struct BDOSCALL writedst = { F_WRITE, { (unsigned int)&dstfcb } }; +struct BDOSCALL closesrc = { F_CLOSE, { (unsigned int)&srcfcb } }; +struct BDOSCALL closedst = { F_CLOSE, { (unsigned int)&dstfcb } }; + +struct BDOSCALL cwrite = { C_WRITE, { (unsigned int)'?' } }; +struct BDOSCALL cread = { C_READ, { (unsigned int)0 } }; + +/* THESE ARE USED BY THE LIBRARY ROUTINES */ +char getchar(void) +{ + struct BDOSCALL cread = { C_READ, { (unsigned int)0 } }; + return cpmbdos(&cread); +} +void outchar(char c) +{ + struct BDOSCALL cwrite = { C_WRITE, { (unsigned int)c } }; + cpmbdos(&cwrite); +} + +int main(void) +{ + int rc; + + cpmbdos(&writestr); + + strncpy(srcfcb.filename,prifcb->filename,8+3); + srcfcb.ex = srcfcb.rc = srcfcb.cr = 0; + rc = cpmbdos(&opensrc); printf("\nrc from opensrc was %2d, ",rc); + if(rc != 0) { + printf("\nSorry, cannot open source file\n"); + return(EXIT_FAILURE); + } + + strncpy(dstfcb.filename,secfcb->filename,8+3); + dstfcb.ex = dstfcb.rc = dstfcb.cr = 0; + rc = cpmbdos(&makedst); printf("rc from makedst was %2d",rc); + if(rc != 0) { + printf("\nSorry, cannot open destination file\n"); + cpmbdos(&closesrc); + return(EXIT_FAILURE); + } + + rc = cpmbdos(&readsrc); printf("\nrc from read was %2d, ",rc); + while(0 == rc) { + rc = cpmbdos(&writedst); printf( "rc from write was %2d", rc); + rc = cpmbdos(&readsrc); printf("\nrc from read was %2d, ",rc); + } + rc = cpmbdos(&closesrc); printf("\nrc from closesrc was %2d, ",rc); + rc = cpmbdos(&closedst); printf( "rc from closedst was %2d", rc); + + return EXIT_SUCCESS; +} + diff --git a/doug/src/copyfile.lk b/doug/src/copyfile.lk new file mode 100755 index 00000000..1d3cdcc2 --- /dev/null +++ b/doug/src/copyfile.lk @@ -0,0 +1,9 @@ +-mjx +-i copyfile.ihx +-k /usr/local/share/sdcc/lib/z80 +-l z80 +cpm0.rel +copyfile.rel +cpmbdos.rel +cprintf.rel +-e diff --git a/doug/src/copyfile.lnk b/doug/src/copyfile.lnk new file mode 100755 index 00000000..1d3cdcc2 --- /dev/null +++ b/doug/src/copyfile.lnk @@ -0,0 +1,9 @@ +-mjx +-i copyfile.ihx +-k /usr/local/share/sdcc/lib/z80 +-l z80 +cpm0.rel +copyfile.rel +cpmbdos.rel +cprintf.rel +-e diff --git a/doug/src/cpm0.lst b/doug/src/cpm0.lst new file mode 100755 index 00000000..ae386b18 --- /dev/null +++ b/doug/src/cpm0.lst @@ -0,0 +1,46 @@ + 1 ;-------------------------------------------------------------------------- + 2 ; cpm0.s - Generic cpm0.s for a Z80 CP/M-80 v2.2 Application + 3 ; Copyright (C) 2011, Douglas Goodall All Rights Reserved. + 4 ;-------------------------------------------------------------------------- + 5 + 6 .globl _main + 7 .area _CODE + 8 + 0000 9 .ds 0x0100 + 0100 10 init: + 11 ;; Define an adequate stack + 0100 31r00s01 12 ld sp,#stktop + 13 + 14 ;; Initialise global variables + 0103 CDr00s00 15 call gsinit + 16 + 17 ;; Call the C main routine + 0106 CDr00s00 18 call _main + 19 + 0109 0E 00 20 ld c,#0 + 010B CD 05 00 21 call 5 + 22 + 23 ;; Ordering of segments for the linker. + 24 .area _TPA + 25 + 26 .area _HOME + 27 .area _CODE + 28 .area _GSINIT + 29 .area _GSFINAL + 30 .area _DATA + 31 + 32 .area _STACK + 0000 33 .ds 256 + 0100 34 stktop: + 35 + 36 .area _GSINIT + 0000 37 gsinit:: + 38 + 39 .area _GSFINAL + 0000 C9 40 ret + 0001 E5 41 .db 0xe5 + 42 + 43 ;;;;;;;;;;;;;;;; + 44 ; eof - cpm0.s ; + 45 ;;;;;;;;;;;;;;;; + 46 diff --git a/doug/src/cpm0.rel b/doug/src/cpm0.rel new file mode 100755 index 00000000..a44191b5 --- /dev/null +++ b/doug/src/cpm0.rel @@ -0,0 +1,26 @@ +XL +H 7 areas 3 global symbols +S _main Ref0000 +S .__.ABS. Def0000 +A _CODE size 10E flags 0 addr 0 +A _TPA size 0 flags 0 addr 0 +A _HOME size 0 flags 0 addr 0 +A _GSINIT size 0 flags 0 addr 0 +S gsinit Def0000 +A _GSFINAL size 2 flags 0 addr 0 +A _DATA size 0 flags 0 addr 0 +A _STACK size 100 flags 0 addr 0 +T 00 00 +R 00 00 00 00 +T 00 01 +R 00 00 00 00 +T 00 01 31 00 01 CD 00 00 CD 00 00 0E 00 CD 05 00 +R 00 00 00 00 00 03 06 00 00 06 03 00 02 09 00 00 +T 00 00 +R 00 00 06 00 +T 00 01 +R 00 00 06 00 +T 00 00 +R 00 00 03 00 +T 00 00 C9 E5 +R 00 00 04 00 diff --git a/doug/src/cpm0.s b/doug/src/cpm0.s new file mode 100755 index 00000000..6e9191ea --- /dev/null +++ b/doug/src/cpm0.s @@ -0,0 +1,46 @@ +;-------------------------------------------------------------------------- +; cpm0.s - Generic cpm0.s for a Z80 CP/M-80 v2.2 Application +; Copyright (C) 2011, Douglas Goodall All Rights Reserved. +;-------------------------------------------------------------------------- + + .globl _main + .area _CODE + + .ds 0x0100 +init: + ;; Define an adequate stack + ld sp,#stktop + + ;; Initialise global variables + call gsinit + + ;; Call the C main routine + call _main + + ld c,#0 + call 5 + + ;; Ordering of segments for the linker. + .area _TPA + + .area _HOME + .area _CODE + .area _GSINIT + .area _GSFINAL + .area _DATA + + .area _STACK + .ds 256 +stktop: + + .area _GSINIT +gsinit:: + + .area _GSFINAL + ret + .db 0xe5 + +;;;;;;;;;;;;;;;; +; eof - cpm0.s ; +;;;;;;;;;;;;;;;; + diff --git a/doug/src/cpm0.sym b/doug/src/cpm0.sym new file mode 100755 index 00000000..706615a9 --- /dev/null +++ b/doug/src/cpm0.sym @@ -0,0 +1,17 @@ + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 1. + +Symbol Table + + .__.ABS.= 0000 G | _main **** GX | 3 gsinit 0000 GR + 0 init 0100 R | 6 stktop 0100 R + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 2. + +Area Table + + 0 _CODE size 10E flags 0 + 1 _TPA size 0 flags 0 + 2 _HOME size 0 flags 0 + 3 _GSINIT size 0 flags 0 + 4 _GSFINAL size 2 flags 0 + 5 _DATA size 0 flags 0 + 6 _STACK size 100 flags 0 diff --git a/doug/src/cpm22.s b/doug/src/cpm22.s new file mode 100755 index 00000000..512e7228 --- /dev/null +++ b/doug/src/cpm22.s @@ -0,0 +1,2989 @@ +; modified 4/22/2011 for the N8VEM Home Computer Z180 -- John Coffman +; +;-------------------------------------------------------------------------- +; cpm22.s - CP/M-80 v2.2 for a Z80 +; +; Copyright (C) 2000, Michael Hope +; +; This library is free software; you can redistribute it and/or modify it +; under the terms of the GNU General Public License as published by the +; Free Software Foundation; either version 2.1, or (at your option) any +; later version. +; +; This library is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this library; see the file COPYING. If not, write to the +; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, +; MA 02110-1301, USA. +; +; As a special exception, if you link this library with other files, +; some of which are compiled with SDCC, to produce an executable, +; this library does not by itself cause the resulting executable to +; be covered by the GNU General Public License. This exception does +; not however invalidate any other reasons why the executable file +; might be covered by the GNU General Public License. +;-------------------------------------------------------------------------- + +;;; .module crt0 + .globl _main + + .area _HEADER (ABS) + ;; Reset vector + .org 0 + jp init + + .org 0x08 + ret + .org 0x10 + ret + .org 0x18 + ret + .org 0x20 + ret + .org 0x28 + ret + .org 0x30 + ret + .org 0x38 + ret + .org 0x66 ; NMI interrupt + retn + +;; .org 0x100 +;;init: +;; ;; Stack at the top of memory. +;; ld sp,#0xffff +;; +;; ;; Initialise global variables +;; call gsinit +;; call _main +;; jp _exit + + + +;; title 'Bdos Interface, Bdos, Version 2.2 Feb, 1980' +;; +;; .Z80 +;; aseg + + org 100h + + maclib MEMCFG.LIB ; define configuration parameters + +;; .phase bdosph +;;bios equ biosph + +;***************************************************************** +;***************************************************************** +;** ** +;** B a s i c D i s k O p e r a t i n g S y s t e m ** +;** I n t e r f a c e M o d u l e ** +;** ** +;***************************************************************** +;***************************************************************** + +; Copyright (c) 1978, 1979, 1980 +; Digital Research +; Box 579, Pacific Grove +; California + + +; 20 january 1980 + +ssize equ 24 ;24 level stack + +; low memory locations + +;;reboot equ 0000h ;reboot system +reboot = 0x0000 + +;;ioloc equ 0003h ;i/o byte location +ioloc = 0x0003 + +;;bdosa equ 0006h ;address field of jp BDOS +bdosa = 0x0006 + +; bios access constants + +bootf defl bios+3*0 ;cold boot function + +wbootf defl bios+3*1 ;warm boot function + +constf defl bios+3*2 ;console status function + +coninf defl bios+3*3 ;console input function + +conoutf defl bios+3*4 ;console output function + +listf defl bios+3*5 ;list output function + +punchf defl bios+3*6 ;punch output function + +readerf defl bios+3*7 ;reader input function + +homef defl bios+3*8 ;disk home function + +seldskf defl bios+3*9 ;select disk function + +settrkf defl bios+3*10 ;set track function + +setsecf defl bios+3*11 ;set sector function + +setdmaf defl bios+3*12 ;set dma function + +readf defl bios+3*13 ;read disk function + +writef defl bios+3*14 ;write disk function + +liststf defl bios+3*15 ;list status function + +sectran defl bios+3*16 ;sector translate + + +; equates for non graphic characters + +;;ctlc .equ 03h ;control c +ctlc = 0x03 + +;;ctle equ 05h ;physical eol +ctle = 0x05 + +;;ctlh equ 08h ;backspace +ctlh = 0x08 + +;;ctlp equ 10h ;prnt toggle +ctlp = 0x10 + +;;ctlr equ 12h ;repeat line +ctlr = 0x12 + +;;ctls equ 13h ;stop/start screen +ctls = 0x13 + +;;ctlu equ 15h ;line delete +ctlu = 0x15 + +;;ctlx equ 18h ;=ctl-u +ctlx = 0x18 + +;;ctlz equ 1ah ;end of file +ctlz = 0x1a + +;;rubout equ 7fh ;char delete +rubout = 0x7f + +;;tab equ 09h ;tab char +tab = 0x09 + +;;cr equ 0dh ;carriage return +cr = 0x0d + +;;lf equ 0ah ;line feed +lf = 0x0a + +;;ctl equ 5eh ;up arrow +ctl equ 0x5e + + .db 0,0,0,0,0,0 + +; enter here from the user's program with function number in c, +; and information address in d,e + jp bdose ;past parameter block + +; ************************************************ +; *** relative locations 0009 - 000e *** +; ************************************************ +pererr: .dw persub ;permanent error subroutine +selerr: .dw selsub ;select error subroutine +roderr: .dw rodsub ;ro disk error subroutine +roferr: .dw rofsub ;ro file error subroutine + + +bdose: ex de,hl ;arrive here from user programs + ld (info),hl + ex de,hl ;info=DE, DE=info + ld a,e + ld (linfo),a ;linfo = low(info) - don't equ + ld hl,0 + ld (aret),hl ;return value defaults to 0000 + ;save user's stack pointer, set to local stack + add hl,sp + ld (entsp),hl ;entsp = stackptr + ld sp,lstack ;local stack setup + xor a + ld (fcbdsk),a + ld (resel),a ;fcbdsk,resel=false + ld hl,goback ;return here after all functions + push hl ;jmp goback equivalent to ret + ld a,c + cp nfuncs + ret nc ;skip if invalid # + ld c,e ;possible output character to C + ld hl,functab + ld e,a + ld d,0 ;DE=func, HL=.ciotab + add hl,de + add hl,de + ld e,(hl) + inc hl + ld d,(hl) ;DE=functab(func) + ld hl,(info) ;info in DE for later xchg + ex de,hl + jp (hl) ;dispatched + +; dispatch table for functions +functab: + .dw wbootf, func1, func2, func3 + .dw punchf, listf, func6, func7 + .dw func8, func9, func10,func11 + +;;diskf equ ($-functab)/2 ;disk funcs +diskf = ($-functab)/2 ;disk funcs + + .dw func12,func13,func14,func15 + .dw func16,func17,func18,func19 + .dw func20,func21,func22,func23 + .dw func24,func25,func26,func27 + .dw func28,func29,func30,func31 + .dw func32,func33,func34,func35 + .dw func36,func37,func38,func39 + .dw func40 + +;;nfuncs equ ($-functab)/2 +nfuncs = ($-functab)/2 + +; error subroutines +persub: ld hl,permsg ;report permanent error + call errflg ;to report the error + cp ctlc + jp z,reboot ;reboot if response is ctlc + ret ;and ignore the error + +selsub: ld hl,selmsg ;report select error + jp wait$err ;wait console before boot + +rodsub: ld hl,rodmsg ;report write to read/only disk + jp wait$err ;wait console + +rofsub: ;report read/only file + ld hl,rofmsg ;drop through to wait for console + +wait$err: ;wait for response before boot + call errflg + jp reboot + +; error messages + +;;dskmsg: db 'Bdos Err On ' +dskmsg .ascii ' : $' + +;;dskerr: db ' : $' ;filled in by errflg +dskerr .ascii ' : $' + +;;permsg: db 'Bad Sector$' +permsg: .ascii 'Bad Sector$' + +;;selmsg: db 'Select$' +selmsg: .ascii 'Select$' + +;;rofmsg: db 'File ' +rofmsg: .asccii 'File ' + +;;rodmsg: db 'R/O$' +rodmsg: .ascii 'R/O$' + + +errflg: push hl ;report error to console, message address in HL + call crlf ;stack mssg address, new line + ld a,(curdsk) + add a,'A' + ld (dskerr),a ;current disk name + ld bc,dskmsg + call print ;the error message + pop bc + call print ;error mssage tail +; jp conin ;to get the input character + ;(drop through to conin) +; ret + + +; console handlers +conin: ld hl,kbchar ;read console character to A + ld a,(hl) + ld (hl),0 + or a + ret nz + ;no previous keyboard character ready + jp coninf ;get character externally +; ret +conech: call conin ;read character with echo + call echoc + ret c ;echo character? + ;character must be echoed before return + push af + ld c,a + call tabout + pop af + ret ;with character in A + +echoc: ;echo character if graphic + cp cr ;cr, lf, tab, or backspace + ret z ;carriage return? + cp lf + ret z ;line feed? + cp tab + ret z ;tab? + cp ctlh + ret z ;backspace? + cp ' ' + ret ;carry set if not graphic + +conbrk: ;check for character ready + ld a,(kbchar) + or a + jp nz,conb1 ;skip if active kbchar + ;no active kbchar, check external break + call constf + and 1 + ret z ;return if no char ready + ;character ready, read it + call coninf ;to A + cp ctls + jp nz,conb0 ;check stop screen function + ;found ctls, read next character + call coninf ;to A + cp ctlc + jp z,reboot ;ctlc implies re-boot + ;not a reboot, act as if nothing has happened + xor a + ret ;with zero in accumulator +conb0: + ;character in accum, save it + ld (kbchar),a +conb1: + ;return with true set in accumulator + ld a,1 + ret + +conout: ;compute character position/write console char from C + ;compcol = true if computing column position + ld a,(compcol) + or a + jp nz,compout + ;write the character, then compute the column + ;write console character from C + push bc + call conbrk ;check for screen stop function + pop bc + push bc ;recall/save character + call conoutf ;externally, to console + pop bc + push bc ;recall/save character + ;may be copying to the list device + ld a,(listcp) + or a + call nz,listf ;to printer, if so + pop bc ;recall the character +compout: + ld a,c ;recall the character + ;and compute column position + ld hl,column ;A = char, HL = .column + cp rubout + ret z ;no column change if nulls + inc (hl) ;column = column + 1 + cp ' ' + ret nc ;return if graphic + ;not graphic, reset column position + dec (hl) ;column = column - 1 + ld a,(hl) + or a + ret z ;return if at zero + ;not at zero, may be backspace or end line + ld a,c ;character back to A + cp ctlh + jp nz,notbacksp + ;backspace character + dec (hl) ;column = column - 1 + ret + +notbacksp: ;not a backspace character, eol? + cp lf + ret nz ;return if not + ;end of line, column = 0 + ld (hl),0 ;column = 0 + ret + +ctlout: ;send C character with possible preceding up-arrow + ld a,c + call echoc ;cy if not graphic (or special case) + jp nc,tabout ;skip if graphic, tab, cr, lf, or ctlh + ;send preceding up arrow + push af + ld c,ctl + call conout ;up arrow + pop af + or 40h ;becomes graphic letter + ld c,a ;ready to print + ;(drop through to tabout) + +tabout: ;expand tabs to console + ld a,c + cp tab + jp nz,conout ;direct to conout if not + ;tab encountered, move to next tab position +tab0: ld c,' ' + call conout ;another blank + ld a,(column) + and 111b ;column mod 8 = 0 ? + jp nz,tab0 ;back for another if not + ret + +backup: ;back-up one screen position + call pctlh + ld c,' ' + call conoutf +; (drop through to pctlh) +pctlh: ;send ctlh to console without affecting column count + ld c,ctlh + jp conoutf +; ret +crlfp: ;print #, cr, lf for ctlx, ctlu, ctlr functions + ;then move to strtcol (starting column) + ld c,'#' + call conout + call crlf ;column = 0, move to position strtcol +crlfp0: ld a,(column) + ld hl,strtcol + cp (hl) + ret nc ;stop when column reaches strtcol + ld c,' ' + call conout ;print blank + jp crlfp0 + +crlf: ld c,cr ;carriage return line feed sequence + call conout + ld c,lf + jp conout +; ret +print: ld a,(bc) ;print message until M(BC) = '$' + cp '$' + ret z ;stop on $ + ;more to print + inc bc + push bc + ld c,a ;char to C + call tabout ;another character printed + pop bc + jp print + +read: ;read to info address (max length, current length, buffer) + ld a,(column) + ld (strtcol),a ;save start for ctl-x, ctl-h + ld hl,(info) + ld c,(hl) + inc hl + push hl + ld b,0 + ;B = current buffer length, + ;C = maximum buffer length, + ;HL= next to fill - 1 +readnx: ;read next character, BC, HL active + push bc + push hl ;blen, cmax, HL saved +readn0: call conin ;next char in A + and 7fh ;mask parity bit + pop hl + pop bc ;reactivate counters + cp cr + jp z,readen ;end of line? + cp lf + jp z,readen ;also end of line + cp ctlh + jp nz,noth ;backspace? + ;do we have any characters to back over? + ld a,b + or a + jp z,readnx + ;characters remain in buffer, backup one + dec b ;remove one character + ld a,(column) + ld (compcol),a ;col > 0 + ;compcol > 0 marks repeat as length compute + jp linelen ;uses same code as repeat + +noth: ;not a backspace + cp rubout + jp nz,notrub ;rubout char? + ;rubout encountered, rubout if possible + ld a,b + or a + jp z,readnx ;skip if len=0 + ;buffer has characters, resend last char + ld a,(hl) + dec b + dec hl ;A = last char + ;blen=blen-1, next to fill - 1 decremented + jp rdech1 ;act like this is an echo + +notrub: ;not a rubout character, check end line + cp ctle + jp nz,note ;physical end line? + ;yes, save active counters and force eol + push bc + push hl + call crlf + xor a + ld (strtcol),a ;start position = 00 + jp readn0 ;for another character + +note: ;not end of line, list toggle? + cp ctlp + jp nz,notp ;skip if not ctlp + ;list toggle - change parity + push hl ;save next to fill - 1 + ld hl,listcp ;HL=.listcp flag + ld a,1 + sub (hl) ;True-listcp + ld (hl),a ;listcp = not listcp + pop hl + jp readnx ;for another char + +notp: ;not a ctlp, line delete? + cp ctlx + jp nz,notx + pop hl ;discard start position + ;loop while column > strtcol +backx: ld a,(strtcol) + ld hl,column + cp (hl) + jp nc,read ;start again + dec (hl) ;column = column - 1 + call backup ;one position + jp backx + +notx: ;not a control x, control u? + ;not control-X, control-U? + cp ctlu + jp nz,notu ;skip if not + ;delete line (ctlu) + call crlfp ;physical eol + pop hl ;discard starting position + jp read ;to start all over + +notu: ;not line delete, repeat line? + cp ctlr + jp nz,notr +linelen: ;repeat line, or compute line len (ctlh) + ;if compcol > 0 + push bc + call crlfp ;save line length + pop bc + pop hl + push hl + push bc + ;bcur, cmax active, beginning buff at HL +rep0: ld a,b + or a + jp z,rep1 ;count len to 00 + inc hl + ld c,(hl) ;next to print + dec b + push bc + push hl ;count length down + call ctlout ;character echoed + pop hl + pop bc ;recall remaining count + jp rep0 ;for the next character + +rep1: ;end of repeat, recall lengths + ;original BC still remains pushed + push hl ;save next to fill + ld a,(compcol) + or a ;>0 if computing length + jp z,readn0 ;for another char if so + ;column position computed for ctlh + ld hl,column + sub (hl) ;diff > 0 + ld (compcol),a ;count down below + ;move back compcol-column spaces +backsp: ;move back one more space + call backup ;one space + ld hl,compcol + dec (hl) + jp nz,backsp + jp readn0 ;for next character + +notr: ;not a ctlr, place into buffer +rdecho: inc hl + ld (hl),a ;character filled to mem + inc b ;blen = blen + 1 +rdech1: ;look for a random control character + push bc + push hl ;active values saved + ld c,a ;ready to print + call ctlout ;may be up-arrow C + pop hl + pop bc + ld a,(hl) ;recall char + cp ctlc ;set flags for reboot test + ld a,b ;move length to A + jp nz,notc ;skip if not a control c + cp 1 ;control C, must be length 1 + jp z,reboot ;reboot if blen = 1 + ;length not one, so skip reboot +notc: ;not reboot, are we at end of buffer? + cp c + jp c,readnx ;go for another if not +readen: ;end of read operation, store blen + pop hl + ld (hl),b ;M(current len) = B + ld c,cr + jp conout ;return carriage +; ret +func1: ;return console character with echo + call conech + jp sta$ret + +func2 equ tabout + ;write console character with tab expansion + +func3: ;return reader character + call readerf + jp sta$ret + +;func4: equated to punchf + ;write punch character + +;func5: equated to listf + ;write list character + ;write to list device + +func6: ;direct console i/o - read if 0ffh + ld a,c + inc a + jp z,dirinp ;0ffh => 00h, means input mode + inc a + jp z,constf ;0feH in C for status + ;direct output function + jp conoutf + +dirinp: call constf ;status check + or a + jp z,retmon ;skip, return 00 if not ready + ;character is ready, get it + call coninf ;to A + jp sta$ret + +func7: ;return io byte + ld a,(ioloc) + jp sta$ret + +func8: ;set i/o byte + ld hl,ioloc + ld (hl),c + ret ;jmp goback + +func9: ;write line until $ encountered + ex de,hl ;was lhld info + ld c,l + ld b,h ;BC=string address + jp print ;out to console + +func10 equ read + ;read a buffered console line + +func11: ;check console status + call conbrk + ;(drop through to sta$ret) +sta$ret: ;store the A register to aret + ld (aret),a +func$ret: + ret ;jmp goback (pop stack for non cp/m functions) + +setlret1: ;set lret = 1 + ld a,1 + jp sta$ret + + + +; data areas + +compcol: + .db 0 ;true if computing column position + +strtcol: + .db 0 ;starting column position after read + +column: .db 0 ;column position +listcp: .db 0 ;listing toggle +kbchar: .db 0 ;initial key char = 00 +entsp: .ds 2 ;entry stack pointer + .ds ssize*2 ;stack size + +lstack: + +; end of Basic I/O System + +;***************************************************************** +;***************************************************************** + +; common values shared between bdosi and bdos +usrcode: + .db 0 ;current user number +curdsk: .db 0 ;current disk number +info: .ds 2 ;information address +aret: .ds 2 ;address value to return +lret .equ aret ;low(aret) + +;***************************************************************** +;***************************************************************** +;** ** +;** B a s i c D i s k O p e r a t i n g S y s t e m ** +;** ** +;***************************************************************** +;***************************************************************** + +;;dvers equ 22h ;version 2.2 +dvers = 0x22 + +; module addresses + +; literal constants + +;;true equ 0ffh ;constant true +true = 0xff + +;;false equ 000h ;constant false +false = 0x00 + +;;enddir equ 0ffffh ;end of directory +enddir = 0xffff + +;;byte equ 1 ;number of bytes for "byte" type +byte = 1 + +;;word equ 2 ;number of bytes for "word" type +word = 2 + +; fixed addresses in low memory + +;;tfcb equ 005ch ;default fcb location +tfcb = 0x5c + +;;tbuff equ 0080h ;default buffer location +tbuff = 0x80 + +; fixed addresses referenced in bios module are +; pererr (0009), selerr (000c), roderr (000f) + +; error message handlers + +;per$error: ;report permanent error to user +; ld hl,pererr +; jp goerr + +;rod$error: ;report read/only disk error +; ld hl,roderr +; jp goerr + +;rof$error: ;report read/only file error +; ld hl,roferr +; jp goerr + +sel$error: ;report select error + ld hl,selerr + + +goerr: ;HL = .errorhandler, call subroutine + ld e,(hl) + inc hl + ld d,(hl) ;address of routine in DE + ex de,hl + jp (hl) ;to subroutine + + + +; local subroutines for bios interface + +move: ;move data length of length C from source DE to + ;destination given by HL + inc c ;in case it is zero +move0: dec c + ret z ;more to move + ld a,(de) + ld (hl),a ;one byte moved + inc de + inc hl ;to next byte + jp move0 + +selectdisk: ;select the disk drive given by curdsk, and fill + ;the base addresses curtrka - alloca, then fill + ;the values of the disk parameter block + ld a,(curdsk) + ld c,a ;current disk# to c + ;lsb of e = 0 if not yet logged - in + call seldskf ;HL filled by call + ;HL = 0000 if error, otherwise disk headers + ld a,h + or l + ret z ;return with 0000 in HL and z flag + ;disk header block address in hl + ld e,(hl) + inc hl + ld d,(hl) + inc hl ;DE=.tran + ld (cdrmaxa),hl + inc hl + inc hl ;.cdrmax + ld (curtrka),hl + inc hl + inc hl ;HL=.currec + ld (curreca),hl + inc hl + inc hl ;HL=.buffa + ;DE still contains .tran + ex de,hl + ld (tranv),hl ;.tran vector + ld hl,buffa ;DE= source for move, HL=dest + ld c,addlist + call move ;addlist filled + ;now fill the disk parameter block + ld hl,(dpbaddr) + ex de,hl ;DE is source + ld hl,sectpt ;HL is destination + ld c,dpblist + call move ;data filled + ;now set single/double map mode + ld hl,(maxall) ;largest allocation number + ld a,h ;00 indicates < 255 + ld hl,single + ld (hl),true ;assume a=00 + or a + jp z,retselect + ;high order of maxall not zero, use double dm + ld (hl),false +retselect: + ld a,true + or a + ret ;select disk function ok + +home: ;move to home position, then offset to start of dir + call homef ;move to track 00, sector 00 reference + ;lxi h,offset ;mov c,m ;inx h ;mov b,m ;call settrkf + ;first directory position selected + xor a ;constant zero to accumulator + ld hl,(curtrka) + ld (hl),a + inc hl + ld (hl),a ;curtrk=0000 + ld hl,(curreca) + ld (hl),a + inc hl + ld (hl),a ;currec=0000 + ;curtrk, currec both set to 0000 + ret + +rdbuff: ;read buffer and check condition + call readf ;current drive, track, sector, dma + jp diocomp ;check for i/o errors + +wrbuff: ;write buffer and check condition + ;write type (wrtype) is in register C + ;wrtype = 0 => normal write operation + ;wrtype = 1 => directory write operation + ;wrtype = 2 => start of new block + call writef ;current drive, track, sector, dma +diocomp: ;check for disk errors + or a + ret z + ld hl,pererr + jp goerr + +seek$dir: ;seek the record containing the current dir entry + ld hl,(dcnt) ;directory counter to HL + ld c,dskshf + call hlrotr ;value to HL + ld (arecord),hl + ld (drec),hl ;ready for seek +; jp seek +; ret + + +seek: ;seek the track given by arecord (actual record) + ;local equates for registers + ;load the registers from memory + ld hl,arecord + ld c,(hl) + inc hl + ld b,(hl) + ld hl,(curreca) + ld e,(hl) + inc hl + ld d,(hl) + ld hl,(curtrka) + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + ;loop while arecord < currec +seek0: ld a,c + sub e + ld a,b + sbc a,d + jp nc,seek1 ;skip if arecord >= currec + ;currec = currec - sectpt + push hl + ld hl,(sectpt) + ld a,e + sub l + ld e,a + ld a,d + sbc a,h + ld d,a + pop hl + ;curtrk = curtrk - 1 + dec hl + jp seek0 ;for another try + +seek1: ;look while arecord >= (t:=currec + sectpt) + push hl + ld hl,(sectpt) + add hl,de ;HL = currec+sectpt + jp c,seek2 ;can be > FFFFH + ld a,c + sub l + ld a,b + sbc a,h + jp c,seek2 ;skip if t > arecord + ;currec = t + ex de,hl + ;curtrk = curtrk + 1 + pop hl + inc hl + jp seek1 ;for another try + +seek2: pop hl + ;arrive here with updated values in each register + push bc + push de + push hl ;to stack for later + ;stack contains (lowest) BC=arecord, DE=currec, HL=curtrk + ex de,hl + ld hl,(offset) + add hl,de ;HL = curtrk+offset + ld b,h + ld c,l + call settrkf ;track set up + ;note that BC - curtrk is difference to move in bios + pop de ;recall curtrk + ld hl,(curtrka) + ld (hl),e + inc hl + ld (hl),d ;curtrk updated + ;now compute sector as arecord-currec + pop de ;recall currec + ld hl,(curreca) + ld (hl),e + inc hl + ld (hl),d + pop bc ;BC=arecord, DE=currec + ld a,c + sub e + ld c,a + ld a,b + sbc a,d + ld b,a + ld hl,(tranv) + ex de,hl ;BC=sector#, DE=.tran + call sectran ;HL = tran(sector) + ld c,l + ld b,h ;BC = tran(sector) + jp setsecf ;sector selected +; ret + +; file control block (fcb) constants +empty equ 0e5h ;empty directory entry +lstrec equ 127 ;last record# in extent +recsiz equ 128 ;record size +fcblen equ 32 ;file control block size +dirrec equ recsiz/fcblen ;directory elts / record +dskshf equ 2 ;log2(dirrec) +dskmsk equ dirrec-1 +fcbshf equ 5 ;log2(fcblen) + +extnum equ 12 ;extent number field +maxext equ 31 ;largest extent number +ubytes equ 13 ;unfilled bytes field +modnum equ 14 ;data module number +maxmod equ 15 ;largest module number +fwfmsk equ 80h ;file write flag is high order modnum +namlen equ 15 ;name length +reccnt equ 15 ;record count field +dskmap equ 16 ;disk map field +lstfcb equ fcblen-1 +nxtrec equ fcblen +ranrec equ nxtrec+1 ;random record field (2 bytes) + +; reserved file indicators +rofile equ 9 ;high order of first type char +invis equ 10 ;invisible file in dir command +; equ 11 ;reserved + +; utility functions for file access + +dm$position: ;compute disk map position for vrecord to HL + ld hl,blkshf + ld c,(hl) ;shift count to C + ld a,(vrecord) ;current virtual record to A +dmpos0: or a + rra + dec c + jp nz,dmpos0 + ;A = shr(vrecord,blkshf) = vrecord/2**(sect/block) + ld b,a ;save it for later addition + ld a,8 + sub (hl) ;8-blkshf to accumulator + ld c,a ;extent shift count in register c + ld a,(extval) ;extent value ani extmsk +dmpos1: + ;blkshf = 3,4,5,6,7, C=5,4,3,2,1 + ;shift is 4,3,2,1,0 + dec c + jp z,dmpos2 + or a + rla + jp dmpos1 + +dmpos2: ;arrive here with A = shl(ext and extmsk,7-blkshf) + add a,b ;add the previous shr(vrecord,blkshf) value + ;A is one of the following values, depending upon alloc + ;bks blkshf + ;1k 3 v/8 + extval * 16 + ;2k 4 v/16+ extval * 8 + ;4k 5 v/32+ extval * 4 + ;8k 6 v/64+ extval * 2 + ;16k 7 v/128+extval * 1 + ret ;with dm$position in A + +getdm: ;return disk map value from position given by BC + ld hl,(info) ;base address of file control block + ld de,dskmap + add hl,de ;HL =.diskmap + add hl,bc ;index by a single byte value + ld a,(single) ;single byte/map entry? + or a + jp z,getdmd ;get disk map single byte + ld l,(hl) + ld h,0 + ret ;with HL=00bb +getdmd: + add hl,bc ;HL=.fcb(dm+i*2) + ;double precision value returned + ld e,(hl) + inc hl + ld d,(hl) + ex de,hl + ret + +index: ;compute disk block number from current fcb + call dm$position ;0...15 in register A + ld c,a + ld b,0 + call getdm ;value to HL + ld (arecord),hl + ret + +allocated: ;called following index to see if block allocated + ld hl,(arecord) + ld a,l + or h + ret + +atran: ;compute actual record address, assuming index called + ld a,(blkshf) ;shift count to reg A + ld hl,(arecord) +atran0: add hl,hl + dec a + jp nz,atran0 ;shl(arecord,blkshf) + ld (arecord1),hl ;save shifted block # + ld a,(blkmsk) + ld c,a ;mask value to C + ld a,(vrecord) + and c ;masked value in A + or l + ld l,a ;to HL + ld (arecord),hl ;arecord=HL or (vrecord and blkmsk) + ret + +getexta: ;get current extent field address to A + ld hl,(info) + ld de,extnum + add hl,de ;HL=.fcb(extnum) + ret + +getfcba: ;compute reccnt and nxtrec addresses for get/setfcb + ld hl,(info) + ld de,reccnt + add hl,de + ex de,hl ;DE=.fcb(reccnt) + ld hl,nxtrec-reccnt + add hl,de ;HL=.fcb(nxtrec) + ret + +getfcb: ;set variables from currently addressed fcb + call getfcba ;addresses in DE, HL + ld a,(hl) + ld (vrecord),a ;vrecord=fcb(nxtrec) + ex de,hl + ld a,(hl) + ld (rcount),a ;rcount=fcb(reccnt) + call getexta ;HL=.fcb(extnum) + ld a,(extmsk) ;extent mask to a + and (hl) ;fcb(extnum) and extmsk + ld (extval),a + ret + +setfcb: ;place values back into current fcb + call getfcba ;addresses to DE, HL + ld a,(seqio) + cp 02 + jp nz,setfcb1 + xor a ;check ranfill +setfcb1: + ld c,a ;=1 if sequential i/o + ld a,(vrecord) + add a,c + ld (hl),a ;fcb(nxtrec)=vrecord+seqio + ex de,hl + ld a,(rcount) + ld (hl),a ;fcb(reccnt)=rcount + ret + +hlrotr: ;hl rotate right by amount C + inc c ;in case zero +hlrotr0: + dec c + ret z ;return when zero + ld a,h + or a + rra + ld h,a ;high byte + ld a,l + rra + ld l,a ;low byte + jp hlrotr0 + +compute$cs: ;compute checksum for current directory buffer + ld c,recsiz ;size of directory buffer + ld hl,(buffa) ;current directory buffer + xor a ;clear checksum value +computecs0: + add a,(hl) + inc hl + dec c ;cs=cs+buff(recsiz-C) + jp nz,computecs0 + ret ;with checksum in A + +hlrotl: ;rotate the mask in HL by amount in C + inc c ;may be zero +hlrotl0: + dec c + ret z ;return if zero + add hl,hl + jp hlrotl0 + +set$cdisk: ;set a "1" value in curdsk position of BC + push bc ;save input parameter + ld a,(curdsk) + ld c,a ;ready parameter for shift + ld hl,1 ;number to shift + call hlrotl ;HL = mask to integrate + pop bc ;original mask + ld a,c + or l + ld l,a + ld a,b + or h + ld h,a ;HL = mask or rol(1,curdsk) + ret + +nowrite: ;return true if dir checksum difference occurred + ld hl,(rodsk) + ld a,(curdsk) + ld c,a + call hlrotr + ld a,l + and 1b + ret ;non zero if nowrite + +set$ro: ;set current disk to read only + ld hl,rodsk + ld c,(hl) + inc hl + ld b,(hl) + call set$cdisk ;sets bit to 1 + ld (rodsk),hl + ;high water mark in directory goes to max + ld hl,(dirmax) + inc hl + ex de,hl ;DE = directory max + ld hl,(cdrmaxa) ;HL = .cdrmax + ld (hl),e + inc hl + ld (hl),d ;cdrmax = dirmax + ret + +check$rodir: ;check current directory element for read/only status + call getdptra ;address of element + +check$rofile: ;check current buff(dptr) or fcb(0) for r/o status + ld de,rofile + add hl,de ;offset to ro bit + ld a,(hl) + rla + ret nc ;return if not set + ld hl,roferr + jp goerr +; jp rof$error ;exit to read only disk message + + +check$write: ;check for write protected disk + call nowrite + ret z ;ok to write if not rodsk + ld hl,roderr + jp goerr +; jp rod$error ;read only disk error + +getdptra: ;compute the address of a directory element at + ;positon dptr in the buffer + ld hl,(buffa) + ld a,(dptr) +addh: ;HL = HL + A + add a,l + ld l,a + ret nc + ;overflow to H + inc h + ret + + +getmodnum: ;compute the address of the module number + ;bring module number to accumulator + ;(high order bit is fwf (file write flag) + ld hl,(info) + ld de,modnum + add hl,de ;HL=.fcb(modnum) + ld a,(hl) + ret ;A=fcb(modnum) + +clrmodnum: ;clear the module number field for user open/make + call getmodnum + ld (hl),0 ;fcb(modnum)=0 + ret + +setfwf: call getmodnum ;HL=.fcb(modnum), A=fcb(modnum) + ;set fwf (file write flag) to "1" + or fwfmsk + ld (hl),a ;fcb(modnum)=fcb(modnum) or 80h + ;also returns non zero in accumulator + ret + + +compcdr: ;return cy if cdrmax > dcnt + ld hl,(dcnt) + ex de,hl ;DE = directory counter + ld hl,(cdrmaxa) ;HL=.cdrmax + ld a,e + sub (hl) ;low(dcnt) - low(cdrmax) + inc hl ;HL = .cdrmax+1 + ld a,d + sbc a,(hl) ;hig(dcnt) - hig(cdrmax) + ;condition dcnt - cdrmax produces cy if cdrmax>dcnt + ret + +setcdr: ;if not (cdrmax > dcnt) then cdrmax = dcnt+1 + call compcdr + ret c ;return if cdrmax > dcnt + ;otherwise, HL = .cdrmax+1, DE = dcnt + inc de + ld (hl),d + dec hl + ld (hl),e + ret + +subdh: ;compute HL = DE - HL + ld a,e + sub l + ld l,a + ld a,d + sbc a,h + ld h,a + ret + +newchecksum: + ld c,true ;drop through to compute new checksum +checksum: ;compute current checksum record and update the + ;directory element if C=true, or check for = if not + ;drec < chksiz? + ld hl,(drec) + ex de,hl + ld hl,(chksiz) + call subdh ;DE-HL + ret nc ;skip checksum if past checksum vector size + ;drec < chksiz, so continue + push bc ;save init flag + call compute$cs ;check sum value to A + ld hl,(checka) ;address of check sum vector + ex de,hl + ld hl,(drec) ;value of drec + add hl,de ;HL = .check(drec) + pop bc ;recall true=0ffh or false=00 to C + inc c ;0ffh produces zero flag + jp z,initial$cs + ;not initializing, compare + cp (hl) ;compute$cs=check(drec)? + ret z ;no message if ok + ;checksum error, are we beyond + ;the end of the disk? + call compcdr + ret nc ;no message if so + call set$ro ;read/only disk set + ret + +initial$cs: ;initializing the checksum + ld (hl),a + ret + + +wrdir: ;write the current directory entry, set checksum + call newchecksum ;initialize entry + call setdir ;directory dma + ld c,1 ;indicates a write directory operation + call wrbuff ;write the buffer + jp setdata ;to data dma address +; ret +rd$dir: ;read a directory entry into the directory buffer + call setdir ;directory dma + call rdbuff ;directory record loaded + ;jmp setdata to data dma address +; ret +setdata: ;set data dma address + ld hl,dmaad + jp setdma ;to complete the call + +setdir: ;set directory dma address + ld hl,buffa ;jmp setdma to complete call + +setdma: ;HL=.dma address to set (i.e., buffa or dmaad) + ld c,(hl) + inc hl + ld b,(hl) ;parameter ready + jp setdmaf + +dir$to$user: ;copy the directory entry to the user buffer + ;after call to search or searchn by user code + ld hl,(buffa) + ex de,hl ;source is directory buffer + ld hl,(dmaad) ;destination is user dma address + ld c,recsiz ;copy entire record + jp move +; ret + +end$of$dir: ;return zero flag if at end of directory, non zero + ;if not at end (end of dir if dcnt = 0ffffh) + ld hl,dcnt + ld a,(hl) ;may be 0ffh + inc hl + cp (hl) ;low(dcnt) = high(dcnt)? + ret nz ;non zero returned if different + ;high and low the same, = 0ffh? + inc a ;0ffh becomes 00 if so + ret + +set$end$dir: ;set dcnt to the end of the directory + ld hl,enddir + ld (dcnt),hl + ret + +read$dir: ;read next directory entry, with C=true if initializing + ld hl,(dirmax) + ex de,hl ;in preparation for subtract + ld hl,(dcnt) + inc hl + ld (dcnt),hl ;dcnt=dcnt+1 + ;continue while dirmax >= dcnt (dirmax-dcnt no cy) + call subdh ;DE-HL + jp nc,read$dir0 + ;yes, set dcnt to end of directory + jp set$end$dir +; ret + +read$dir0: ;not at end of directory, seek next element + ;initialization flag is in C + ld a,(dcnt) + and dskmsk ;low(dcnt) and dskmsk + ld b,fcbshf ;to multiply by fcb size +read$dir1: + add a,a + dec b + jp nz,read$dir1 + ;A = (low(dcnt) and dskmsk) shl fcbshf + ld (dptr),a ;ready for next dir operation + or a + ret nz ;return if not a new record + push bc ;save initialization flag C + call seek$dir ;seek proper record + call rd$dir ;read the directory record + pop bc ;recall initialization flag + jp checksum ;checksum the directory elt +; ret + + +getallocbit: ;given allocation vector position BC, return with byte + ;containing BC shifted so that the least significant + ;bit is in the low order accumulator position. HL is + ;the address of the byte for possible replacement in + ;memory upon return, and D contains the number of shifts + ;required to place the returned value back into position + ld a,c + +;; and 111b + and 0b00000111 + + inc a + ld e,a + ld d,a + ;d and e both contain the number of bit positions to shift + ld a,c + rrca + rrca + rrca + +; and 11111b + and 0b00011111 + + ld c,a ;C shr 3 to C + ld a,b + add a,a + add a,a + add a,a + add a,a + add a,a ;B shl 5 + or c + ld c,a ;bbbccccc to C + ld a,b + rrca + rrca + rrca + +;; and 11111b + and 0b00011111 + + ld b,a ;BC shr 3 to BC + ld hl,(alloca) ;base address of allocation vector + add hl,bc + ld a,(hl) ;byte to A, hl = .alloc(BC shr 3) + ;now move the bit to the low order position of A +rotl: rlca + dec e + jp nz,rotl + ret + + +set$alloc$bit: ;BC is the bit position of ALLOC to set or reset. The + ;value of the bit is in register E. + push de + call getallocbit ;shifted val A, count in D + +;; and 11111110b ;mask low bit to zero (may be set) + and 0b11111110 + + or c ;low bit of C is masked into A +; jp rotr ;to rotate back into proper position +; ret +rotr: + ;byte value from ALLOC is in register A, with shift count + ;in register C (to place bit back into position), and + ;target ALLOC position in registers HL, rotate and replace + rrca + dec d + jp nz,rotr ;back into position + ld (hl),a ;back to ALLOC + ret + +scandm: ;scan the disk map addressed by dptr for non-zero + ;entries, the allocation vector entry corresponding + ;to a non-zero entry is set to the value of C (0,1) + call getdptra ;HL = buffa + dptr + ;HL addresses the beginning of the directory entry + ld de,dskmap + add hl,de ;hl now addresses the disk map + push bc ;save the 0/1 bit to set + ld c,fcblen-dskmap+1;size of single byte disk map + 1 +scandm0: ;loop once for each disk map entry + pop de ;recall bit parity + dec c + ret z ;all done scanning? + ;no, get next entry for scan + push de ;replace bit parity + ld a,(single) + or a + jp z,scandm1 + ;single byte scan operation + push bc ;save counter + push hl ;save map address + ld c,(hl) + ld b,0 ;BC=block# + jp scandm2 + +scandm1: ;double byte scan operation + dec c ;count for double byte + push bc ;save counter + ld c,(hl) + inc hl + ld b,(hl) ;BC=block# + push hl ;save map address +scandm2: ;arrive here with BC=block#, E=0/1 + ld a,c + or b ;skip if = 0000 + jp z,scanm3 + ld hl,(maxall) ;check invalid index + ld a,l + sub c + ld a,h + sbc a,b ;maxall - block# + call nc,set$alloc$bit + ;bit set to 0/1 +scanm3: pop hl + inc hl ;to next bit position + pop bc ;recall counter + jp scandm0 ;for another item + +initialize: ;initialize the current disk + ;lret = false ;set to true if $ file exists + ;compute the length of the allocation vector - 2 + ld hl,(maxall) + ld c,3 ;perform maxall/8 + ;number of bytes in alloc vector is (maxall/8)+1 + call hlrotr + inc hl ;HL = maxall/8+1 + ld b,h + ld c,l ;count down BC til zero + ld hl,(alloca) ;base of allocation vector + ;fill the allocation vector with zeros +initial0: + ld (hl),0 + inc hl ;alloc(i)=0 + dec bc ;count length down + ld a,b + or c + jp nz,initial0 + ;set the reserved space for the directory + ld hl,(dirblk) + ex de,hl + ld hl,(alloca) ;HL=.alloc() + ld (hl),e + inc hl + ld (hl),d ;sets reserved directory blks + ;allocation vector initialized, home disk + call home + ;cdrmax = 3 (scans at least one directory record) + ld hl,(cdrmaxa) + ld (hl),3 + inc hl + ld (hl),0 + ;cdrmax = 0000 + call set$end$dir ;dcnt = enddir + ;read directory entries and check for allocated storage +initial2: + ld c,true + call read$dir + call end$of$dir + ret z ;return if end of directory + ;not end of directory, valid entry? + call getdptra ;HL = buffa + dptr + ld a,empty + cp (hl) + jp z,initial2 ;go get another item + ;not empty, user code the same? + ld a,(usrcode) + cp (hl) + jp nz,pdollar + ;same user code, check for '$' submit + inc hl + ld a,(hl) ;first character + sub '$' ;dollar file? + jp nz,pdollar + ;dollar file found, mark in lret + dec a + ld (lret),a ;lret = 255 +pdollar: ;now scan the disk map for allocated blocks + ld c,1 ;set to allocated + call scandm + call setcdr ;set cdrmax to dcnt + jp initial2 ;for another entry + +copy$dirloc: ;copy directory location to lret following + ;delete, rename, ... ops + ld a,(dirloc) + jp sta$ret +; ret + +compext: ;compare extent# in A with that in C, return nonzero + ;if they do not match + push bc ;save C's original value + push af + ld a,(extmsk) + cpl + ld b,a + ;B has negated form of extent mask + ld a,c + and b + ld c,a ;low bits removed from C + pop af + and b ;low bits removed from A + sub c + and maxext ;set flags + pop bc ;restore original values + ret + +search: ;search for directory element of length C at info + +;; ld a,0ffh + ld a,0xff + + ld (dirloc),a ;changed if actually found + ld hl,searchl + ld (hl),c ;searchl = C + ld hl,(info) + ld (searcha),hl ;searcha = info + call set$end$dir ;dcnt = enddir + call home ;to start at the beginning + ;(drop through to searchn) + +searchn: ;search for the next directory element, assuming + ;a previous call on search which sets searcha and + ;searchl + ld c,false + call read$dir ;read next dir element + call end$of$dir + jp z,search$fin ;skip to end if so + ;not end of directory, scan for match + ld hl,(searcha) + ex de,hl ;DE=beginning of user fcb + ld a,(de) ;first character + cp empty ;keep scanning if empty + jp z,searchnext + ;not empty, may be end of logical directory + push de ;save search address + call compcdr ;past logical end? + pop de ;recall address + jp nc,search$fin ;artificial stop +searchnext: + call getdptra ;HL = buffa+dptr + ld a,(searchl) + ld c,a ;length of search to c + ld b,0 ;b counts up, c counts down +searchloop: + ld a,c + or a + jp z,endsearch + ld a,(de) + cp '?' + jp z,searchok ;? matches all + ;scan next character if not ubytes + ld a,b + cp ubytes + jp z,searchok + ;not the ubytes field, extent field? + cp extnum ;may be extent field + ld a,(de) ;fcb character + jp z,searchext ;skip to search extent + sub (hl) + and 7fh ;mask-out flags/extent modulus + jp nz,searchn ;skip if not matched + jp searchok ;matched character + +searchext: ;A has fcb character + ;attempt an extent # match + push bc ;save counters + ld c,(hl) ;directory character to c + call compext ;compare user/dir char + pop bc ;recall counters + jp nz,searchn ;skip if no match +searchok: ;current character matches + inc de + inc hl + inc b + dec c + jp searchloop + +endsearch: ;entire name matches, return dir position + ld a,(dcnt) + and dskmsk + ld (lret),a + ;lret = low(dcnt) and 11b + ld hl,dirloc + ld a,(hl) + rla + ret nc ;dirloc=0ffh? + ;yes, change it to 0 to mark as found + xor a + ld (hl),a ;dirloc=0 + ret + +search$fin: ;end of directory, or empty name + call set$end$dir ;may be artifical end + ld a,255 + jp sta$ret + +delete: ;delete the currently addressed file + call check$write ;write protected? + ld c,extnum + call search ;search through file type +delete0: + ;loop while directory matches + call end$of$dir + ret z ;stop if end + ;set each non zero disk map entry to 0 + ;in the allocation vector + ;may be r/o file + call check$rodir ;ro disk error if found + call getdptra ;HL=.buff(dptr) + ld (hl),empty + ld c,0 + call scandm ;alloc elts set to 0 + call wrdir ;write the directory + call searchn ;to next element + jp delete0 ;for another record + +get$block: ;given allocation vector position BC, find the zero bit + ;closest to this position by searching left and right. + ;if found, set the bit to one and return the bit position + ;in hl. if not found (i.e., we pass 0 on the left, or + ;maxall on the right), return 0000 in hl + ld d,b + ld e,c ;copy of starting position to de +lefttst: + ld a,c + or b + jp z,righttst ;skip if left=0000 + ;left not at position zero, bit zero? + dec bc + push de + push bc ;left,right pushed + call getallocbit + rra + jp nc,retblock ;return block number if zero + ;bit is one, so try the right + pop bc + pop de ;left, right restored +righttst: + ld hl,(maxall) ;value of maximum allocation# + ld a,e + sub l + ld a,d + sbc a,h ;right=maxall? + jp nc,retblock0 ;return block 0000 if so + inc de + push bc + push de ;left, right pushed + ld b,d + ld c,e ;ready right for call + call getallocbit + rra + jp nc,retblock ;return block number if zero + pop de + pop bc ;restore left and right pointers + jp lefttst ;for another attempt +retblock: + rla + inc a ;bit back into position and set to 1 + ;d contains the number of shifts required to reposition + call rotr ;move bit back to position and store + pop hl + pop de ;HL returned value, DE discarded + ret + +retblock0: ;cannot find an available bit, return 0000 + ld a,c + or b + jp nz,lefttst ;also at beginning + ld hl,0000h + ret + +copy$fcb: ;copy the entire file control block + ld c,0 + ld e,fcblen ;start at 0, to fcblen-1 +; jp copy$dir + +copy$dir: ;copy fcb information starting at C for E bytes + ;into the currently addressed directory entry + push de ;save length for later + ld b,0 ;double index to BC + ld hl,(info) ;HL = source for data + add hl,bc + ex de,hl ;DE=.fcb(C), source for copy + call getdptra ;HL=.buff(dptr), destination + pop bc ;DE=source, HL=dest, C=length + call move ;data moved +seek$copy: ;enter from close to seek and copy current element + call seek$dir ;to the directory element + jp wrdir ;write the directory element +; ret +rename: ;rename the file described by the first half of + ;the currently addressed file control block. the + ;new name is contained in the last half of the + ;currently addressed file conrol block. the file + ;name and type are changed, but the reel number + ;is ignored. the user number is identical + call check$write ;may be write protected + ;search up to the extent field + ld c,extnum + call search + ;copy position 0 + ld hl,(info) + ld a,(hl) ;HL=.fcb(0), A=fcb(0) + ld de,dskmap + add hl,de ;HL=.fcb(dskmap) + ld (hl),a ;fcb(dskmap)=fcb(0) + ;assume the same disk drive for new named file +rename0: + call end$of$dir + ret z ;stop at end of dir + ;not end of directory, rename next element + call check$rodir ;may be read-only file + ld c,dskmap + ld e,extnum + call copy$dir + ;element renamed, move to next + call searchn + jp rename0 + +indicators: ;set file indicators for current fcb + ld c,extnum + call search ;through file type +indic0: call end$of$dir + ret z ;stop at end of dir + ;not end of directory, continue to change + ld c,0 + ld e,extnum ;copy name + call copy$dir + call searchn + jp indic0 + +open: ;search for the directory entry, copy to fcb + ld c,namlen + call search + call end$of$dir + ret z ;return with lret=255 if end + ;not end of directory, copy fcb information +open$copy: ;(referenced below to copy fcb info) + call getexta + ld a,(hl) + push af + push hl ;save extent# + call getdptra + ex de,hl ;DE = .buff(dptr) + ld hl,(info) ;HL=.fcb(0) + ld c,nxtrec ;length of move operation + push de ;save .buff(dptr) + call move ;from .buff(dptr) to .fcb(0) + ;note that entire fcb is copied, including indicators + call setfwf ;sets file write flag + pop de + ld hl,extnum + add hl,de ;HL=.buff(dptr+extnum) + ld c,(hl) ;C = directory extent number + ld hl,reccnt + add hl,de ;HL=.buff(dptr+reccnt) + ld b,(hl) ;B holds directory record count + pop hl + pop af + ld (hl),a ;restore extent number + ;HL = .user extent#, B = dir rec cnt, C = dir extent# + ;if user ext < dir ext then user := 128 records + ;if user ext = dir ext then user := dir records + ;if user ext > dir ext then user := 0 records + ld a,c + cp (hl) + ld a,b ;ready dir reccnt + jp z,open$rcnt ;if same, user gets dir reccnt + ld a,0 + jp c,open$rcnt ;user is larger + ld a,128 ;directory is larger +open$rcnt: ;A has record count to fill + ld hl,(info) + ld de,reccnt + add hl,de + ld (hl),a + ret + +mergezero: ;HL = .fcb1(i), DE = .fcb2(i), + ;if fcb1(i) = 0 then fcb1(i) := fcb2(i) + ld a,(hl) + inc hl + or (hl) + dec hl + ret nz ;return if = 0000 + ld a,(de) + ld (hl),a + inc de + inc hl ;low byte copied + ld a,(de) + ld (hl),a + dec de + dec hl ;back to input form + ret + +close: ;locate the directory element and re-write it + xor a + ld (lret),a + ld (dcnt),a + ld (dcnt+1),a + call nowrite + ret nz ;skip close if r/o disk + ;check file write flag - 0 indicates written + call getmodnum ;fcb(modnum) in A + and fwfmsk + ret nz ;return if bit remains set + ld c,namlen + call search ;locate file + call end$of$dir + ret z ;return if not found + ;merge the disk map at info with that at buff(dptr) + ld bc,dskmap + call getdptra + add hl,bc + ex de,hl ;DE is .buff(dptr+16) + ld hl,(info) + add hl,bc ;DE=.buff(dptr+16), HL=.fcb(16) + ld c,fcblen-dskmap;length of single byte dm +merge0: ld a,(single) + or a + jp z,merged ;skip to double + ;this is a single byte map + ;if fcb(i) = 0 then fcb(i) = buff(i) + ;if buff(i) = 0 then buff(i) = fcb(i) + ;if fcb(i) <> buff(i) then error + ld a,(hl) + or a + ld a,(de) + jp nz,fcbnzero + ;fcb(i) = 0 + ld (hl),a ;fcb(i) = buff(i) +fcbnzero: + or a + jp nz,buffnzero + ;buff(i) = 0 + ld a,(hl) + ld (de),a ;buff(i)=fcb(i) +buffnzero: + cp (hl) + jp nz,mergerr ;fcb(i) = buff(i)? + jp dmset ;if merge ok + +merged: ;this is a double byte merge operation + call mergezero ;buff = fcb if buff 0000 + ex de,hl + call mergezero + ex de,hl ;fcb = buff if fcb 0000 + ;they should be identical at this point + ld a,(de) + cp (hl) + jp nz,mergerr ;low same? + inc de + inc hl ;to high byte + ld a,(de) + cp (hl) + jp nz,mergerr ;high same? + ;merge operation ok for this pair + dec c ;extra count for double byte +dmset: inc de + inc hl ;to next byte position + dec c + jp nz,merge0 ;for more + ;end of disk map merge, check record count + ;DE = .buff(dptr)+32, HL = .fcb(32) + ld bc,-(fcblen-extnum) + add hl,bc + ex de,hl + add hl,bc + ;DE = .fcb(extnum), HL = .buff(dptr+extnum) + ld a,(de) ;current user extent number + ;if fcb(ext) >= buff(fcb) then + ;buff(ext) := fcb(ext), buff(rec) := fcb(rec) + cp (hl) + jp c,endmerge + ;fcb extent number >= dir extent number + ld (hl),a ;buff(ext) = fcb(ext) + ;update directory record count field + ld bc,reccnt-extnum + add hl,bc + ex de,hl + add hl,bc + ;DE=.buff(reccnt), HL=.fcb(reccnt) + ld a,(hl) + ld (de),a ;buff(reccnt)=fcb(reccnt) +endmerge: + ld a,true + ld (fcb$copied),a ;mark as copied + jp seek$copy ;ok to "wrdir" here - 1.4 compat + ; ret + +mergerr: ;elements did not merge correctly + ld hl,lret + dec (hl) ;=255 non zero flag set + ret + +make: ;create a new file by creating a directory entry + ;then opening the file + call check$write ;may be write protected + ld hl,(info) + push hl ;save fcb address, look for e5 + ld hl,efcb + ld (info),hl ;info = .empty + ld c,1 + call search ;length 1 match on empty entry + call end$of$dir ;zero flag set if no space + pop hl ;recall info address + ld (info),hl ;in case we return here + ret z ;return with error condition 255 if not found + ex de,hl ;DE = info address + ;clear the remainder of the fcb + ld hl,namlen + add hl,de ;HL=.fcb(namlen) + ld c,fcblen-namlen ;number of bytes to fill + xor a ;clear accumulator to 00 for fill +make0: ld (hl),a + inc hl + dec c + jp nz,make0 + ld hl,ubytes + add hl,de ;HL = .fcb(ubytes) + ld (hl),a ;fcb(ubytes) = 0 + call setcdr ;may have extended the directory + ;now copy entry to the directory + call copy$fcb + ;and set the file write flag to "1" + jp setfwf +; ret + +open$reel: ;close the current extent, and open the next one + ;if possible. RMF is true if in read mode + xor a + ld (fcb$copied),a ;set true if actually copied + call close ;close current extent + ;lret remains at enddir if we cannot open the next ext + call end$of$dir + ret z ;return if end + ;increment extent number + ld hl,(info) + ld bc,extnum + add hl,bc ;HL=.fcb(extnum) + ld a,(hl) + inc a + and maxext + ld (hl),a ;fcb(extnum)=++1 + jp z,open$mod ;move to next module if zero + ;may be in the same extent group + ld b,a + ld a,(extmsk) + and b + ;if result is zero, then not in the same group + ld hl,fcb$copied ;true if the fcb was copied to directory + and (hl) ;produces a 00 in accumulator if not written + jp z,open$reel0 ;go to next physical extent + ;result is non zero, so we must be in same logical ext + jp open$reel1 ;to copy fcb information +open$mod: ;extent number overflow, go to next module + ld bc,modnum-extnum + add hl,bc ;HL=.fcb(modnum) + inc (hl) ;fcb(modnum)=++1 + ;module number incremented, check for overflow + ld a,(hl) + and maxmod ;mask high order bits + jp z,open$r$err ;cannot overflow to zero + ;otherwise, ok to continue with new module +open$reel0: + ld c,namlen + call search ;next extent found? + call end$of$dir + jp nz,open$reel1 + ;end of file encountered + ld a,(rmf) + inc a ;0ffh becomes 00 if read + jp z,open$r$err ;sets lret = 1 + ;try to extend the current file + call make + ;cannot be end of directory + call end$of$dir + jp z,open$r$err ;with lret = 1 + jp open$reel2 + +open$reel1: ;not end of file, open + call open$copy +open$reel2: + call getfcb ;set parameters + xor a + jp sta$ret ;lret = 0 +; ret ;with lret = 0 + +open$r$err: ;cannot move to next extent of this file + call setlret1 ;lret = 1 + jp setfwf ;ensure that it will not be closed +; ret + +seqdiskread: ;sequential disk read operation + ld a,1 + ld (seqio),a + ;drop through to diskread + +diskread: ;(may enter from seqdiskread) + ld a,true + ld (rmf),a ;read mode flag = true (open$reel) + ;read the next record from the current fcb + call getfcb ;sets parameters for the read + ld a,(vrecord) + ld hl,rcount + cp (hl) ;vrecord-rcount + ;skip if rcount > vrecord + jp c,recordok + ;not enough records in the extent + ;record count must be 128 to continue + cp 128 ;vrecord = 128? + jp nz,diskeof ;skip if vrecord<>128 + call open$reel ;go to next extent if so + xor a + ld (vrecord),a ;vrecord=00 + ;now check for open ok + ld a,(lret) + or a + jp nz,diskeof ;stop at eof +recordok: ;arrive with fcb addressing a record to read + call index + ;error 2 if reading unwritten data + ;(returns 1 to be compatible with 1.4) + call allocated ;arecord=0000? + jp z,diskeof + ;record has been allocated, read it + call atran ;arecord now a disk address + call seek ;to proper track,sector + call rdbuff ;to dma address + jp setfcb ;replace parameter +; ret + +diskeof: + jp setlret1 ;lret = 1 +; ret + +seqdiskwrite: ;sequential disk write + ld a,1 + ld (seqio),a + ;drop through to diskwrite + +diskwrite: ;(may enter here from seqdiskwrite above) + ld a,false + ld (rmf),a ;read mode flag + ;write record to currently selected file + call check$write ;in case write protected + ld hl,(info) ;HL = .fcb(0) + call check$rofile ;may be a read-only file + call getfcb ;to set local parameters + ld a,(vrecord) + cp lstrec+1 ;vrecord-128 + ;skip if vrecord > lstrec + ;vrecord = 128, cannot open next extent + jp nc,setlret1 ;lret=1 +diskwr0: ;can write the next record, so continue + call index + call allocated + ld c,0 ;marked as normal write operation for wrbuff + jp nz,diskwr1 + ;not allocated + ;the argument to getblock is the starting + ;position for the disk search, and should be + ;the last allocated block for this file, or + ;the value 0 if no space has been allocated + call dm$position + ld (dminx),a ;save for later + ld bc,0000h ;may use block zero + or a + jp z,nopblock ;skip if no previous block + ;previous block exists at A + ld c,a + dec bc ;previous block # in BC + call getdm ;previous block # to HL + ld b,h + ld c,l ;BC=prev block# +nopblock: ;BC = 0000, or previous block # + call get$block ;block # to HL + ;arrive here with block# or zero + ld a,l + or h + jp nz,blockok + ;cannot find a block to allocate + ld a,2 + jp sta$ret ;lret=2 + +blockok: ;allocated block number is in HL + ld (arecord),hl + ex de,hl ;block number to DE + ld hl,(info) + ld bc,dskmap + add hl,bc ;HL=.fcb(dskmap) + ld a,(single) + or a ;set flags for single byte dm + ld a,(dminx) ;recall dm index + jp z,allocwd ;skip if allocating word + ;allocating a byte value + call addh + ld (hl),e ;single byte alloc + jp diskwru ;to continue + +allocwd: ;allocate a word value + ld c,a + ld b,0 ;double(dminx) + add hl,bc + add hl,bc ;HL=.fcb(dminx*2) + ld (hl),e + inc hl + ld (hl),d ;double wd +diskwru: ;disk write to previously unallocated block + ld c,2 ;marked as unallocated write +diskwr1: ;continue the write operation of no allocation error + ;C = 0 if normal write, 2 if to prev unalloc block + ld a,(lret) + or a + ret nz ;stop if non zero returned value + push bc ;save write flag + call atran ;arecord set + ld a,(seqio) + dec a + dec a + jp nz,diskwr11 + pop bc + push bc + ld a,c + dec a + dec a + jp nz,diskwr11 ;old allocation + push hl ;arecord in hl ret from atran + ld hl,(buffa) + ld d,a ;zero buffa & fill +fill0: ld (hl),a + inc hl + inc d + jp p,fill0 + call setdir + ld hl,(arecord1) + ld c,2 +fill1: ld (arecord),hl + push bc + call seek + pop bc + call wrbuff ;write fill record + ld hl,(arecord) ;restore last record + ld c,0 ;change allocate flag + ld a,(blkmsk) + ld b,a + and l + cp b + inc hl + jp nz,fill1 ;cont until cluster is zeroed + pop hl + ld (arecord),hl + call setdata +diskwr11: + call seek ;to proper file position + pop bc + push bc ;restore/save write flag (C=2 if new block) + call wrbuff ;written to disk + pop bc ;C = 2 if a new block was allocated, 0 if not + ;increment record count if rcount<=vrecord + ld a,(vrecord) + ld hl,rcount + cp (hl) ;vrecord-rcount + jp c,diskwr2 + ;rcount <= vrecord + ld (hl),a + inc (hl) ;rcount = vrecord+1 + ld c,2 ;mark as record count incremented +diskwr2: ;A has vrecord, C=2 if new block or new record# + dec c + dec c + jp nz,noupdate + push af ;save vrecord value + call getmodnum ;HL=.fcb(modnum), A=fcb(modnum) + ;reset the file write flag to mark as written fcb + and (not fwfmsk) and 0ffh;bit reset + ld (hl),a ;fcb(modnum) = fcb(modnum) and 7fh + pop af ;restore vrecord +noupdate: ;check for end of extent, if found attempt to open + ;next extent in preparation for next write + cp lstrec ;vrecord=lstrec? + jp nz,diskwr3 ;skip if not + ;may be random access write, if so we are done + ;change next + ld a,(seqio) + cp 1 + jp nz,diskwr3 ;skip next extent open op + ;update current fcb before going to next extent + call setfcb + call open$reel ;rmf=false + ;vrecord remains at lstrec causing eof if + ;no more directory space is available + ld hl,lret + ld a,(hl) + or a + jp nz,nospace + ;space available, set vrecord=255 + dec a + ld (vrecord),a ;goes to 00 next time +nospace: + ld (hl),0 ;lret = 00 for returned value +diskwr3: + jp setfcb ;replace parameters +; ret + +rseek: ;random access seek operation, C=0ffh if read mode + ;fcb is assumed to address an active file control block + ;(modnum has been set to 1100$0000b if previous bad seek) + xor a + ld (seqio),a ;marked as random access operation +rseek1: push bc ;save r/w flag + ld hl,(info) + ex de,hl ;DE will hold base of fcb + ld hl,ranrec + add hl,de ;HL=.fcb(ranrec) + ld a,(hl) + and 7fh + push af ;record number + ld a,(hl) + rla ;cy=lsb of extent# + inc hl + ld a,(hl) + rla + and 11111b ;A=ext# + ld c,a ;C holds extent number, record stacked + ld a,(hl) + rra + rra + rra + rra + and 1111b ;mod# + ld b,a ;B holds module#, C holds ext# + pop af ;recall sought record # + ;check to insure that high byte of ran rec = 00 + inc hl + ld l,(hl) ;l=high byte (must be 00) + inc l + dec l + ld l,6 ;zero flag, l=6 + ;produce error 6, seek past physical eod + jp nz,seekerr + ;otherwise, high byte = 0, A = sought record + ld hl,nxtrec + add hl,de ;HL = .fcb(nxtrec) + ld (hl),a ;sought rec# stored away + ;arrive here with B=mod#, C=ext#, DE=.fcb, rec stored + ;the r/w flag is still stacked. compare fcb values + ld hl,extnum + add hl,de + ld a,c ;A=seek ext# + sub (hl) + jp nz,ranclose ;tests for = extents + ;extents match, check mod# + ld hl,modnum + add hl,de + ld a,b ;B=seek mod# + ;could be overflow at eof, producing module# + ;of 90H or 10H, so compare all but fwf + sub (hl) + and 7fh + jp z,seekok ;same? +ranclose: + push bc + push de ;save seek mod#,ext#, .fcb + call close ;current extent closed + pop de + pop bc ;recall parameters and fill + ld l,3 ;cannot close error #3 + ld a,(lret) + inc a + jp z,badseek + ld hl,extnum + add hl,de + ld (hl),c ;fcb(extnum)=ext# + ld hl,modnum + add hl,de + ld (hl),b ;fcb(modnum)=mod# + call open ;is the file present? + ld a,(lret) + inc a + jp nz,seekok ;open successful? + ;cannot open the file, read mode? + pop bc ;r/w flag to c (=0ffh if read) + push bc ;everyone expects this item stacked + ld l,4 ;seek to unwritten extent #4 + inc c ;becomes 00 if read operation + jp z,badseek ;skip to error if read operation + ;write operation, make new extent + call make + ld l,5 ;cannot create new extent #5 + ld a,(lret) + inc a + jp z,badseek ;no dir space + ;file make operation successful +seekok: + pop bc ;discard r/w flag + xor a + jp sta$ret ;with zero set +badseek: ;fcb no longer contains a valid fcb, mark + ;with 1100$000b in modnum field so that it + ;appears as overflow with file write flag set + push hl ;save error flag + call getmodnum ;HL = .modnum + ld (hl),11000000b + pop hl ;and drop through +seekerr: + pop bc ;discard r/w flag + ld a,l + ld (lret),a ;lret=#, nonzero + ;setfwf returns non-zero accumulator for err + jp setfwf ;flag set, so subsequent close ok +; ret + +randiskread: ;random disk read operation + ld c,true ;marked as read operation + call rseek + call z,diskread ;if seek successful + ret + +randiskwrite: ;random disk write operation + ld c,false ;marked as write operation + call rseek + call z,diskwrite ;if seek successful + ret + +compute$rr: ;compute random record position for getfilesize/setrandom + ex de,hl + add hl,de + ;DE=.buf(dptr) or .fcb(0), HL = .f(nxtrec/reccnt) + ld c,(hl) + ld b,0 ;BC = 0000 0000 ?rrr rrrr + ld hl,extnum + add hl,de + ld a,(hl) + rrca + and 80h ;A=e000 0000 + add a,c + ld c,a + ld a,0 + adc a,b + ld b,a + ;BC = 0000 000? errrr rrrr + ld a,(hl) + rrca + and 0fh + add a,b + ld b,a + ;BC = 000? eeee errrr rrrr + ld hl,modnum + add hl,de + ld a,(hl) ;A=XXX? mmmm + add a,a + add a,a + add a,a + add a,a ;cy=? A=mmmm 0000 + push af + add a,b + ld b,a + ;cy=?, BC = mmmm eeee errr rrrr + push af ;possible second carry + pop hl ;cy = lsb of L + ld a,l ;cy = lsb of A + pop hl ;cy = lsb of L + or l ;cy/cy = lsb of A + and 1 ;A = 0000 000? possible carry-out + ret + +getfilesize: ;compute logical file size for current fcb + ld c,extnum + call search + ;zero the receiving ranrec field + ld hl,(info) + ld de,ranrec + add hl,de + push hl ;save position + ld (hl),d + inc hl + ld (hl),d + inc hl + ld (hl),d ;=00 00 00 +getsize: + call end$of$dir + jp z,setsize + ;current fcb addressed by dptr + call getdptra + ld de,reccnt ;ready for compute size + call compute$rr + ;A=0000 000? BC = mmmm eeee errr rrrr + ;compare with memory, larger? + pop hl + push hl ;recall, replace .fcb(ranrec) + ld e,a ;save cy + ld a,c + sub (hl) + inc hl ;ls byte + ld a,b + sbc a,(hl) + inc hl ;middle byte + ld a,e + sbc a,(hl) ;carry if .fcb(ranrec) > directory + jp c,getnextsize ;for another try + ;fcb is less or equal, fill from directory + ld (hl),e + dec hl + ld (hl),b + dec hl + ld (hl),c +getnextsize: + call searchn + jp getsize + +setsize: + pop hl ;discard .fcb(ranrec) + ret + +setrandom: ;set random record from the current file control block + ld hl,(info) + ld de,nxtrec ;ready params for computesize + call compute$rr ;DE=info, A=cy, BC=mmmm eeee errr rrrr + ld hl,ranrec + add hl,de ;HL = .fcb(ranrec) + ld (hl),c + inc hl + ld (hl),b + inc hl + ld (hl),a ;to ranrec + ret + +select: ;select disk info for subsequent input or output ops + ld hl,(dlog) + ld a,(curdsk) + ld c,a + call hlrotr + push hl + ex de,hl ;save it for test below, send to seldsk + call selectdisk + pop hl ;recall dlog vector + call z,sel$error ;returns true if select ok + ;is the disk logged in? + ld a,l + rra + ret c ;return if bit is set + ;disk not logged in, set bit and initialize + ld hl,(dlog) + ld c,l + ld b,h ;call ready + call set$cdisk + ld (dlog),hl ;dlog=set$cdisk(dlog) + jp initialize +; ret + +curselect: + ld a,(linfo) + ld hl,curdsk + cp (hl) + ret z ;skip if linfo=curdsk + ld (hl),a ;curdsk=info + jp select +; ret + +reselect: ;check current fcb to see if reselection necessary + ld a,true + ld (resel),a ;mark possible reselect + ld hl,(info) + ld a,(hl) ;drive select code + and 11111b ;non zero is auto drive select + dec a ;drive code normalized to 0..30, or 255 + ld (linfo),a ;save drive code + cp 30 + jp nc,noselect + ;auto select function, save curdsk + ld a,(curdsk) + ld (olddsk),a ;olddsk=curdsk + ld a,(hl) + ld (fcbdsk),a ;save drive code + +;; and 11100000b + and 0b11100000 + + ld (hl),a ;preserve hi bits + call curselect +noselect: ;set user code + ld a,(usrcode) ;0...31 + ld hl,(info) + or (hl) + ld (hl),a + ret + +; individual function handlers +func12: ;return version number + ld a,dvers + jp sta$ret ;lret = dvers (high = 00) +; ret +; jp goback + +func13: ;reset disk system - initialize to disk 0 + ld hl,0 + ld (rodsk),hl + ld (dlog),hl + xor a + ld (curdsk),a ;note that usrcode remains unchanged + ld hl,tbuff + ld (dmaad),hl ;dmaad = tbuff + call setdata ;to data dma address + jp select +; ret +; jp goback + +func14 equ curselect ;select disk info +; ret +; jp goback + +func15: ;open file + call clrmodnum ;clear the module number + call reselect + jp open +; ret +; jp goback + +func16: ;close file + call reselect + jp close +; ret +; jp goback + +func17: ;search for first occurrence of a file + ld c,0 ;length assuming '?' true + ex de,hl ;was lhld info + ld a,(hl) + cp '?' ;no reselect if ? + jp z,qselect ;skip reselect if so + ;normal search + call getexta + ld a,(hl) + cp '?' ; + call nz,clrmodnum ;module number zeroed + call reselect + ld c,namlen +qselect: + call search + jp dir$to$user ;copy directory entry to user +; ret +; jp goback + +func18: ;search for next occurrence of a file name + ld hl,(searcha) + ld (info),hl + call reselect + call searchn + jp dir$to$user ;copy directory entry to user +; ret +; jp goback + +func19: ;delete a file + call reselect + call delete + jp copy$dirloc +; ret +; jp goback + +func20: ;read a file + call reselect + jp seqdiskread +; jp goback + +func21: ;write a file + call reselect + jp seqdiskwrite +; jp goback + +func22: ;make a file + call clrmodnum + call reselect + jp make +; ret +; jp goback + +func23: ;rename a file + call reselect + call rename + jp copy$dirloc +; ret +; jp goback + +func24: ;return the login vector + ld hl,(dlog) + jp sthl$ret +; ret +; jp goback + +func25: ;return selected disk number + ld a,(curdsk) + jp sta$ret +; ret +; jp goback + +func26: ;set the subsequent dma address to info + ex de,hl ;was lhld info + ld (dmaad),hl ;dmaad = info + jp setdata ;to data dma address +; ret +; jp goback + +func27: ;return the login vector address + ld hl,(alloca) + jp sthl$ret +; ret +; jp goback + +func28 equ set$ro + ;write protect current disk +; ret +; jp goback + +func29: ;return r/o bit vector + ld hl,(rodsk) + jp sthl$ret +; ret +; jp goback + +func30: ;set file indicators + call reselect + call indicators + jp copy$dirloc ;lret=dirloc +; ret +; jp goback + +func31: ;return address of disk parameter block + ld hl,(dpbaddr) +sthl$ret: + ld (aret),hl + ret +; jp goback + +func32: ;set user code + ld a,(linfo) + cp 0ffh + jp nz,setusrcode + ;interrogate user code instead + ld a,(usrcode) + jp sta$ret ;lret=usrcode +; ret +; jp goback + +setusrcode: + and 1fh + ld (usrcode),a + ret +; jp goback + +func33: ;random disk read operation + call reselect + jp randiskread ;to perform the disk read +; ret +; jp goback + +func34: ;random disk write operation + call reselect + jp randiskwrite ;to perform the disk write +; ret +; jp goback + +func35: ;return file size (0-65536) + call reselect + jp getfilesize +; ret +; jp goback + +func36 equ setrandom ;set random record +; ret +; jp goback + +func37: ld hl,(info) + ld a,l + cpl + ld e,a + ld a,h + cpl + ld hl,(dlog) + and h + ld d,a + ld a,l + and e + ld e,a + ld hl,(rodsk) + ex de,hl + ld (dlog),hl + ld a,l + and e + ld l,a + ld a,h + and d + ld h,a + ld (rodsk),hl + ret + +goback: ;arrive here at end of processing to return to user + ld a,(resel) + or a + jp z,retmon + ;reselection may have taken place + ld hl,(info) + ld (hl),0 ;fcb(0)=0 + ld a,(fcbdsk) + or a + jp z,retmon + ;restore disk number + ld (hl),a ;fcb(0)=fcbdsk + ld a,(olddsk) + ld (linfo),a + call curselect + +; return from the disk monitor +retmon: ld hl,(entsp) + ld sp,hl ;user stack restored + ld hl,(aret) + ld a,l + ld b,h ;BA = HL = aret + ret + +func38 equ func$ret +func39 equ func$ret +func40: ;random disk write with zero fill of unallocated block + call reselect + ld a,2 + ld (seqio),a + ld c,false + call rseek1 + call z,diskwrite ;if seek successful + ret + +; data areas + +; initialized data +efcb: .db empty ;0e5=available dir entry +rodsk: .dw 0 ;read only disk vector +dlog: .dw 0 ;logged-in disks +dmaad: .dw tbuff ;initial dma address + +; curtrka - alloca are set upon disk select +; (data must be adjacent, do not insert variables) +; (address of translate vector, not used) +cdrmaxa: + .ds word ;pointer to cur dir max value +curtrka: + .ds word ;current track address +curreca: + .ds word ;current record address +buffa: .ds word ;pointer to directory dma address +dpbaddr: + .ds word ;current disk parameter block address +checka: .ds word ;current checksum vector address +alloca: .ds word ;current allocation vector address + +addlist equ $-buffa ;address list size + +; sectpt - offset obtained from disk parm block at dpbaddr +; (data must be adjacent, do not insert variables) +sectpt: .ds word ;sectors per track +blkshf: .ds byte ;block shift factor +blkmsk: .ds byte ;block mask +extmsk: .ds byte ;extent mask +maxall: .ds word ;maximum allocation number +dirmax: .ds word ;largest directory number +dirblk: .ds word ;reserved allocation bits for directory +chksiz: .ds word ;size of checksum vector +offset: .ds word ;offset tracks at beginning + +dpblist equ $-sectpt ;size of area + +; local variables +tranv: ds word ;address of translate vector +fcb$copied: + ds byte ;set true if copy$fcb called +rmf: ds byte ;read mode flag for open$reel +dirloc: ds byte ;directory flag in rename, etc. +seqio: ds byte ;1 if sequential i/o +linfo: ds byte ;low(info) +dminx: ds byte ;local for diskwrite +searchl: + ds byte ;search length +searcha: + ds word ;search address +tinfo: ds word ;temp for info in "make" +single: ds byte ;set true if single byte allocation map +resel: ds byte ;reselection flag +olddsk: ds byte ;disk on entry to bdos +fcbdsk: ds byte ;disk named in fcb +rcount: ds byte ;record count in current fcb +extval: ds byte ;extent number and extmsk +vrecord: + ds word ;current virtual record +arecord: + ds word ;current actual record +arecord1: + ds word ;current actual block# * blkmsk + +; local variables for directory access +dptr: ds byte ;directory pointer 0,1,2,3 +dcnt: ds word ;directory counter 0,1,...,dirmax +drec: ds word ;directory record 0,1,...,dirmax/4 + +;bios equ ($ and 0ff00h)+100h;next module + + end + + + + + + ;; Ordering of segments for the linker. + .area _HOME + .area _CODE + .area _GSINIT + .area _GSFINAL + + .area _DATA + .area _BSEG + .area _BSS + .area _HEAP + + .area _CODE +.if 0 +__clock:: + ld a,#2 + rst 0x08 + ret +.endif + +_exit:: + ;; Exit - special code to the emulator + ld a,#0 + rst 0x08 +1$: + halt + jr 1$ + + .area _GSINIT +gsinit:: + + .area _GSFINAL + ret diff --git a/doug/src/cpmbdos.lst b/doug/src/cpmbdos.lst new file mode 100755 index 00000000..659ab2c8 --- /dev/null +++ b/doug/src/cpmbdos.lst @@ -0,0 +1,65 @@ + 1 ;-------------------------------------------------------- + 2 ; File Created by SDCC : free open source ANSI-C Compiler + 3 ; Version 3.0.2 #6489 (May 10 2011) (Mac OS X x86_64) + 4 ; This file was generated Wed May 11 05:28:20 2011 + 5 ;-------------------------------------------------------- + 6 .module cpmbdos + 7 .optsdcc -mz80 + 8 + 9 ;-------------------------------------------------------- + 10 ; Public variables in this module + 11 ;-------------------------------------------------------- + 12 .globl _cpmbdos + 13 ;-------------------------------------------------------- + 14 ; special function registers + 15 ;-------------------------------------------------------- + 16 ;-------------------------------------------------------- + 17 ; ram data + 18 ;-------------------------------------------------------- + 19 .area _DATA + 20 ;-------------------------------------------------------- + 21 ; overlayable items in ram + 22 ;-------------------------------------------------------- + 23 .area _OVERLAY + 24 ;-------------------------------------------------------- + 25 ; external initialized ram data + 26 ;-------------------------------------------------------- + 27 ;-------------------------------------------------------- + 28 ; global & static initialisations + 29 ;-------------------------------------------------------- + 30 .area _HOME + 31 .area _GSINIT + 32 .area _GSFINAL + 33 .area _GSINIT + 34 ;-------------------------------------------------------- + 35 ; Home + 36 ;-------------------------------------------------------- + 37 .area _HOME + 38 .area _HOME + 39 ;-------------------------------------------------------- + 40 ; code + 41 ;-------------------------------------------------------- + 42 .area _CODE + 43 ;cpmbdos.c:1: unsigned char cpmbdos(void * p) + 44 ; --------------------------------- + 45 ; Function cpmbdos + 46 ; --------------------------------- + 0000 47 _cpmbdos_start:: + 0000 48 _cpmbdos: + 0000 DD E5 49 push ix + 0002 DD 21 00 00 50 ld ix,#0 + 0006 DD 39 51 add ix,sp + 52 ;cpmbdos.c:3: return 2; + 0008 DD 6E 04 53 ld l,4(ix) + 000B DD 66 05 54 ld h,5(ix) + 000E 4E 55 ld c,(hl) + 000F 23 56 inc hl + 0010 5E 57 ld e,(hl) + 0011 23 58 inc hl + 0012 56 59 ld d,(hl) + 0013 CD 05 00 60 call 5 + 0016 DD E1 61 pop ix + 0018 C9 62 ret + 0019 63 _cpmbdos_end:: + 64 .area _CODE + 65 .area _CABS diff --git a/doug/src/cpmbdos.rel b/doug/src/cpmbdos.rel new file mode 100755 index 00000000..c7464cec --- /dev/null +++ b/doug/src/cpmbdos.rel @@ -0,0 +1,25 @@ +XL +H 7 areas 4 global symbols +M cpmbdos +O -mz80 +S .__.ABS. Def0000 +A _CODE size 19 flags 0 addr 0 +S _cpmbdos Def0000 +S _cpmbdos_start Def0000 +S _cpmbdos_end Def0019 +A _DATA size 0 flags 0 addr 0 +A _OVERLAY size 0 flags 0 addr 0 +A _HOME size 0 flags 0 addr 0 +A _GSINIT size 0 flags 0 addr 0 +A _GSFINAL size 0 flags 0 addr 0 +A _CABS size 0 flags 0 addr 0 +T 00 00 +R 00 00 00 00 +T 00 00 +R 00 00 00 00 +T 00 00 DD E5 DD 21 00 00 DD 39 DD 6E 04 DD 66 05 +R 00 00 00 00 +T 0E 00 4E 23 5E 23 56 CD 05 00 DD E1 C9 +R 00 00 00 00 +T 19 00 +R 00 00 00 00 diff --git a/doug/src/cpmbdos.s b/doug/src/cpmbdos.s new file mode 100755 index 00000000..01c438e0 --- /dev/null +++ b/doug/src/cpmbdos.s @@ -0,0 +1,65 @@ +;-------------------------------------------------------- +; File Created by SDCC : free open source ANSI-C Compiler +; Version 3.0.2 #6489 (May 10 2011) (Mac OS X x86_64) +; This file was generated Wed May 11 05:28:20 2011 +;-------------------------------------------------------- + .module cpmbdos + .optsdcc -mz80 + +;-------------------------------------------------------- +; Public variables in this module +;-------------------------------------------------------- + .globl _cpmbdos +;-------------------------------------------------------- +; special function registers +;-------------------------------------------------------- +;-------------------------------------------------------- +; ram data +;-------------------------------------------------------- + .area _DATA +;-------------------------------------------------------- +; overlayable items in ram +;-------------------------------------------------------- + .area _OVERLAY +;-------------------------------------------------------- +; external initialized ram data +;-------------------------------------------------------- +;-------------------------------------------------------- +; global & static initialisations +;-------------------------------------------------------- + .area _HOME + .area _GSINIT + .area _GSFINAL + .area _GSINIT +;-------------------------------------------------------- +; Home +;-------------------------------------------------------- + .area _HOME + .area _HOME +;-------------------------------------------------------- +; code +;-------------------------------------------------------- + .area _CODE +;cpmbdos.c:1: unsigned char cpmbdos(void * p) +; --------------------------------- +; Function cpmbdos +; --------------------------------- +_cpmbdos_start:: +_cpmbdos: + push ix + ld ix,#0 + add ix,sp +;cpmbdos.c:3: return 2; + ld l,4(ix) + ld h,5(ix) + ld c,(hl) + inc hl + ld e,(hl) + inc hl + ld d,(hl) + call 5 + pop ix + ret +_cpmbdos_end:: + .area _CODE + .area _CABS diff --git a/doug/src/cpmbdos.sym b/doug/src/cpmbdos.sym new file mode 100755 index 00000000..e18058e6 --- /dev/null +++ b/doug/src/cpmbdos.sym @@ -0,0 +1,17 @@ + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 1. + +Symbol Table + + .__.ABS.= 0000 G | 0 _cpmbdos 0000 GR | 0 _cpmbdos 0019 GR + 0 _cpmbdos 0000 GR + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 2. + +Area Table + + 0 _CODE size 19 flags 0 + 1 _DATA size 0 flags 0 + 2 _OVERLAY size 0 flags 0 + 3 _HOME size 0 flags 0 + 4 _GSINIT size 0 flags 0 + 5 _GSFINAL size 0 flags 0 + 6 _CABS size 0 flags 0 diff --git a/doug/src/cprintf.c b/doug/src/cprintf.c new file mode 100755 index 00000000..7f94e9bb --- /dev/null +++ b/doug/src/cprintf.c @@ -0,0 +1,267 @@ +/* Copyright (C) 1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +/* Modified 14-Jan-2002 by John Coffman for inclusion + * in the set of LILO diagnostics. This code is the property of Robert + * de Bath, and is used with his permission. + */ + +/* Modified 14-Sep-2010 by John Coffman for use with + * the N8VEM SBC-188 BIOS project. + */ +#include +#include + +#undef printf +#define ASM_CVT 0 +#ifndef strlen +int strlen(char *s); +#endif + +void outchar(char ch); +#define putch(ch) outchar((char)ch) + + +#ifndef NULL +# define NULL ((void*)0L) +#endif + +#define __fastcall +#define NUMLTH 11 +static unsigned char * __fastcall __numout(long i, int base, unsigned char out[]); + +int cprintf(const char * fmt, ...) +{ + register int c; + int count = 0; + int type, base; + long val; + char * cp; + char padch=' '; + int minsize, maxsize; + unsigned char out[NUMLTH+1]; + va_list ap; + + va_start(ap, fmt); + + while(c=*fmt++) + { + count++; + if(c!='%') + { + if (c=='\n') putch('\r'); + putch(c); + } + else + { + type=1; + padch = *fmt; + maxsize=minsize=0; + if(padch == '-') fmt++; + + for(;;) + { + c=*fmt++; + if( c<'0' || c>'9' ) break; + minsize*=10; minsize+=c-'0'; + } + + if( c == '.' ) + for(;;) + { + c=*fmt++; + if( c<'0' || c>'9' ) break; + maxsize*=10; maxsize+=c-'0'; + } + + if( padch == '-' ) minsize = -minsize; + else + if( padch != '0' ) padch=' '; + + if( c == 0 ) break; + if(c=='h') + { + c=*fmt++; + type = 0; + } + else if(c=='l') + { + c=*fmt++; + type = 2; + } + + switch(c) + { + case 'X': + case 'x': base=16; type |= 4; if(0) { + case 'o': base= 8; type |= 4; } if(0) { + case 'u': base=10; type |= 4; } if(0) { + case 'd': base=-10; } + switch(type) + { + case 0: val=va_arg(ap, short); break; + case 1: val=va_arg(ap, int); break; + case 2: val=va_arg(ap, long); break; + case 4: val=va_arg(ap, unsigned short); break; + case 5: val=va_arg(ap, unsigned int); break; + case 6: val=va_arg(ap, unsigned long); break; + default:val=0; break; + } + cp = __numout(val,base,out); + if(0) { + case 's': + cp=va_arg(ap, char *); + } + count--; + c = strlen(cp); + if( !maxsize ) maxsize = c; + if( minsize > 0 ) + { + minsize -= c; + while(minsize>0) { putch(padch); count++; minsize--; } + minsize=0; + } + if( minsize < 0 ) minsize= -minsize-c; + while(*cp && maxsize-->0 ) + { + putch(*cp++); + count++; + } + while(minsize>0) { putch(' '); count++; minsize--; } + break; + case 'c': + putch(va_arg(ap, int)); + break; + default: + putch(c); + break; + } + } + } + va_end(ap); + return count; +} + +const char nstring[]="0123456789ABCDEF"; + +#if ASM_CVT==0 + +static unsigned char * +__fastcall +__numout(long i, int base, unsigned char *out) +{ + int n; + int flg = 0; + unsigned long val; + + if (base<0) + { + base = -base; + if (i<0) + { + flg = 1; + i = -i; + } + } + val = i; + + out[NUMLTH] = '\0'; + n = NUMLTH-1; + do + { +#if 1 + out[n] = nstring[val % base]; + val /= base; + --n; +#else + out[n--] = nstring[remLS(val,base)]; + val = divLS(val,base); +#endif + } + while(val); + if(flg) out[n--] = '-'; + + return &out[n+1]; +} +#else + +#asm +! numout.s +! +#if 0 +.data +_nstring: +.ascii "0123456789ABCDEF" +.byte 0 +#endif + +.bss +___out lcomm $C + +.text +___numout: +push bp +mov bp,sp +push di +push si +add sp,*-4 +mov byte ptr -8[bp],*$0 ! flg = 0 +mov si,4[bp] ; i or val.lo +mov di,6[bp] ; i or val.hi +mov cx,8[bp] ; base +test cx,cx ! base < 0 ? +jge .3num +neg cx ! base = -base +or di,di ! i < 0 ? +jns .5num +mov byte ptr -8[bp],*1 ! flg = 1 +neg di ! i = -i +neg si +sbb di,*0 +.5num: +.3num: +mov byte ptr [___out+$B],*$0 ! out[11] = nul +mov -6[bp],*$A ! n = 10 + +.9num: +!!! out[n--] = nstring[val % base]; +xor dx,dx +xchg ax,di +div cx +xchg ax,di +xchg ax,si +div cx +xchg ax,si ! val(new) = val / base + +mov bx,dx ! dx = val % base + +mov al,_nstring[bx] +mov bx,-6[bp] +dec word ptr -6[bp] +mov ___out[bx],al + +mov ax,si +or ax,di ! while (val) +jne .9num + +cmp byte ptr -8[bp],*$0 ! flg == 0 ? +je .Dnum + +mov bx,-6[bp] +dec word ptr -6[bp] +mov byte ptr ___out[bx],*$2D ! out[n--] = minus + +.Dnum: +mov ax,-6[bp] +add ax,#___out+1 + +add sp,*4 +pop si +pop di +pop bp +ret +#endasm + +#endif diff --git a/doug/src/crt0.lst b/doug/src/crt0.lst new file mode 100755 index 00000000..600c32c1 --- /dev/null +++ b/doug/src/crt0.lst @@ -0,0 +1,97 @@ + 1 ; modified 4/22/2011 for the N8VEM Home Computer Z180 -- John Coffman + 2 ; + 3 ;-------------------------------------------------------------------------- + 4 ; crt0.s - Generic crt0.s for a Z80 + 5 ; + 6 ; Copyright (C) 2000, Michael Hope + 7 ; + 8 ; This library is free software; you can redistribute it and/or modify it + 9 ; under the terms of the GNU General Public License as published by the + 10 ; Free Software Foundation; either version 2.1, or (at your option) any + 11 ; later version. + 12 ; + 13 ; This library is distributed in the hope that it will be useful, + 14 ; but WITHOUT ANY WARRANTY; without even the implied warranty of + 15 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 16 ; GNU General Public License for more details. + 17 ; + 18 ; You should have received a copy of the GNU General Public License + 19 ; along with this library; see the file COPYING. If not, write to the + 20 ; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + 21 ; MA 02110-1301, USA. + 22 ; + 23 ; As a special exception, if you link this library with other files, + 24 ; some of which are compiled with SDCC, to produce an executable, + 25 ; this library does not by itself cause the resulting executable to + 26 ; be covered by the GNU General Public License. This exception does + 27 ; not however invalidate any other reasons why the executable file + 28 ; might be covered by the GNU General Public License. + 29 ;-------------------------------------------------------------------------- + 30 + 31 ;;; .module crt0 + 32 .globl _main + 33 + 34 .area _HEADER (ABS) + 35 ;; Reset vector + 0000 36 .org 0 + 0000 C3r00s01 37 jp init + 38 + 0008 39 .org 0x08 + 0008 C9 40 ret + 0010 41 .org 0x10 + 0010 C9 42 ret + 0018 43 .org 0x18 + 0018 C9 44 ret + 0020 45 .org 0x20 + 0020 C9 46 ret + 0028 47 .org 0x28 + 0028 C9 48 ret + 0030 49 .org 0x30 + 0030 C9 50 ret + 0038 51 .org 0x38 + 0038 C9 52 ret + 0066 53 .org 0x66 ; NMI interrupt + 0066 ED 45 54 retn + 55 + 0100 56 .org 0x100 + 0100 57 init: + 58 ;; Stack at the top of memory. + 0100 31 FF FF 59 ld sp,#0xffff + 60 + 61 ;; Initialise global variables + 0103 CDr00s00 62 call gsinit + 0106 CDr00s00 63 call _main + 0109 C3r00s00 64 jp _exit + 65 + 66 ;; Ordering of segments for the linker. + 67 .area _HOME + 68 .area _CODE + 69 .area _GSINIT + 70 .area _GSFINAL + 71 + 72 .area _DATA + 73 .area _BSEG + 74 .area _BSS + 75 .area _HEAP + 76 + 77 .area _CODE + 0000 78 .if 0 + 79 __clock:: + 80 ld a,#2 + 81 rst 0x08 + 82 ret + 83 .endif + 84 + 0000 85 _exit:: + 86 ;; Exit - special code to the emulator + 0000 3E 00 87 ld a,#0 + 0002 CF 88 rst 0x08 + 0003 89 1$: + 0003 76 90 halt + 0004 18 FD 91 jr 1$ + 92 + 93 .area _GSINIT + 0000 94 gsinit:: + 95 + 96 .area _GSFINAL + 0000 C9 97 ret diff --git a/doug/src/crt0.rel b/doug/src/crt0.rel new file mode 100755 index 00000000..2f28cda8 --- /dev/null +++ b/doug/src/crt0.rel @@ -0,0 +1,79 @@ +XL +H 13 areas 4 global symbols +S _main Ref0000 +S .__.ABS. Def0000 +A _CODE size 6 flags 0 addr 0 +S _exit Def0000 +A _HEADER size 0 flags 8 addr 0 +A _HEADER0 size 3 flags 8 addr 0 +A _HEADER1 size 1 flags 8 addr 8 +A _HEADER2 size 1 flags 8 addr 10 +A _HEADER3 size 1 flags 8 addr 18 +A _HEADER4 size 1 flags 8 addr 20 +A _HEADER5 size 1 flags 8 addr 28 +A _HEADER6 size 1 flags 8 addr 30 +A _HEADER7 size 1 flags 8 addr 38 +A _HEADER8 size 2 flags 8 addr 66 +A _HEADER9 size C flags 8 addr 100 +A _HOME size 0 flags 0 addr 0 +A _GSINIT size 0 flags 0 addr 0 +S gsinit Def0000 +A _GSFINAL size 1 flags 0 addr 0 +A _DATA size 0 flags 0 addr 0 +A _BSEG size 0 flags 0 addr 0 +A _BSS size 0 flags 0 addr 0 +A _HEAP size 0 flags 0 addr 0 +T 00 00 +R 00 00 02 00 +T 00 00 C3 00 01 +R 00 00 02 00 00 03 0B 00 +T 08 00 +R 00 00 03 00 +T 08 00 C9 +R 00 00 03 00 +T 10 00 +R 00 00 04 00 +T 10 00 C9 +R 00 00 04 00 +T 18 00 +R 00 00 05 00 +T 18 00 C9 +R 00 00 05 00 +T 20 00 +R 00 00 06 00 +T 20 00 C9 +R 00 00 06 00 +T 28 00 +R 00 00 07 00 +T 28 00 C9 +R 00 00 07 00 +T 30 00 +R 00 00 08 00 +T 30 00 C9 +R 00 00 08 00 +T 38 00 +R 00 00 09 00 +T 38 00 C9 +R 00 00 09 00 +T 66 00 +R 00 00 0A 00 +T 66 00 ED 45 +R 00 00 0A 00 +T 00 01 +R 00 00 0B 00 +T 00 01 +R 00 00 0B 00 +T 00 01 31 FF FF CD 00 00 CD 00 00 C3 00 00 +R 00 00 0B 00 00 06 0D 00 02 09 00 00 00 0C 00 00 +T 00 00 +R 00 00 00 00 +T 00 00 3E 00 CF +R 00 00 00 00 +T 03 00 +R 00 00 00 00 +T 03 00 76 18 FD +R 00 00 00 00 +T 00 00 +R 00 00 0D 00 +T 00 00 C9 +R 00 00 0E 00 diff --git a/doug/src/crt0.s b/doug/src/crt0.s new file mode 100755 index 00000000..cd5212df --- /dev/null +++ b/doug/src/crt0.s @@ -0,0 +1,97 @@ +; modified 4/22/2011 for the N8VEM Home Computer Z180 -- John Coffman +; +;-------------------------------------------------------------------------- +; crt0.s - Generic crt0.s for a Z80 +; +; Copyright (C) 2000, Michael Hope +; +; This library is free software; you can redistribute it and/or modify it +; under the terms of the GNU General Public License as published by the +; Free Software Foundation; either version 2.1, or (at your option) any +; later version. +; +; This library is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this library; see the file COPYING. If not, write to the +; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, +; MA 02110-1301, USA. +; +; As a special exception, if you link this library with other files, +; some of which are compiled with SDCC, to produce an executable, +; this library does not by itself cause the resulting executable to +; be covered by the GNU General Public License. This exception does +; not however invalidate any other reasons why the executable file +; might be covered by the GNU General Public License. +;-------------------------------------------------------------------------- + +;;; .module crt0 + .globl _main + + .area _HEADER (ABS) + ;; Reset vector + .org 0 + jp init + + .org 0x08 + ret + .org 0x10 + ret + .org 0x18 + ret + .org 0x20 + ret + .org 0x28 + ret + .org 0x30 + ret + .org 0x38 + ret + .org 0x66 ; NMI interrupt + retn + + .org 0x100 +init: + ;; Stack at the top of memory. + ld sp,#0xffff + + ;; Initialise global variables + call gsinit + call _main + jp _exit + + ;; Ordering of segments for the linker. + .area _HOME + .area _CODE + .area _GSINIT + .area _GSFINAL + + .area _DATA + .area _BSEG + .area _BSS + .area _HEAP + + .area _CODE +.if 0 +__clock:: + ld a,#2 + rst 0x08 + ret +.endif + +_exit:: + ;; Exit - special code to the emulator + ld a,#0 + rst 0x08 +1$: + halt + jr 1$ + + .area _GSINIT +gsinit:: + + .area _GSFINAL + ret diff --git a/doug/src/crt0.sym b/doug/src/crt0.sym new file mode 100755 index 00000000..eb73396b --- /dev/null +++ b/doug/src/crt0.sym @@ -0,0 +1,29 @@ + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 1. + +Symbol Table + + .__.ABS.= 0000 G | 0 _exit 0000 GR | _main **** GX + D gsinit 0000 GR | B init 0100 R + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 2. + +Area Table + + 0 _CODE size 6 flags 0 + 1 _HEADER size 0 flags 8 + 2 _HEADER0 size 3 flags 8 + 3 _HEADER1 size 1 flags 8 + 4 _HEADER2 size 1 flags 8 + 5 _HEADER3 size 1 flags 8 + 6 _HEADER4 size 1 flags 8 + 7 _HEADER5 size 1 flags 8 + 8 _HEADER6 size 1 flags 8 + 9 _HEADER7 size 1 flags 8 + A _HEADER8 size 2 flags 8 + B _HEADER9 size C flags 8 + C _HOME size 0 flags 0 + D _GSINIT size 0 flags 0 + E _GSFINAL size 1 flags 0 + F _DATA size 0 flags 0 + 10 _BSEG size 0 flags 0 + 11 _BSS size 0 flags 0 + 12 _HEAP size 0 flags 0 diff --git a/doug/src/crt0jplp.lst b/doug/src/crt0jplp.lst new file mode 100644 index 00000000..b23ba63f --- /dev/null +++ b/doug/src/crt0jplp.lst @@ -0,0 +1,9 @@ + 1 ;-------------------------------------------------------------------------- + 2 ; crt0jplp.s 8/7/2011 dwg - - Generic crt0.s for a Z80 with jump loop + 3 ;-------------------------------------------------------------------------- + 4 + 5 .area _HEADER (ABS) + 0000 6 .org 0 + 0000 C3r00s00 7 jploop: jp jploop + 8 + 9 diff --git a/doug/src/crt0jplp.rel b/doug/src/crt0jplp.rel new file mode 100644 index 00000000..2b867446 --- /dev/null +++ b/doug/src/crt0jplp.rel @@ -0,0 +1,10 @@ +XL +H 3 areas 1 global symbols +S .__.ABS. Def0000 +A _CODE size 0 flags 0 addr 0 +A _HEADER size 0 flags 8 addr 0 +A _HEADER0 size 3 flags 8 addr 0 +T 00 00 +R 00 00 02 00 +T 00 00 C3 00 00 +R 00 00 02 00 00 03 02 00 diff --git a/doug/src/crt0jplp.s b/doug/src/crt0jplp.s new file mode 100755 index 00000000..41005105 --- /dev/null +++ b/doug/src/crt0jplp.s @@ -0,0 +1,9 @@ +;-------------------------------------------------------------------------- +; crt0jplp.s 8/7/2011 dwg - - Generic crt0.s for a Z80 with jump loop +;-------------------------------------------------------------------------- + + .area _HEADER (ABS) + .org 0 +jploop: jp jploop + + diff --git a/doug/src/crt0jplp.sym b/doug/src/crt0jplp.sym new file mode 100644 index 00000000..2ac002fe --- /dev/null +++ b/doug/src/crt0jplp.sym @@ -0,0 +1,12 @@ + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 1. + +Symbol Table + + .__.ABS.= 0000 G | 2 jploop 0000 R + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 2. + +Area Table + + 0 _CODE size 0 flags 0 + 1 _HEADER size 0 flags 8 + 2 _HEADER0 size 3 flags 8 diff --git a/doug/src/crt0scrm.lst b/doug/src/crt0scrm.lst new file mode 100644 index 00000000..231c555a --- /dev/null +++ b/doug/src/crt0scrm.lst @@ -0,0 +1,72 @@ + 1 ;-------------------------------------------------------------------------- + 2 ; crt0scrm.s 8/7/2011 dwg - - Generic crt0.s for a Z80 with jump loop + 3 ;-------------------------------------------------------------------------- + 4 + 5 + 6 .area _HEADER (ABS) + 0000 7 .org 0 + 8 + 9 .include "scsi2ide.inc" + 1 ; scsi2ide.inc 8/7/2011 dwg - macros describing the N8VEM SCSI2IDE + 2 + 0000 3 SCSI2IDE_IO_BASE = 0 + 4 + 0010 5 UART_IO_BASE = SCSI2IDE_IO_BASE+16 + 6 + 0010 7 rUART_RDR = UART_IO_BASE + 0 + 0010 8 wUART_TDR = UART_IO_BASE + 0 + 0010 9 wUART_DIV_LO = UART_IO_BASE + 0 + 0011 10 wUART_DIV_HI = UART_IO_BASE + 1 + 0011 11 wUART_IER = UART_IO_BASE + 1 + 0012 12 rUART_IIR = UART_IO_BASE + 2 + 0013 13 wUART_LCR = UART_IO_BASE + 3 + 0014 14 wUART_MCR = UART_IO_BASE + 4 + 0015 15 rUART_LSR = UART_IO_BASE + 5 + 0016 16 rUART_MSR = UART_IO_BASE + 6 + 0017 17 wUART_FCR = UART_IO_BASE + 7 + 18 + 19 ; eof - scsi2ide.inc + 20 + 10 .include "ns16550.inc" + 1 ; ns16550.inc 8/7/2011 dwg - National 16550 + 2 + 0080 3 UART_DLAB = 0x80 + 000C 4 UART_BAUD_9600 = 12 + 0001 5 UART_RDA = 0x01 + 0020 6 UART_TBE = 0x20 + 7 + 8 ; eof - ns16550.inc + 11 + 0000 12 scream: + 13 + 0000 3E 80 14 ld a,#UART_DLAB + 0002 D3 13 15 out (wUART_LCR),a + 16 + 0004 3E 00 17 ld a,#0x00 + 0006 D3 11 18 out (wUART_DIV_HI),a + 19 + 0008 3E 0C 20 ld a,#UART_BAUD_9600 + 000A D3 10 21 out (wUART_DIV_LO),a + 22 + 000C 3E 00 23 ld a,#0 + 000E D3 13 24 out (wUART_LCR),a + 25 + 0010 3E 03 26 ld a,#0x03 + 0012 D3 13 27 out (wUART_LCR),a + 28 + 0014 3E 03 29 ld a,#0x03 + 0016 D3 14 30 out (wUART_MCR),a + 31 + 0018 32 scrmlp: + 0018 DB 15 33 in a,(rUART_LSR) + 001A E6 20 34 and a,#UART_TBE + 001C CAr18s00 35 jp z,scrmlp + 36 + 001F 3E 30 37 ld a,#0x30 ; ascii 0 (zero) + 0021 D3 10 38 out (wUART_TDR),a + 39 + 0023 C3r18s00 40 jp scrmlp + 41 + 42 + 43 + 44 diff --git a/doug/src/crt0scrm.rel b/doug/src/crt0scrm.rel new file mode 100644 index 00000000..76e135ea --- /dev/null +++ b/doug/src/crt0scrm.rel @@ -0,0 +1,18 @@ +XL +H 3 areas 1 global symbols +S .__.ABS. Def0000 +A _CODE size 0 flags 0 addr 0 +A _HEADER size 0 flags 8 addr 0 +A _HEADER0 size 26 flags 8 addr 0 +T 00 00 +R 00 00 02 00 +T 00 00 +R 00 00 02 00 +T 00 00 3E 80 D3 13 3E 00 D3 11 3E 0C D3 10 3E 00 +R 00 00 02 00 +T 0E 00 D3 13 3E 03 D3 13 3E 03 D3 14 +R 00 00 02 00 +T 18 00 +R 00 00 02 00 +T 18 00 DB 15 E6 20 CA 18 00 3E 30 D3 10 C3 18 00 +R 00 00 02 00 00 07 02 00 00 0E 02 00 diff --git a/doug/src/crt0scrm.s b/doug/src/crt0scrm.s new file mode 100755 index 00000000..b787bde5 --- /dev/null +++ b/doug/src/crt0scrm.s @@ -0,0 +1,44 @@ +;-------------------------------------------------------------------------- +; crt0scrm.s 8/7/2011 dwg - - Generic crt0.s for a Z80 with jump loop +;-------------------------------------------------------------------------- + + + .area _HEADER (ABS) + .org 0 + + .include "scsi2ide.inc" + .include "ns16550.inc" + +scream: + + ld a,#UART_DLAB + out (wUART_LCR),a + + ld a,#0x00 + out (wUART_DIV_HI),a + + ld a,#UART_BAUD_9600 + out (wUART_DIV_LO),a + + ld a,#0 + out (wUART_LCR),a + + ld a,#0x03 + out (wUART_LCR),a + + ld a,#0x03 + out (wUART_MCR),a + +scrmlp: + in a,(rUART_LSR) + and a,#UART_TBE + jp z,scrmlp + + ld a,#0x30 ; ascii 0 (zero) + out (wUART_TDR),a + + jp scrmlp + + + + diff --git a/doug/src/crt0scrm.sym b/doug/src/crt0scrm.sym new file mode 100644 index 00000000..adeabd9e --- /dev/null +++ b/doug/src/crt0scrm.sym @@ -0,0 +1,18 @@ + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 1. + +Symbol Table + + .__.ABS.= 0000 G | SCSI2IDE= 0000 | UART_BAU= 000C + UART_DLA= 0080 | UART_IO_= 0010 | UART_RDA= 0001 + UART_TBE= 0020 | rUART_II= 0012 | rUART_LS= 0015 + rUART_MS= 0016 | rUART_RD= 0010 | 2 scream 0000 R + 2 scrmlp 0018 R | wUART_DI= 0011 | wUART_DI= 0010 + wUART_FC= 0017 | wUART_IE= 0011 | wUART_LC= 0013 + wUART_MC= 0014 | wUART_TD= 0010 + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 2. + +Area Table + + 0 _CODE size 0 flags 0 + 1 _HEADER size 0 flags 8 + 2 _HEADER0 size 26 flags 8 diff --git a/doug/src/dbgmon.arf b/doug/src/dbgmon.arf new file mode 100755 index 00000000..4db7f615 --- /dev/null +++ b/doug/src/dbgmon.arf @@ -0,0 +1,6 @@ +-mjx +-i dbgmon.ihx +-k /usr/local/share/sdcc/lib/z80 +-l z80 +dbgmon.rel +-e diff --git a/doug/src/dbgmon.lst b/doug/src/dbgmon.lst new file mode 100755 index 00000000..ed616c0e --- /dev/null +++ b/doug/src/dbgmon.lst @@ -0,0 +1,1909 @@ + 1 .title dbgmon.s derived from dbgmon.asm + 2 .sbttl Ported by Douglas Goodall + 3 + 4 .module dbgmon + 5 .optsdcc -mz80 + 6 + 7 ;-------------------------------------------------------- + 8 ; Public variables in this module + 9 ;-------------------------------------------------------- + 10 .globl _dbgmon + 11 ;-------------------------------------------------------- + 12 ; special function registers + 13 ;-------------------------------------------------------- + 14 ;-------------------------------------------------------- + 15 ; ram data + 16 ;-------------------------------------------------------- + 17 .area _DATA + 18 ;-------------------------------------------------------- + 19 ; overlayable items in ram + 20 ;-------------------------------------------------------- + 21 .area _OVERLAY + 22 ;-------------------------------------------------------- + 23 ; external initialized ram data + 24 ;-------------------------------------------------------- + 25 ;-------------------------------------------------------- + 26 ; global & static initialisations + 27 ;-------------------------------------------------------- + 28 .area _HOME + 29 .area _GSINIT + 30 .area _GSFINAL + 31 .area _GSINIT + 32 ;-------------------------------------------------------- + 33 ; Home + 34 ;-------------------------------------------------------- + 35 .area _HOME + 36 .area _HOME + 37 ;-------------------------------------------------------- + 38 ; code + 39 ;-------------------------------------------------------- + 40 .area _DBGMON + 0000 41 _dbgmon_start:: + 0000 42 _dbgmon: + 43 + 44 + 45 ;___ROM_MONITOR_PROGRAM_____________________________________________________________________________________________________________ + 46 ; + 47 ; ORIGINAL CODE BY: ANDREW LYNCH (LYNCHAJ@YAHOO COM) 13 FEB 2007 + 48 ; + 49 ; MODIFIED BY : DAN WERNER 03 09.2009 + 50 ; + 51 ;__REFERENCES________________________________________________________________________________________________________________________ + 52 ; THOMAS SCHERRER BASIC HAR.DWARE TEST ASSEMBLER SOURCES FROM THE Z80 INFO PAGE + 53 ; INCLUDING ORIGINAL SCHEMATIC CONCEPT + 54 ; HTTP://Z80 INFO/Z80SOURC.TXT + 55 ; CODE SAMPLES FROM BRUCE JONES PUBLIC DOMAIN ROM MONITOR FOR THE SBC-200C + 56 ; HTTP://WWW RETROTECHNOLOGY.COM/HERBS_STUFF/SD_BRUCE_CODE.ZIP + 57 ; INSPIRATION FROM JOEL OWENS "Z-80 SPACE-TIME PRODUCTIONS SINGLE BOARD COMPUTER" + 58 ; HTTP://WWW JOELOWENS.ORG/Z80/Z80INDEX.HTML + 59 ; GREAT HELP AND TECHNICAL ADVICE FROM ALLISON AT ALPACA_DESIGNERS + 60 ; HTTP://GROUPS YAHOO.COM/GROUP/ALPACA_DESIGNERS + 61 ; INTEL SDK-85 ROM DEBUG MONITOR + 62 ; + 63 ;__HARDWARE_INTERFACES________________________________________________________________________________________________________________ + 64 ; + 65 ; PIO 82C55 I/O IS DECODED TO PORT 60-67 + 66 ; + 0060 67 PORTA = 0x60 + 0061 68 PORTB = 0x61 + 0062 69 PORTC = 0x62 + 0063 70 PIOCONT = 0x63 + 71 ; + 72 ; UART 16C450 SERIAL IS DECODED TO 68-6F + 73 ; + 0068 74 UART0 = 0x68 ; DATA IN/OUT + 0069 75 UART1 = 0x69 ; CHECK RX + 006A 76 UART2 = 0x6A ; INTERRUPTS + 006B 77 UART3 = 0x6B ; LINE CONTROL + 006C 78 UART4 = 0x6C ; MODEM CONTROL + 006D 79 UART5 = 0x6D ; LINE STATUS + 006E 80 UART6 = 0x6E ; MODEM STATUS + 006F 81 UART7 = 0x6F ; SCRATCH REG. + 82 ; + 83 ; MEMORY PAGE CONFIGURATION LATCH IS DECODED TO 78 + 84 ; + 0078 85 MPCL = 0x78 ; CONTROL PORT, SHOULD ONLY BE CHANGED WHILE + 86 ; IN UPPER MEMORY PAGE 08000h-$FFFF OR LIKELY + 0078 87 MPCL_RAM = 0x78 ; BASE IO ADDRESS OF RAM MEMORY PAGER CONFIGURATION LATCH + 007C 88 MPCL_ROM = 0x7C ; BASE IO ADDRESS OF ROM MEMORY PAGER CONFIGURATION LATCH + 89 ; LOSS OF CPU MEMORY CONTEXT + 90 ; + 91 ; MEMORY PAGE CONFIGURATION LATCH CONTROL PORT ( IO_Y3 ) INFORMATION + 92 ; + 93 ; 7 6 5 4 3 2 1 0 ONLY APPLICABLE TO THE LOWER MEMORY PAGE 00000h-$7FFF + 94 ; ^ ^ ^ ^ ^ ^ ^ ^ + 95 ; : : : : : : : :--0 = A15 RAM/ROM ADDRESS LINE DEFAULT IS 0 + 96 ; : : : : : : :----0 = A16 RAM/ROM ADDRESS LINE DEFAULT IS 0 + 97 ; : : : : : :------0 = A17 RAM/ROM ADDRESS LINE DEFAULT IS 0 + 98 ; : : : : :--------0 = A18 RAM/ROM ADDRESS LINE DEFAULT IS 0 + 99 ; : : : :-----------0 = A19 ROM ONLY ADDRESS LINE DEFAULT IS 0 + 100 ; : : :-------------0 = + 101 ; : :---------------0 = + 102 ; :-----------------0 = ROM SELECT (0=ROM, 1=RAM) DEFAULT IS 0 + 103 ; + 104 ; + 105 ;IDE REGISTER IO PORT ; FUNCTION + 0020 106 IDELO = 0x020 ; DATA PORT (LOW BYTE) + 0021 107 IDEERR = 0x021 ; READ: ERROR REGISTER; WRITE: PRECOMP + 0022 108 IDESECTC = 0x022 ; SECTOR COUNT + 0023 109 IDESECTN = 0x023 ; SECTOR NUMBER + 0024 110 IDECYLLO = 0x024 ; CYLINDER LOW + 0025 111 IDECYLHI = 0x025 ; CYLINDER HIGH + 0026 112 IDEHEAD = 0x026 ; DRIVE/HEAD + 0027 113 IDESTTS = 0x027 ; READ: STATUS; WRITE: COMMAND + 0028 114 IDEHI = 0x028 ; DATA PORT (HIGH BYTE) + 002E 115 IDECTRL = 0x02E ; READ: ALTERNATIVE STATUS; WRITE; DEVICE CONTROL + 002F 116 IDEADDR = 0x02F ; DRIVE ADDRESS (READ ONLY) + 117 + 118 ; + 119 ; + 120 ;__CONSTANTS_________________________________________________________________________________________________________________________ + 121 ; + FFFF 122 RAMTOP = 0x0FFFF ; HIGHEST ADDRESSABLE MEMORY LOCATION + CFFF 123 STACKSTART = 0x0CFFF ; START OF STACK + 8000 124 RAMBOTTOM = 0x08000 ; START OF FIXED UPPER 32K PAGE OF 512KB X 8 RAM 8000H-FFFFH + 8000 125 MONSTARTCOLD = 0x08000 ; COLD START MONITOR IN HIGH RAM + 00FF 126 ENDT = 0x0FF ; MARK END OF TEXT + 000D 127 CR = 0x0D ; ASCII CARRIAGE RETURN CHARACTER + 000A 128 LF = 0x0A ; ASCII LINE FEED CHARACTER + 001B 129 ESC = 0x1B ; ASCII ESCAPE CHARACTER + 0008 130 BS = 0x08 ; ASCII BACKSPACE CHARACTER + 131 + 0041 132 ASCIIA = 0x41 + 0042 133 ASCIIB = 0x42 + 0043 134 ASCIIC = 0x43 + 0044 135 ASCIID = 0x44 + 0045 136 ASCIIE = 0x45 + 0046 137 ASCIIF = 0x46 + 0047 138 ASCIIG = 0x47 + 0048 139 ASCIIH = 0x48 + 0049 140 ASCIII = 0x49 + 004A 141 ASCIIJ = 0x4A + 004B 142 ASCIIK = 0x4B + 004C 143 ASCIIL = 0x4C + 004D 144 ASCIIM = 0x4D + 004E 145 ASCIIN = 0x4E + 004F 146 ASCIIO = 0x4F + 0050 147 ASCIIP = 0x50 + 0051 148 ASCIIQ = 0x51 + 0052 149 ASCIIR = 0x52 + 0053 150 ASCIIS = 0x53 + 0054 151 ASCIIT = 0x54 + 0055 152 ASCIIU = 0x55 + 0056 153 ASCIIV = 0x56 + 0057 154 ASCIIW = 0x57 + 0058 155 ASCIIX = 0x58 + 0059 156 ASCIIY = 0x59 + 005A 157 ASCIIZ = 0x5A + 158 + 159 ; + 160 ; + 161 ; + 162 ;__MAIN_PROGRAM_____________________________________________________________________________________________________________________ + 163 ; + 164 ; ORG 00100h ; FOR DEBUG IN CP/M (AS .COM) + 165 + 166 ;dwg; .ORG 8000H ; NORMAL OP + 167 + 0000 31 FF CF 168 LD SP,#STACKSTART ; SET THE STACK POINTER TO STACKSTART + 0003 CDr32s06 169 CALL INITIALIZE ; INITIALIZE SYSTEM + 170 + 171 + 172 + 173 ;__FRONT_PANEL_STARTUP___________________________________________________________________________________________________________ + 174 ; + 175 ; START UP THE SYSTEM WITH THE FRONT PANEL INTERFACE + 176 ; + 177 ;________________________________________________________________________________________________________________________________ + 178 ; + 0006 CDr3Bs06 179 CALL MTERM_INIT ; INIT 8255 FOR MTERM + 0009 21rC7s0C 180 LD HL,#CPUUP ; SET POINTER TO DATA BUFFER + 000C CDr05s07 181 CALL SEGDISPLAY ; DISPLAY + 182 + 183 + 184 + 000F 185 FRONTPANELLOOP: + 000F CDr40s06 186 CALL KB_GET ; GET KEY FROM KB + 187 + 0012 FE 10 188 CP #0x10 ; IS PORT READ? + 0014 CAr3Cs00 189 JP Z,DOPORTREAD ; YES, JUMP + 0017 FE 11 190 CP #0x11 ; IS PORT WRITE? + 0019 CAr94s00 191 JP Z,DOPORTWRITE ; YES, JUMP + 001C FE 14 192 CP #0x14 ; IS DEPOSIT? + 001E CArD0s00 193 JP Z,DODEPOSIT ; YES, JUMP + 0021 FE 15 194 CP #0x15 ; IS EXAMINE? + 0023 CAr24s01 195 JP Z,DOEXAMINE ; YES, JUMP + 0026 FE 16 196 CP #0x16 ; IS GO? + 0028 CArCCs00 197 JP Z,DOGO ; YES, JUMP + 002B FE 17 198 CP #0x17 ; IS BO? + 002D CAr33s00 199 JP Z,DOBOOT ; YES, JUMP + 200 + 0030 18 DD 201 JR FRONTPANELLOOP ; LOOP + 0032 202 EXIT: + 0032 C9 203 RET + 204 + 205 + 206 ;__DOBOOT________________________________________________________________________________________________________________________ + 207 ; + 208 ; PERFORM BOOT FRONT PANEL ACTION + 209 ;________________________________________________________________________________________________________________________________ + 210 ; + 0033 211 DOBOOT: + 0033 3E 00 212 LD A,#0 ; LOAD VALUE TO SWITCH OUT ROM + 0035 D3 7C 213 OUT (MPCL_ROM),A ; SWITCH OUT ROM, BRING IN LOWER 32K RAM PAGE + 214 ; + 215 ; + 0037 D3 78 216 OUT (MPCL_RAM),A ; + 0039 C3 00 00 217 JP 0 ; GO TO CP/M + 218 + 219 + 220 ;__DOPORTREAD____________________________________________________________________________________________________________________ + 221 ; + 222 ; PERFORM PORT READ FRONT PANEL ACTION + 223 ;________________________________________________________________________________________________________________________________ + 224 ; + 003C 225 DOPORTREAD: + 003C CDr6Cs02 226 CALL GETPORT ; GET PORT INTO A + 003F 227 PORTREADLOOP: + 003F 4F 228 LD C,A ; STORE PORT IN "C" + 0040 CB 3F 229 SRL A ; ROTATE HIGH NIB TO LOW + 0042 CB 3F 230 SRL A ; + 0044 CB 3F 231 SRL A ; + 0046 CB 3F 232 SRL A ; + 0048 32r90s07 233 LD (DISPLAYBUF+5),A ; SHOW HIGH NIB IN DISP 5 + 004B 79 234 LD A,C ; RESTORE PORT VALUE INTO "A" + 004C E6 0F 235 AND #0x0F ; CLEAR HIGH NIB, LEAVING LOW + 004E 32r8Fs07 236 LD (DISPLAYBUF+4),A ; SHOW LOW NIB IN DISP 4 + 0051 ED 78 237 IN A,(C) ; GET PORT VALUE FROM PORT IN "C" + 0053 4F 238 LD C,A ; STORE VALUE IN "C" + 0054 CB 3F 239 SRL A ; ROTATE HIGH NIB TO LOW + 0056 CB 3F 240 SRL A ; + 0058 CB 3F 241 SRL A ; + 005A CB 3F 242 SRL A ; + 005C 32r8Cs07 243 LD (DISPLAYBUF+1),A ; SHOW HIGH NIB IN DISP 1 + 005F 79 244 LD A,C ; RESTORE VALUE TO "A" + 0060 E6 0F 245 AND #0x0F ; CLEAR HIGH NIB, LEAVING LOW + 0062 32r8Bs07 246 LD (DISPLAYBUF),A ; DISPLAY LOW NIB IN DISP 0 + 0065 3E 10 247 LD A,#0x10 ; CLEAR OTHER DISPLAYS + 0067 32r8Ds07 248 LD (DISPLAYBUF+2),A ; + 006A 32r8Es07 249 LD (DISPLAYBUF+3),A ; + 006D 3E 13 250 LD A,#0x13 ; "P" + 006F 32r92s07 251 LD (DISPLAYBUF+7),A ; STORE IN DISP 7 + 0072 3E 14 252 LD A,#0x14 ; "O" + 0074 32r91s07 253 LD (DISPLAYBUF+6),A ; STORE IN DISP 6 + 0077 21r8Bs07 254 LD HL,#DISPLAYBUF ; SET POINTER TO DISPLAY BUFFER + 007A CDrBEs06 255 CALL HEXDISPLAY ; DISPLAY BUFFER CONTENTS + 007D 256 PORTREADGETKEY: + 007D CDr40s06 257 CALL KB_GET ; GET KEY FROM KB + 0080 FE 12 258 CP #0x12 ; [CL] PRESSED, EXIT + 0082 CAr8Bs00 259 JP Z,PORTREADEXIT ; + 0085 FE 10 260 CP #0x10 ; [PR] PRESSED, PROMPT FOR NEW PORT + 0087 28 B3 261 JR Z,DOPORTREAD ; + 0089 18 F2 262 JR PORTREADGETKEY ; NO VALID KEY, LOOP + 008B 263 PORTREADEXIT: + 008B 21rC7s0C 264 LD HL,#CPUUP ; SET POINTER TO DATA BUFFER + 008E CDr05s07 265 CALL SEGDISPLAY ; DISPLAY + 0091 C3r0Fs00 266 JP FRONTPANELLOOP ; + 267 + 268 ;__DOPORTWRITE____________________________________________________________________________________________________________________ + 269 ; + 270 ; PERFORM PORT WRITE FRONT PANEL ACTION + 271 ;________________________________________________________________________________________________________________________________ + 272 ; + 0094 273 DOPORTWRITE: + 0094 CDr6Cs02 274 CALL GETPORT ; GET PORT INTO A + 0097 275 PORTWRITELOOP: + 0097 4F 276 LD C,A ; STORE PORT IN "C" + 0098 CB 3F 277 SRL A ; ROTATE HIGH NIB INTO LOW + 009A CB 3F 278 SRL A ; + 009C CB 3F 279 SRL A ; + 009E CB 3F 280 SRL A ; + 00A0 32r90s07 281 LD (DISPLAYBUF+5),A ; DISPLAY HIGH NIB IN DISPLAY 5 + 00A3 79 282 LD A,C ; RESTORE PORT VALUE INTO "A" + 00A4 E6 0F 283 AND #0x0F ; CLEAR OUT HIGH NIB + 00A6 32r8Fs07 284 LD (DISPLAYBUF+4),A ; DISPLAY LOW NIB IN DISPLAY 4 + 00A9 3E 10 285 LD A,#0x10 ; CLEAR OUT DISPLAYS 2 AND 3 + 00AB 32r8Ds07 286 LD (DISPLAYBUF+2),A ; + 00AE 32r8Es07 287 LD (DISPLAYBUF+3),A ; + 00B1 3E 13 288 LD A,#0x13 ; DISPLAY "P" IN DISP 7 + 00B3 32r92s07 289 LD (DISPLAYBUF+7),A ; + 00B6 3E 14 290 LD A,#0x14 ; DISPLAY "O" IN DISP 6 + 00B8 32r91s07 291 LD (DISPLAYBUF+6),A ; + 00BB 21r8Bs07 292 LD HL,#DISPLAYBUF ; POINT TO DISPLAY BUFFER + 00BE CDrCFs02 293 CALL GETVALUE ; INPUT A BYTE VALUE, RETURN IN "A" + 00C1 ED 79 294 OUT (C),A ; OUTPUT VALUE TO PORT STORED IN "C" + 00C3 21rC7s0C 295 LD HL,#CPUUP ; SET POINTER TO DATA BUFFER + 00C6 CDr05s07 296 CALL SEGDISPLAY ; DISPLAY + 00C9 C3r0Fs00 297 JP FRONTPANELLOOP ; + 298 + 299 + 300 ;__DOGO__________________________________________________________________________________________________________________________ + 301 ; + 302 ; PERFORM GO FRONT PANEL ACTION + 303 ;________________________________________________________________________________________________________________________________ + 304 ; + 00CC 305 DOGO: + 00CC CDr89s01 306 CALL GETADDR ; GET ADDRESS INTO HL + 00CF E9 307 JP (HL) ; GO THERE! + 308 + 309 + 310 + 311 ;__DODEPOSIT________________________________________________________________________________________________________________________ + 312 ; + 313 ; PERFORM DEPOSIT FRONT PANEL ACTION + 314 ;________________________________________________________________________________________________________________________________ + 315 ; + 00D0 316 DODEPOSIT: + 00D0 CDr89s01 317 CALL GETADDR ; GET ADDRESS INTO HL + 00D3 E5 318 PUSH HL + 00D4 319 DEPOSITLOOP: + 00D4 7C 320 LD A,H ; + 00D5 CB 3F 321 SRL A ; + 00D7 CB 3F 322 SRL A ; + 00D9 CB 3F 323 SRL A ; + 00DB CB 3F 324 SRL A ; + 00DD 32r92s07 325 LD (DISPLAYBUF+7),A ; + 00E0 7C 326 LD A,H ; + 00E1 E6 0F 327 AND #0x0F ; + 00E3 32r91s07 328 LD (DISPLAYBUF+6),A ; + 00E6 7D 329 LD A,L ; + 00E7 CB 3F 330 SRL A ; + 00E9 CB 3F 331 SRL A ; + 00EB CB 3F 332 SRL A ; + 00ED CB 3F 333 SRL A ; + 00EF 32r90s07 334 LD (DISPLAYBUF+5),A ; + 00F2 7D 335 LD A,L ; + 00F3 E6 0F 336 AND #0x0F ; + 00F5 32r8Fs07 337 LD (DISPLAYBUF+4),A ; + 00F8 3E 10 338 LD A,#0x10 ; + 00FA 32r8Es07 339 LD (DISPLAYBUF+3),A ; + 00FD 21r8Bs07 340 LD HL,#DISPLAYBUF ; + 0100 CDrCFs02 341 CALL GETVALUE ; + 0103 E1 342 POP HL ; + 0104 77 343 LD (HL),A ; + 0105 344 DEPOSITGETKEY: + 0105 CDr40s06 345 CALL KB_GET ; GET KEY FROM KB + 0108 FE 12 346 CP #0x12 ; [CL] PRESSED, EXIT + 010A CAr1Bs01 347 JP Z,DEPOSITEXIT ; + 010D FE 13 348 CP #0x13 ; [EN] PRESSED, INC ADDRESS AND LOOP + 010F 28 06 349 JR Z,DEPOSITFW ; + 0111 FE 14 350 CP #0x14 ; [DE] PRESSED, PROMPT FOR NEW ADDRESS + 0113 28 BB 351 JR Z,DODEPOSIT ; + 0115 18 EE 352 JR DEPOSITGETKEY ; NO VALID KEY, LOOP + 0117 353 DEPOSITFW: + 0117 23 354 INC HL ; + 0118 E5 355 PUSH HL ; STORE HL + 0119 18 B9 356 JR DEPOSITLOOP ; + 011B 357 DEPOSITEXIT: + 011B 21rC7s0C 358 LD HL,#CPUUP ; SET POINTER TO DATA BUFFER + 011E CDr05s07 359 CALL SEGDISPLAY ; DISPLAY + 0121 C3r0Fs00 360 JP FRONTPANELLOOP ; + 361 + 362 + 363 + 364 + 365 ;__DOEXAMINE________________________________________________________________________________________________________________________ + 366 ; + 367 ; PERFORM EXAMINE FRONT PANEL ACTION + 368 ;________________________________________________________________________________________________________________________________ + 369 ; + 0124 370 DOEXAMINE: + 0124 CDr89s01 371 CALL GETADDR ; GET ADDRESS INTO HL + 0127 E5 372 PUSH HL ; STORE HL + 0128 373 EXAMINELOOP: + 0128 7C 374 LD A,H ; MOVE HIGH BYTE IN "A" + 0129 CB 3F 375 SRL A ; SHOW HIGH NIBBLE IN DISP 7 + 012B CB 3F 376 SRL A ; + 012D CB 3F 377 SRL A ; + 012F CB 3F 378 SRL A ; + 0131 32r92s07 379 LD (DISPLAYBUF+7),A ; + 0134 7C 380 LD A,H ; RESTORE HIGH BYTE + 0135 E6 0F 381 AND #0x0F ; CLEAR HIGH NIBBLE + 0137 32r91s07 382 LD (DISPLAYBUF+6),A ; DISPLAY LOW NIBBLE IN DISP 6 + 013A 7D 383 LD A,L ; PUT LOW BYTE IN "A" + 013B CB 3F 384 SRL A ; SHOW HIGH NIBBLE IN DISP 5 + 013D CB 3F 385 SRL A ; + 013F CB 3F 386 SRL A ; + 0141 CB 3F 387 SRL A ; + 0143 32r90s07 388 LD (DISPLAYBUF+5),A ; + 0146 7D 389 LD A,L ; RESTORE LOW BYTE IN "A" + 0147 E6 0F 390 AND #0x0F ; CLEAR OUT HIGH NIBBLE + 0149 32r8Fs07 391 LD (DISPLAYBUF+4),A ; DISPLAY LOW NIBBLE IN DISP 4 + 014C 3E 10 392 LD A,#0x10 ; CLEAR OUT DISP 3 + 014E 32r8Es07 393 LD (DISPLAYBUF+3),A ; + 0151 7E 394 LD A,(HL) ; GET VALUE FROM ADDRESS IN HL + 0152 CB 3F 395 SRL A ; DISPLAY HIGH NIB IN DISPLAY 1 + 0154 CB 3F 396 SRL A ; + 0156 CB 3F 397 SRL A ; + 0158 CB 3F 398 SRL A ; + 015A 32r8Cs07 399 LD (DISPLAYBUF+1),A ; + 015D 7E 400 LD A,(HL) ; GET VALUE FROM ADDRESS IN HL + 015E E6 0F 401 AND #0x0F ; CLEAR OUT HIGH NIBBLE + 0160 32r8Bs07 402 LD (DISPLAYBUF),A ; DISPLAY LOW NIBBLE IN DISPLAY 0 + 0163 21r8Bs07 403 LD HL,#DISPLAYBUF ; POINT TO DISPLAY BUFFER + 0166 CDrBEs06 404 CALL HEXDISPLAY ; DISPLAY BUFFER ON DISPLAYS + 0169 E1 405 POP HL ; RESTORE HL + 016A 406 EXAMINEGETKEY: + 016A CDr40s06 407 CALL KB_GET ; GET KEY FROM KB + 016D FE 12 408 CP #0x12 ; [CL] PRESSED, EXIT + 016F CAr80s01 409 JP Z,EXAMINEEXIT ; + 0172 FE 13 410 CP #0x13 ; [EN] PRESSED, INC ADDRESS AND LOOP + 0174 28 06 411 JR Z,EXAMINEFW ; + 0176 FE 15 412 CP #0x15 ; [DE] PRESSED, PROMPT FOR NEW ADDRESS + 0178 28 AA 413 JR Z,DOEXAMINE ; + 017A 18 EE 414 JR EXAMINEGETKEY ; NO VALID KEY, LOOP + 017C 415 EXAMINEFW: + 017C 23 416 INC HL ; HL++ + 017D E5 417 PUSH HL ; STORE HL + 017E 18 A8 418 JR EXAMINELOOP ; + 0180 419 EXAMINEEXIT: + 0180 21rC7s0C 420 LD HL,#CPUUP ; SET POINTER TO DATA BUFFER + 0183 CDr05s07 421 CALL SEGDISPLAY ; DISPLAY + 0186 C3r0Fs00 422 JP FRONTPANELLOOP ; + 423 + 424 + 425 ;__GETADDR_______________________________________________________________________________________________________________________ + 426 ; + 427 ; GET ADDRESS FROM FRONT PANEL + 428 ;________________________________________________________________________________________________________________________________ + 429 ; + 0189 430 GETADDR: + 0189 C5 431 PUSH BC ; STORE BC + 018A 18 6A 432 JR GETADDRCLEAR ; + 018C 433 GETADDR1: + 018C 21rCFs0C 434 LD HL,#ADDR ; DISPLAY PROMPT + 018F CDr05s07 435 CALL SEGDISPLAY ; + 0192 436 GETADDRLOOP: + 0192 CDr40s06 437 CALL KB_GET ; + 0195 FE 10 438 CP #0x10 ; + 0197 FArDDs01 439 JP M,GETADDRNUM ; NUMBER PRESSED, STORE IT + 019A FE 13 440 CP #0x13 ; EN PRESSED, DONE + 019C 28 06 441 JR Z,GETADDRDONE ; + 019E FE 12 442 CP #0x12 ; CLEAR PRESSED, CLEAR + 01A0 28 54 443 JR Z,GETADDRCLEAR ; + 01A2 18 EE 444 JR GETADDRLOOP ; INVALID KEY, LOOP + 01A4 445 GETADDRDONE: + 01A4 21 00 00 446 LD HL,#0 ; HL=0 + 01A7 3Ar8Cs07 447 LD A,(DISPLAYBUF+1) ; GET DIGIT IN DISPLAY 1 + 01AA CB 27 448 SLA A ; ROTATE IT TO HIGH NIBBLE + 01AC CB 27 449 SLA A ; + 01AE CB 27 450 SLA A ; + 01B0 CB 27 451 SLA A ; + 01B2 4F 452 LD C,A ; STORE IT IN "C" + 01B3 3Ar8Bs07 453 LD A,(DISPLAYBUF) ; GET DIGIT IN DISPLAY 0 + 01B6 E6 0F 454 AND #0x0F ; CLEAR HIGH NIBBLE + 01B8 B1 455 OR C ; ADD IN NIBBLE STORED IN C + 01B9 6F 456 LD L,A ; STORE IT IN LOW BYTE OF ADDRESS POINTER + 01BA 3Ar8Es07 457 LD A,(DISPLAYBUF+3) ; GET DIGIT IN DISPLAY 3 + 01BD CB 27 458 SLA A ; ROTATE IT TO HIGH NIBBLE + 01BF CB 27 459 SLA A ; + 01C1 CB 27 460 SLA A ; + 01C3 CB 27 461 SLA A ; + 01C5 4F 462 LD C,A ; STORE IT IN "C" + 01C6 3Ar8Ds07 463 LD A,(DISPLAYBUF+2) ; GET DIGIT IN DISPLAY 2 + 01C9 E6 0F 464 AND #0x0F ; CLEAR HIGH NIBBLE + 01CB B1 465 OR C ; ADD IN NIBBLE STORED IN "C" + 01CC 67 466 LD H,A ; STORE BYTE IN HIGH BYTE OF ADDRESS POINTER + 01CD 3E 10 467 LD A,#0x10 ; CLEAR OUT DISPLAYS 0,1,2 & 3 + 01CF 32r8Bs07 468 LD (DISPLAYBUF),A ; + 01D2 32r8Cs07 469 LD (DISPLAYBUF+1),A ; + 01D5 32r8Ds07 470 LD (DISPLAYBUF+2),A ; + 01D8 32r8Es07 471 LD (DISPLAYBUF+3),A ; + 01DB C1 472 POP BC ; RESTORE BC + 01DC C9 473 RET + 01DD 474 GETADDRNUM: + 01DD 4F 475 LD C,A ; + 01DE 3Ar8Ds07 476 LD A,(DISPLAYBUF+2) ; SHIFT BYTES IN DISPLAY BUF TO THE LEFT + 01E1 32r8Es07 477 LD (DISPLAYBUF+3),A ; + 01E4 3Ar8Cs07 478 LD A,(DISPLAYBUF+1) ; + 01E7 32r8Ds07 479 LD (DISPLAYBUF+2),A ; + 01EA 3Ar8Bs07 480 LD A,(DISPLAYBUF) ; + 01ED 32r8Cs07 481 LD (DISPLAYBUF+1),A ; + 01F0 79 482 LD A,C ; DISPLAY KEYSTROKE IN RIGHT MOST DISPLAY (0) + 01F1 32r8Bs07 483 LD (DISPLAYBUF+0),A ; + 01F4 18 0E 484 JR GETADDRDISP ; + 01F6 485 GETADDRCLEAR: + 01F6 3E 12 486 LD A,#0x12 ; CLEAR OUT DISPLAYS 0,1,2 & 3 + 01F8 32r8Bs07 487 LD (DISPLAYBUF),A ; + 01FB 32r8Cs07 488 LD (DISPLAYBUF+1),A ; + 01FE 32r8Ds07 489 LD (DISPLAYBUF+2),A ; + 0201 32r8Es07 490 LD (DISPLAYBUF+3),A ; + 0204 491 GETADDRDISP: + 0204 3Ar8Bs07 492 LD A,(DISPLAYBUF) ; ENCODE DIGITS IN DISPLAY BUFFER TO DISPLAY + 0207 CDrF8s06 493 CALL DECODEDISPLAY ; + 020A 32rCFs0C 494 LD (ADDR),A ; + 020D 3Ar8Cs07 495 LD A,(DISPLAYBUF+1) ; + 0210 CDrF8s06 496 CALL DECODEDISPLAY ; + 0213 32rD0s0C 497 LD (ADDR+1),A ; + 0216 3Ar8Ds07 498 LD A,(DISPLAYBUF+2) ; + 0219 CDrF8s06 499 CALL DECODEDISPLAY ; + 021C 32rD1s0C 500 LD (ADDR+2),A ; + 021F 3Ar8Es07 501 LD A,(DISPLAYBUF+3) ; + 0222 CDrF8s06 502 CALL DECODEDISPLAY ; + 0225 32rD2s0C 503 LD (ADDR+3),A ; + 0228 C3r8Cs01 504 JP GETADDR1 ; + 505 + 506 + 507 + 508 ;__DSPSECTOR_______________________________________________________________________________________________________________________ + 509 ; + 510 ; DISPLAY SECTOR IN HL ON FRONT PANEL + 511 ;________________________________________________________________________________________________________________________________ + 512 ; + 022B 513 DSPSECTOR: + 022B C5 514 PUSH BC ; STORE BC + 022C E5 515 PUSH HL ; STORE HL + 022D 7C 516 LD A,H ; DISPLAY HIGH BYTE, HIGH NIBBLE + 022E CB 3F 517 SRL A ; + 0230 CB 3F 518 SRL A ; + 0232 CB 3F 519 SRL A ; + 0234 CB 3F 520 SRL A ; + 0236 E6 0F 521 AND #0x0F ; + 0238 CDrF8s06 522 CALL DECODEDISPLAY ; + 023B 32rE2s0C 523 LD (SEC+3),A ; + 023E 7C 524 LD A,H ; DISPLAY HIGH BYTE, LOW NIBBLE + 023F E6 0F 525 AND #0x0F ; + 0241 CDrF8s06 526 CALL DECODEDISPLAY ; + 0244 32rE1s0C 527 LD (SEC+2),A ; + 0247 7D 528 LD A,L ; DISPLAY LOW BYTE, HIGH NIBBLE + 0248 E6 F0 529 AND #0x0F0 ; + 024A CB 3F 530 SRL A ; + 024C CB 3F 531 SRL A ; + 024E CB 3F 532 SRL A ; + 0250 CB 3F 533 SRL A ; + 0252 E6 0F 534 AND #0x0F ; + 0254 CDrF8s06 535 CALL DECODEDISPLAY ; + 0257 32rE0s0C 536 LD (SEC+1),A ; DISPLAY LOW BYTE, LOW NIBBLE + 025A 7D 537 LD A,L ; + 025B E6 0F 538 AND #0x0F ; + 025D CDrF8s06 539 CALL DECODEDISPLAY ; + 0260 32rDFs0C 540 LD (SEC),A ; + 0263 21rDFs0C 541 LD HL,#SEC ; DISPLAY PROMPT + 0266 CDr05s07 542 CALL SEGDISPLAY ; + 0269 E1 543 POP HL ; RESTORE HL + 026A C1 544 POP BC ; RESTORE BC + 026B C9 545 RET + 546 + 547 + 548 + 549 ;__GETPORT_______________________________________________________________________________________________________________________ + 550 ; + 551 ; GET PORT FROM FRONT PANEL + 552 ;________________________________________________________________________________________________________________________________ + 553 ; + 026C 554 GETPORT: + 026C C5 555 PUSH BC ; STORE BC + 026D 18 43 556 JR GETPORTCLEAR ; + 026F 557 GETPORT1: + 026F 21rD7s0C 558 LD HL,#PORT ; DISPLAY PROMPT + 0272 CDr05s07 559 CALL SEGDISPLAY ; + 0275 560 GETPORTLOOP: + 0275 CDr40s06 561 CALL KB_GET ; + 0278 FE 10 562 CP #0x10 ; + 027A FArA5s02 563 JP M,GETPORTNUM ; NUMBER PRESSED, STORE IT + 027D FE 13 564 CP #0x13 ; EN PRESSED, DONE + 027F 28 06 565 JR Z,GETPORTDONE ; + 0281 FE 12 566 CP #0x12 ; CLEAR PRESSED, CLEAR + 0283 28 2D 567 JR Z,GETPORTCLEAR ; + 0285 18 EE 568 JR GETPORTLOOP ; INVALID KEY, LOOP + 0287 569 GETPORTDONE: + 0287 3Ar8Cs07 570 LD A,(DISPLAYBUF+1) ; + 028A CB 27 571 SLA A ; + 028C CB 27 572 SLA A ; + 028E CB 27 573 SLA A ; + 0290 CB 27 574 SLA A ; + 0292 4F 575 LD C,A ; + 0293 3Ar8Bs07 576 LD A,(DISPLAYBUF) ; + 0296 E6 0F 577 AND #0x0F ; + 0298 B1 578 OR C ; + 0299 4F 579 LD C,A ; + 029A 3E 10 580 LD A,#0x10 ; + 029C 32r8Bs07 581 LD (DISPLAYBUF),A ; + 029F 32r8Cs07 582 LD (DISPLAYBUF+1),A ; + 02A2 79 583 LD A,C ; + 02A3 C1 584 POP BC ; RESTORE BC + 02A4 C9 585 RET + 02A5 586 GETPORTNUM: + 02A5 4F 587 LD C,A ; + 02A6 3Ar8Bs07 588 LD A,(DISPLAYBUF) ; + 02A9 32r8Cs07 589 LD (DISPLAYBUF+1),A ; + 02AC 79 590 LD A,C ; + 02AD 32r8Bs07 591 LD (DISPLAYBUF+0),A ; + 02B0 18 08 592 JR GETPORTDISP ; + 02B2 593 GETPORTCLEAR: + 02B2 3E 12 594 LD A,#0x12 ; + 02B4 32r8Bs07 595 LD (DISPLAYBUF),A ; + 02B7 32r8Cs07 596 LD (DISPLAYBUF+1),A ; + 02BA 597 GETPORTDISP: + 02BA 3Ar8Bs07 598 LD A,(DISPLAYBUF) ; + 02BD CDrF8s06 599 CALL DECODEDISPLAY ; + 02C0 32rD7s0C 600 LD (PORT),A ; + 02C3 3Ar8Cs07 601 LD A,(DISPLAYBUF+1) ; + 02C6 CDrF8s06 602 CALL DECODEDISPLAY ; + 02C9 32rD8s0C 603 LD (PORT+1),A ; + 02CC C3r6Fs02 604 JP GETPORT1 ; + 605 + 606 + 607 ;__GETVALUE______________________________________________________________________________________________________________________ + 608 ; + 609 ; GET VALUE FROM FRONT PANEL + 610 ;________________________________________________________________________________________________________________________________ + 611 ; + 02CF 612 GETVALUE: + 02CF C5 613 PUSH BC ; STORE BC + 02D0 18 40 614 JR GETVALUECLEAR ; + 02D2 615 GETVALUE1: + 02D2 CDrBEs06 616 CALL HEXDISPLAY ; + 617 + 02D5 618 GETVALUELOOP: + 02D5 CDr40s06 619 CALL KB_GET ; + 02D8 FE 10 620 CP #0x10 ; + 02DA FAr05s03 621 JP M,GETVALUENUM ; NUMBER PRESSED, STORE IT + 02DD FE 13 622 CP #0x13 ; EN PRESSED, DONE + 02DF 28 06 623 JR Z,GETVALUEDONE ; + 02E1 FE 12 624 CP #0x12 ; CLEAR PRESSED, CLEAR + 02E3 28 2D 625 JR Z,GETVALUECLEAR ; + 02E5 18 EE 626 JR GETVALUELOOP ; INVALID KEY, LOOP + 02E7 627 GETVALUEDONE: + 02E7 3Ar8Cs07 628 LD A,(DISPLAYBUF+1) ; + 02EA CB 27 629 SLA A ; + 02EC CB 27 630 SLA A ; + 02EE CB 27 631 SLA A ; + 02F0 CB 27 632 SLA A ; + 02F2 4F 633 LD C,A ; + 02F3 3Ar8Bs07 634 LD A,(DISPLAYBUF) ; + 02F6 E6 0F 635 AND #0x0F ; + 02F8 B1 636 OR C ; + 02F9 4F 637 LD C,A ; + 02FA 3E 10 638 LD A,#0x10 ; + 02FC 32r8Bs07 639 LD (DISPLAYBUF),A ; + 02FF 32r8Cs07 640 LD (DISPLAYBUF+1),A ; + 0302 79 641 LD A,C ; + 0303 C1 642 POP BC ; RESTORE BC + 0304 C9 643 RET + 0305 644 GETVALUENUM: + 0305 4F 645 LD C,A ; + 0306 3Ar8Bs07 646 LD A,(DISPLAYBUF) ; + 0309 32r8Cs07 647 LD (DISPLAYBUF+1),A ; + 030C 79 648 LD A,C ; + 030D 32r8Bs07 649 LD (DISPLAYBUF+0),A ; + 0310 18 C0 650 JR GETVALUE1 ; + 0312 651 GETVALUECLEAR: + 0312 3E 12 652 LD A,#0x12 ; + 0314 32r8Bs07 653 LD (DISPLAYBUF),A ; + 0317 32r8Cs07 654 LD (DISPLAYBUF+1),A ; + 031A C3rD2s02 655 JP GETVALUE1 ; + 656 + 657 + 658 ;__MONSTARTWARM___________________________________________________________________________________________________________________ + 659 ; + 660 ; SERIAL MONITOR STARTUP + 661 ;________________________________________________________________________________________________________________________________ + 662 ; + 663 + 031D 664 MONSTARTWARM: ; CALL HERE FOR SERIAL MONITOR WARM START + 031D 31 FF CF 665 LD SP,#STACKSTART ; SET THE STACK POINTER TO STACKSTART + 0320 CDr32s06 666 CALL INITIALIZE ; INITIALIZE SYSTEM + 667 + 0323 AF 668 XOR A ;ZERO OUT ACCUMULATOR (ADDED) + 0324 E5 669 PUSH HL ;PROTECT HL FROM OVERWRITE + 0325 21r9Bs09 670 LD HL,#TXT_READY ;POINT AT TEXT + 0328 CDr8As04 671 CALL MSG ;SHOW WE'RE HERE + 032B E1 672 POP HL ;PROTECT HL FROM OVERWRITE + 673 + 674 ; + 675 ;__SERIAL_MONITOR_COMMANDS_________________________________________________________________________________________________________ + 676 ; + 677 ; B XX BOOT CPM FROM DRIVE XX + 678 ; D XXXXH YYYYH DUMP MEMORY FROM XXXX TO YYYY + 679 ; F XXXXH YYYYH ZZH FILL MEMORY FROM XXXX TO YYYY WITH ZZ + 680 ; H LOAD INTEL HEX FORMAT DATA + 681 ; I INPUT FROM PORT AND SHOW HEX DATA + 682 ; K ECHO KEYBOARD INPUT + 683 ; M XXXXH YYYYH ZZZZH MOVE MEMORY BLOCK XXXX TO YYYY TO ZZZZ + 684 ; O OUTPUT TO PORT HEX DATA + 685 ; P XXXXH YYH PROGRAM RAM FROM XXXXH WITH VALUE IN YYH, WILL PROMPT FOR NEXT LINES FOLLOWING UNTIL CR + 686 ; R RUN A PROGRAM FROM CURRENT LOCATION + 687 + 688 + 689 + 690 ;__COMMAND_PARSE_________________________________________________________________________________________________________________ + 691 ; + 692 ; PROMPT USER FOR COMMANDS, THEN PARSE THEM + 693 ;________________________________________________________________________________________________________________________________ + 694 ; + 695 + 032C 696 SERIALCMDLOOP: + 032C CDr81s04 697 CALL CRLFA ; CR,LF,> + 032F 21r3Bs07 698 LD HL,#KEYBUF ; SET POINTER TO KEYBUF AREA + 0332 CDr81s03 699 CALL GETLN ; GET A LINE OF INPUT FROM THE USER + 0335 21r3Bs07 700 LD HL,#KEYBUF ; RESET POINTER TO START OF KEYBUF + 0338 7E 701 LD A,(HL) ; LOAD FIRST CHAR INTO A (THIS SHOULD BE THE COMMAND) + 0339 23 702 INC HL ; INC POINTER + 703 + 033A FE 42 704 CP #ASCIIB ; IS IT "B" (Y/N) + 033C CAr33s00 705 JP Z,DOBOOT ; IF YES DO BOOT + 033F FE 52 706 CP #ASCIIR ; IS IT "R" (Y/N) + 0341 CAr98s04 707 JP Z,RUN ; IF YES GO RUN ROUTINE + 0344 FE 50 708 CP #ASCIIP ; IS IT "P" (Y/N) + 0346 CAr9Ds04 709 JP Z,PROGRM ; IF YES GO PROGRAM ROUTINE + 0349 FE 4F 710 CP #ASCIIO ; IS IT AN "O" (Y/N) + 034B CAr63s04 711 JP Z,POUT ; PORT OUTPUT + 034E FE 48 712 CP #ASCIIH ; IS IT A "H" (Y/N) + 0350 CAr30s05 713 JP Z,HXLOAD ; INTEL HEX FORMAT LOAD DATA + 0353 FE 49 714 CP #ASCIII ; IS IT AN "I" (Y/N) + 0355 CAr71s04 715 JP Z,PIN ; PORT INPUT + 0358 FE 44 716 CP #ASCIID ; IS IT A "D" (Y/N) + 035A CArD4s04 717 JP Z,DUMP ; DUMP MEMORY + 035D FE 4B 718 CP #ASCIIK + 035F CAr74s03 719 JP Z,KLOP ; LOOP ON KEYBOARD + 0362 FE 4D 720 CP #ASCIIM ; IS IT A "M" (Y/N) + 0364 CAr9Cs05 721 JP Z,MOVE ; MOVE MEMORY COMMAND + 0367 FE 46 722 CP #ASCIIF ; IS IT A "F" (Y/N) + 0369 CArDDs05 723 JP Z,FILL ; FILL MEMORY COMMAND + 036C 21rA2s0C 724 LD HL,#TXT_COMMAND ; POINT AT ERROR TEXT + 036F CDr8As04 725 CALL MSG ; PRINT COMMAND LABEL + 726 + 0372 18 B8 727 JR SERIALCMDLOOP + 728 + 729 + 730 + 731 + 732 + 733 ;__KLOP__________________________________________________________________________________________________________________________ + 734 ; + 735 ; READ FROM THE SERIAL PORT AND ECHO, MONITOR COMMAND "K" + 736 ;________________________________________________________________________________________________________________________________ + 737 ; + 0374 738 KLOP: + 0374 CDrB4s03 739 CALL KIN ; GET A KEY + 0377 CDrC8s03 740 CALL COUT ; OUTPUT KEY TO SCREEN + 037A FE 1B 741 CP #ESC ; IS ? + 037C 20 F6 742 JR NZ,KLOP ; NO, LOOP + 037E C3r2Cs03 743 JP SERIALCMDLOOP ; + 744 + 745 ;__GETLN_________________________________________________________________________________________________________________________ + 746 ; + 747 ; READ A LINE(80) OF TEXT FROM THE SERIAL PORT, HANDLE , TERM ON + 748 ; EXIT IF TOO MANY CHARS STORE RESULT IN HL. CHAR COUNT IN C. + 749 ;________________________________________________________________________________________________________________________________ + 750 ; + 0381 751 GETLN: + 0381 0E 00 752 LD C,#0 ; ZERO CHAR COUNTER + 0383 D5 753 PUSH DE ; STORE DE + 0384 754 GETLNLOP: + 0384 CDrB4s03 755 CALL KIN ; GET A KEY + 0387 CDrC8s03 756 CALL COUT ; OUTPUT KEY TO SCREEN + 038A FE 0D 757 CP #CR ; IS ? + 038C 28 22 758 JR Z,GETLNDONE ; YES, EXIT + 038E FE 08 759 CP #BS ; IS ? + 0390 20 16 760 JR NZ,GETLNSTORE ; NO, STORE CHAR + 0392 79 761 LD A,C ; A=C + 0393 FE 00 762 CP #0 ; + 0395 28 ED 763 JR Z,GETLNLOP ; NOTHING TO BACKSPACE, IGNORE & GET NEXT KEY + 0397 2B 764 DEC HL ; PERFORM BACKSPACE + 0398 0D 765 DEC C ; LOWER CHAR COUNTER + 0399 3E 00 766 LD A,#0 ; + 039B 77 767 LD (HL),A ; STORE NULL IN BUFFER + 039C 3E 20 768 LD A,#0x20 ; BLANK OUT CHAR ON TERM + 039E CDrC8s03 769 CALL COUT ; + 03A1 3E 08 770 LD A,#BS ; + 03A3 CDrC8s03 771 CALL COUT ; + 03A6 18 DC 772 JR GETLNLOP ; GET NEXT KEY + 03A8 773 GETLNSTORE: + 03A8 77 774 LD (HL),A ; STORE CHAR IN BUFFER + 03A9 23 775 INC HL ; INC POINTER + 03AA 0C 776 INC C ; INC CHAR COUNTER + 03AB 79 777 LD A,C ; A=C + 03AC FE 4D 778 CP #0x4D ; OUT OF BUFFER SPACE? + 03AE 20 D4 779 JR NZ,GETLNLOP ; NOPE, GET NEXT CHAR + 03B0 780 GETLNDONE: + 03B0 36 00 781 LD (HL),#0 ; STORE NULL IN BUFFER + 03B2 D1 782 POP DE ; RESTORE DE + 03B3 C9 783 RET ; + 784 + 785 + 786 ;__KIN___________________________________________________________________________________________________________________________ + 787 ; + 788 ; READ FROM THE SERIAL PORT AND ECHO & CONVERT INPUT TO UCASE + 789 ;________________________________________________________________________________________________________________________________ + 790 ; + 03B4 791 KIN: + 03B4 DB 6D 792 IN A,(UART5) ; READ LINE STATUS REGISTER + 03B6 CB 47 793 BIT 0,A ; TEST IF DATA IN RECEIVE BUFFER + 03B8 CArB4s03 794 JP Z,KIN ; LOOP UNTIL DATA IS READY + 03BB DB 68 795 IN A,(UART0) ; THEN READ THE CHAR FROM THE UART + 03BD E6 7F 796 AND #0x7F ; STRIP HI BIT + 03BF FE 41 797 CP #ASCIIA ; KEEP NUMBERS, CONTROLS + 03C1 D8 798 RET C ; AND UPPER CASE + 03C2 FE 7B 799 CP #0x7B ; SEE IF NOT LOWER CASE + 03C4 D0 800 RET NC ; + 03C5 E6 5F 801 AND #0x5F ; MAKE UPPER CASE + 03C7 C9 802 RET + 803 + 804 + 805 ;__COUT__________________________________________________________________________________________________________________________ + 806 ; + 807 ; WRITE THE VALUE IN "A" TO THE SERIAL PORT + 808 ;________________________________________________________________________________________________________________________________ + 809 ; + 03C8 810 COUT: + 03C8 F5 811 PUSH AF ; STORE AF + 03C9 812 TX_BUSYLP: + 03C9 DB 6D 813 IN A,(UART5) ; READ LINE STATUS REGISTER + 03CB CB 6F 814 BIT 5,A ; TEST IF UART IS READY TO SEND + 03CD CArC9s03 815 JP Z,TX_BUSYLP ; IF NOT REPEAT + 03D0 F1 816 POP AF ; RESTORE AF + 03D1 D3 68 817 OUT (UART0),A ; THEN WRITE THE CHAR TO UART + 03D3 C9 818 RET ; DONE + 819 + 820 + 821 ;__CRLF__________________________________________________________________________________________________________________________ + 822 ; + 823 ; SEND CR & LF TO THE SERIAL PORT + 824 ;________________________________________________________________________________________________________________________________ + 825 ; + 03D4 826 CRLF: + 03D4 E5 827 PUSH HL ; PROTECT HL FROM OVERWRITE + 03D5 21r94s09 828 LD HL,#TCRLF ; LOAD MESSAGE POINTER + 03D8 CDr8As04 829 CALL MSG ; SEBD MESSAGE TO SERIAL PORT + 03DB E1 830 POP HL ; PROTECT HL FROM OVERWRITE + 03DC C9 831 RET ; + 832 + 833 + 834 ;__LDHL__________________________________________________________________________________________________________________________ + 835 ; + 836 ; GET ONE WORD OF HEX DATA FROM BUFFER POINTED TO BY HL SERIAL PORT, RETURN IN HL + 837 ;________________________________________________________________________________________________________________________________ + 838 ; + 03DD 839 LDHL: + 03DD D5 840 PUSH DE ; STORE DE + 03DE CDrE9s03 841 CALL HEXIN ; GET K B. AND MAKE HEX + 03E1 57 842 LD D,A ; THATS THE HI BYTE + 03E2 CDrE9s03 843 CALL HEXIN ; DO HEX AGAIN + 03E5 6F 844 LD L,A ; THATS THE LOW BYTE + 03E6 62 845 LD H,D ; MOVE TO HL + 03E7 D1 846 POP DE ; RESTORE BC + 03E8 C9 847 RET ; GO BACK WITH ADDRESS + 848 + 849 + 850 ;__HEXIN__________________________________________________________________________________________________________________________ + 851 ; + 852 ; GET ONE BYTE OF HEX DATA FROM BUFFER IN HL, RETURN IN A + 853 ;________________________________________________________________________________________________________________________________ + 854 ; + 03E9 855 HEXIN: + 03E9 C5 856 PUSH BC ;SAVE BC REGS + 03EA CDrFCs03 857 CALL NIBL ;DO A NIBBLE + 03ED CB 07 858 RLC A ;MOVE FIRST BYTE UPPER NIBBLE + 03EF CB 07 859 RLC A ; + 03F1 CB 07 860 RLC A ; + 03F3 CB 07 861 RLC A ; + 03F5 47 862 LD B,A ; SAVE ROTATED BYTE + 03F6 CDrFCs03 863 CALL NIBL ; DO NEXT NIBBLE + 03F9 80 864 ADD A,B ; COMBINE NIBBLES IN ACC + 03FA C1 865 POP BC ; RESTORE BC + 03FB C9 866 RET ; DONE + 03FC 867 NIBL: + 03FC 7E 868 LD A,(HL) ; GET K B. DATA + 03FD 23 869 INC HL ; INC KB POINTER + 03FE FE 40 870 CP #0x40 ; TEST FOR ALPHA + 0400 30 03 871 JR NC,ALPH ; + 0402 E6 0F 872 AND #0x0F ; GET THE BITS + 0404 C9 873 RET ; + 0405 874 ALPH: + 0405 E6 0F 875 AND #0x0F ; GET THE BITS + 0407 C6 09 876 ADD A,#9 ; MAKE IT HEX A-F + 0409 C9 877 RET ; + 878 + 879 + 880 ;__HEXINS_________________________________________________________________________________________________________________________ + 881 ; + 882 ; GET ONE BYTE OF HEX DATA FROM SERIAL PORT, RETURN IN A + 883 ;________________________________________________________________________________________________________________________________ + 884 ; + 040A 885 HEXINS: + 040A C5 886 PUSH BC ;SAVE BC REGS + 040B CDr1Ds04 887 CALL NIBLS ;DO A NIBBLE + 040E CB 07 888 RLC A ;MOVE FIRST BYTE UPPER NIBBLE + 0410 CB 07 889 RLC A ; + 0412 CB 07 890 RLC A ; + 0414 CB 07 891 RLC A ; + 0416 47 892 LD B,A ; SAVE ROTATED BYTE + 0417 CDr1Ds04 893 CALL NIBLS ; DO NEXT NIBBLE + 041A 80 894 ADD A,B ; COMBINE NIBBLES IN ACC + 041B C1 895 POP BC ; RESTORE BC + 041C C9 896 RET ; DONE + 041D 897 NIBLS: + 041D CDrB4s03 898 CALL KIN ; GET K B. DATA + 0420 23 899 INC HL ; INC KB POINTER + 0421 FE 40 900 CP #0x40 ; TEST FOR ALPHA + 0423 30 E0 901 JR NC,ALPH ; + 0425 E6 0F 902 AND #0x0F ; GET THE BITS + 0427 C9 903 RET ; + 904 + 905 + 906 ;__HXOUT_________________________________________________________________________________________________________________________ + 907 ; + 908 ; PRINT THE ACCUMULATOR CONTENTS AS HEX DATA ON THE SERIAL PORT + 909 ;________________________________________________________________________________________________________________________________ + 910 ; + 0428 911 HXOUT: + 0428 C5 912 PUSH BC ; SAVE BC + 0429 47 913 LD B,A ; + 042A CB 07 914 RLC A ; DO HIGH NIBBLE FIRST + 042C CB 07 915 RLC A ; + 042E CB 07 916 RLC A ; + 0430 CB 07 917 RLC A ; + 0432 E6 0F 918 AND #0x0F ; ONLY THIS NOW + 0434 C6 30 919 ADD A,#0x30 ; TRY A NUMBER + 0436 FE 3A 920 CP #0x3A ; TEST IT + 0438 38 02 921 JR C,OUT1 ; IF CY SET PRINT 'NUMBER' + 043A C6 07 922 ADD A,#0x07 ; MAKE IT AN ALPHA + 043C 923 OUT1: + 043C CDrC8s03 924 CALL COUT ; SCREEN IT + 043F 78 925 LD A,B ; NEXT NIBBLE + 0440 E6 0F 926 AND #0x0F ; JUST THIS + 0442 C6 30 927 ADD A,#0x30 ; TRY A NUMBER + 0444 FE 3A 928 CP #0x3A ; TEST IT + 0446 38 02 929 JR C,OUT2 ; PRINT 'NUMBER' + 0448 C6 07 930 ADD A,#7 ; MAKE IT ALPHA + 044A 931 OUT2: + 044A CDrC8s03 932 CALL COUT ; SCREEN IT + 044D C1 933 POP BC ; RESTORE BC + 044E C9 934 RET ; + 935 + 936 + 937 ;__SPACE_________________________________________________________________________________________________________________________ + 938 ; + 939 ; PRINT A SPACE CHARACTER ON THE SERIAL PORT + 940 ;________________________________________________________________________________________________________________________________ + 941 ; + 044F 942 SPACE: + 044F F5 943 PUSH AF ; STORE AF + 0450 3E 20 944 LD A,#0x20 ; LOAD A "SPACE" + 0452 CDrC8s03 945 CALL COUT ; SCREEN IT + 0455 F1 946 POP AF ; RESTORE AF + 0456 C9 947 RET ; DONE + 948 + 949 ;__PHL_________________________________________________________________________________________________________________________ + 950 ; + 951 ; PRINT THE HL REG ON THE SERIAL PORT + 952 ;________________________________________________________________________________________________________________________________ + 953 ; + 0457 954 PHL: + 0457 7C 955 LD A,H ; GET HI BYTE + 0458 CDr28s04 956 CALL HXOUT ; DO HEX OUT ROUTINE + 045B 7D 957 LD A,L ; GET LOW BYTE + 045C CDr28s04 958 CALL HXOUT ; HEX IT + 045F CDr4Fs04 959 CALL SPACE ; + 0462 C9 960 RET ; DONE + 961 + 962 ;__POUT__________________________________________________________________________________________________________________________ + 963 ; + 964 ; OUTPUT TO AN I/O PORT, MONITOR COMMAND "O" + 965 ;________________________________________________________________________________________________________________________________ + 966 ; + 0463 967 POUT: + 0463 968 POUT1: + 0463 23 969 INC HL ; + 0464 CDrE9s03 970 CALL HEXIN ; GET PORT + 0467 4F 971 LD C,A ; SAVE PORT POINTER + 0468 23 972 INC HL ; + 0469 CDrE9s03 973 CALL HEXIN ; GET DATA + 046C 974 OUTIT: + 046C ED 79 975 OUT (C),A ; + 046E C3r2Cs03 976 JP SERIALCMDLOOP ; + 977 + 978 + 979 ;__PIN___________________________________________________________________________________________________________________________ + 980 ; + 981 ; INPUT FROM AN I/O PORT, MONITOR COMMAND "I" + 982 ;________________________________________________________________________________________________________________________________ + 983 ; + 0471 984 PIN: + 0471 23 985 INC HL ; + 0472 CDrE9s03 986 CALL HEXIN ; GET PORT + 0475 4F 987 LD C,A ; SAVE PORT POINTER + 0476 CDrD4s03 988 CALL CRLF ; + 0479 ED 78 989 IN A,(C) ; GET DATA + 047B CDr28s04 990 CALL HXOUT ; SHOW IT + 047E C3r2Cs03 991 JP SERIALCMDLOOP ; + 992 + 993 + 994 + 995 + 996 + 997 ;__CRLFA_________________________________________________________________________________________________________________________ + 998 ; + 999 ; PRINT COMMAND PROMPT TO THE SERIAL PORT + 1000 ;________________________________________________________________________________________________________________________________ + 1001 ; + 0481 1002 CRLFA: + 0481 E5 1003 PUSH HL ; PROTECT HL FROM OVERWRITE + 0482 21r97s09 1004 LD HL,#PROMPT ; + 0485 CDr8As04 1005 CALL MSG ; + 0488 E1 1006 POP HL ; PROTECT HL FROM OVERWRITE + 0489 C9 1007 RET ; DONE + 1008 + 1009 + 1010 ;__MSG___________________________________________________________________________________________________________________________ + 1011 ; + 1012 ; PRINT A STRING TO THE SERIAL PORT + 1013 ;________________________________________________________________________________________________________________________________ + 1014 ; + 048A 1015 MSG: + 1016 + 048A 1017 TX_SERLP: + 048A 7E 1018 LD A,(HL) ; GET CHARACTER TO A + 048B FE FF 1019 CP #ENDT ; TEST FOR END BYTE + 048D CAr97s04 1020 JP Z,TX_END ; JUMP IF END BYTE IS FOUND + 0490 CDrC8s03 1021 CALL COUT ; + 0493 23 1022 INC HL ; INC POINTER, TO NEXT CHAR + 0494 C3r8As04 1023 JP TX_SERLP ; TRANSMIT LOOP + 0497 1024 TX_END: + 0497 C9 1025 RET ;ELSE DONE + 1026 + 1027 ;__RUN___________________________________________________________________________________________________________________________ + 1028 ; + 1029 ; TRANSFER OUT OF MONITOR, USER OPTION "R" + 1030 ;________________________________________________________________________________________________________________________________ + 1031 ; + 0498 1032 RUN: + 0498 23 1033 INC HL ; SHOW READY + 0499 CDrDDs03 1034 CALL LDHL ; GET START ADDRESS + 049C E9 1035 JP (HL) ; + 1036 + 1037 + 1038 ;__PROGRM________________________________________________________________________________________________________________________ + 1039 ; + 1040 ; PROGRAM RAM LOCATIONS, USER OPTION "P" + 1041 ;________________________________________________________________________________________________________________________________ + 1042 ; + 049D 1043 PROGRM: + 049D 23 1044 INC HL ; SHOW READY + 049E E5 1045 PUSH HL ; STORE HL + 049F CDrDDs03 1046 CALL LDHL ; GET START ADDRESS + 04A2 54 1047 LD D,H ; + 04A3 5D 1048 LD E,L ; DE POINTS TO ADDRESS TO PROGRAM + 04A4 E1 1049 POP HL ; + 04A5 23 1050 INC HL ; + 04A6 23 1051 INC HL ; + 04A7 23 1052 INC HL ; + 04A8 23 1053 INC HL ; + 04A9 23 1054 INC HL ; + 04AA 1055 PROGRMLP: + 04AA CDrE9s03 1056 CALL HEXIN ; GET NEXT HEX NUMBER + 04AD 12 1057 LD (DE),A ; STORE IT + 04AE 13 1058 INC DE ; NEXT ADDRESS; + 04AF CDr81s04 1059 CALL CRLFA ; CR,LF,> + 04B2 3E 50 1060 LD A,#ASCIIP ; + 04B4 CDrC8s03 1061 CALL COUT ; + 04B7 CDr4Fs04 1062 CALL SPACE ; + 04BA 62 1063 LD H,D ; + 04BB 6B 1064 LD L,E ; + 04BC CDr57s04 1065 CALL PHL ; + 04BF 21r3Bs07 1066 LD HL,#KEYBUF ; SET POINTER TO KEYBUF AREA + 04C2 CDr81s03 1067 CALL GETLN ; GET A LINE OF INPUT FROM THE USER + 04C5 21r3Bs07 1068 LD HL,#KEYBUF ; RESET POINTER TO START OF KEYBUF + 04C8 7E 1069 LD A,(HL) ; LOAD FIRST CHAR INTO A + 04C9 FE 00 1070 CP #0 ; END OF LINE? + 04CB CArD1s04 1071 JP Z,PROGRMEXIT ; YES, EXIT + 04CE C3rAAs04 1072 JP PROGRMLP ; NO, LOOP + 04D1 1073 PROGRMEXIT: + 04D1 C3r2Cs03 1074 JP SERIALCMDLOOP + 1075 + 1076 + 1077 + 1078 + 1079 + 1080 + 1081 + 1082 ;__DUMP__________________________________________________________________________________________________________________________ + 1083 ; + 1084 ; PRINT A MEMORY DUMP, USER OPTION "D" + 1085 ;________________________________________________________________________________________________________________________________ + 1086 ; + 04D4 1087 DUMP: + 04D4 23 1088 INC HL ; SHOW READY + 04D5 E5 1089 PUSH HL ; STORE HL + 04D6 CDrDDs03 1090 CALL LDHL ; GET START ADDRESS + 04D9 54 1091 LD D,H ; + 04DA 5D 1092 LD E,L ; + 04DB E1 1093 POP HL ; + 04DC D5 1094 PUSH DE ; SAVE START + 04DD 23 1095 INC HL ; + 04DE 23 1096 INC HL ; + 04DF 23 1097 INC HL ; + 04E0 23 1098 INC HL ; + 04E1 23 1099 INC HL ; + 04E2 CDrDDs03 1100 CALL LDHL ; GET END ADDRESS + 04E5 23 1101 INC HL ; ADD ONE MORE FOR LATER COMPARE + 04E6 EB 1102 EX DE,HL ; PUT END ADDRESS IN DE + 04E7 E1 1103 POP HL ; GET BACK START + 04E8 1104 GDATA: + 04E8 CDrD4s03 1105 CALL CRLF ; + 04EB 1106 BLKRD: + 04EB CDr57s04 1107 CALL PHL ; PRINT START LOCATION + 04EE 0E 10 1108 LD C,#16 ; SET FOR 16 LOCS + 04F0 E5 1109 PUSH HL ; SAVE STARTING HL + 04F1 1110 NXTONE: + 04F1 D9 1111 EXX ; + 04F2 4B 1112 LD C,E ; + 04F3 ED 78 1113 IN A,(C) ; + 04F5 D9 1114 EXX ; + 04F6 E6 7F 1115 AND #0x7F ; + 04F8 FE 1B 1116 CP #ESC ; + 04FA CAr2Cs03 1117 JP Z,SERIALCMDLOOP ; + 04FD FE 13 1118 CP #19 ; + 04FF 28 F0 1119 JR Z,NXTONE ; + 0501 7E 1120 LD A,(HL) ; GET BYTE + 0502 CDr28s04 1121 CALL HXOUT ; PRINT IT + 0505 CDr4Fs04 1122 CALL SPACE ; + 0508 1123 UPDH: + 0508 23 1124 INC HL ; POINT NEXT + 0509 0D 1125 DEC C ; DEC LOC COUNT + 050A 20 E5 1126 JR NZ,NXTONE ; IF LINE NOT DONE + 1127 ; NOW PRINT 'DECODED' DATA TO RIGHT OF DUMP + 050C 1128 PCRLF: + 050C CDr4Fs04 1129 CALL SPACE ; SPACE IT + 050F 0E 10 1130 LD C,#16 ; SET FOR 16 CHARS + 0511 E1 1131 POP HL ; GET BACK START + 0512 1132 PCRLF0: + 0512 7E 1133 LD A,(HL) ; GET BYTE + 0513 E6 60 1134 AND #0x060 ; SEE IF A 'DOT' + 0515 7E 1135 LD A,(HL) ; O K. TO GET + 0516 20 02 1136 JR NZ,PDOT ; + 0518 1137 DOT: + 0518 3E 2E 1138 LD A,#0x2E ; LOAD A DOT + 051A 1139 PDOT: + 051A CDrC8s03 1140 CALL COUT ; PRINT IT + 051D 23 1141 INC HL ; + 051E 7A 1142 LD A,D ; + 051F BC 1143 CP H ; + 0520 20 05 1144 JR NZ,UPDH1 ; + 0522 7B 1145 LD A,E ; + 0523 BD 1146 CP L ; + 0524 CAr2Cs03 1147 JP Z,SERIALCMDLOOP ; + 1148 ; + 1149 ;IF BLOCK NOT DUMPED, DO NEXT CHARACTER OR LINE + 0527 1150 UPDH1: + 0527 0D 1151 DEC C ; DEC CHAR COUNT + 0528 20 E8 1152 JR NZ,PCRLF0 ; DO NEXT + 052A 1153 CONTD: + 052A CDrD4s03 1154 CALL CRLF ; + 052D C3rEBs04 1155 JP BLKRD ; + 1156 + 1157 + 1158 ;__HXLOAD__________________________________________________________________________________________________________________________ + 1159 ; + 1160 ; LOAD INTEL HEX FORMAT FILE FROM THE SERIAL PORT, USER OPTION "H" + 1161 ; + 1162 ; [INTEL HEX FORMAT IS: + 1163 ; 1) COLON (FRAME 0) + 1164 ; 2) RECORD LENGTH FIELD (FRAMES 1 AND 2) + 1165 ; 3) LOAD ADDRESS FIELD (FRAMES 3,4,5,6) + 1166 ; 4) RECORD TYPE FIELD (FRAMES 7 AND 8) + 1167 ; 5) DATA FIELD (FRAMES 9 TO 9+2*(RECORD LENGTH)-1 + 1168 ; 6) CHECKSUM FIELD - SUM OF ALL BYTE VALUES FROM RECORD LENGTH TO AND + 1169 ; INCLUDING CHECKSUM FIELD = 0 ] + 1170 ; + 1171 ; EXAMPLE OF INTEL HEX FORMAT FILE + 1172 ; EACH LINE CONTAINS A CARRIAGE RETURN AS THE LAST CHARACTER + 1173 ; :18F900002048454C4C4F20574F524C4420FF0D0AFF0D0A3EFF0D0A54BF + 1174 ; :18F918006573742050726F746F7479706520524F4D204D6F6E69746FF1 + 1175 ; :18F9300072205265616479200D0AFF0D0A434F4D4D414E4420524543F2 + 1176 ; :18F948004549564544203AFF0D0A434845434B53554D204552524F52CD + 1177 ; :16F96000FF0A0D20202D454E442D4F462D46494C452D20200A0DA4 + 1178 ; :00000001FF + 1179 ;________________________________________________________________________________________________________________________________ + 0530 1180 HXLOAD: + 0530 CDrD4s03 1181 CALL CRLF ; SHOW READY + 0533 1182 HXLOAD0: + 0533 CDrB4s03 1183 CALL KIN ; GET THE FIRST CHARACTER, EXPECTING A ':' + 0536 1184 HXLOAD1: + 0536 FE 3A 1185 CP #0x3A ; IS IT COLON ':'? START OF LINE OF INTEL HEX FILE + 0538 20 47 1186 JR NZ,HXLOADERR ; IF NOT, MUST BE ERROR, ABORT ROUTINE + 053A 1E 00 1187 LD E,#0 ; FIRST TWO CHARACTERS IS THE RECORD LENGTH FIELD + 053C CDr0As04 1188 CALL HEXINS ; GET US TWO CHARACTERS INTO BC, CONVERT IT TO A BYTE + 053F CDr8As05 1189 CALL HXCHKSUM ; UPDATE HEX CHECK SUM + 0542 57 1190 LD D,A ; LOAD RECORD LENGTH COUNT INTO D + 0543 CDr0As04 1191 CALL HEXINS ; GET NEXT TWO CHARACTERS, MEMORY LOAD ADDRESS + 0546 CDr8As05 1192 CALL HXCHKSUM ; UPDATE HEX CHECK SUM + 0549 67 1193 LD H,A ; PUT VALUE IN H REGISTER + 054A CDr0As04 1194 CALL HEXINS ; GET NEXT TWO CHARACTERS, MEMORY LOAD ADDRESS + 054D CDr8As05 1195 CALL HXCHKSUM ; UPDATE HEX CHECK SUM + 0550 6F 1196 LD L,A ; PUT VALUE IN L REGISTER + 0551 CDr0As04 1197 CALL HEXINS ; GET NEXT TWO CHARACTERS, RECORD FIELD TYPE + 0554 CDr8As05 1198 CALL HXCHKSUM ; UPDATE HEX CHECK SUM + 0557 FE 01 1199 CP #1 ; RECORD FIELD TYPE 00 IS DATA, 01 IS END OF FILE + 0559 20 0D 1200 JR NZ,HXLOAD2 ; MUST BE THE END OF THAT FILE + 055B CDr0As04 1201 CALL HEXINS ; GET NEXT TWO CHARACTERS, ASSEMBLE INTO BYTE + 055E CDr8As05 1202 CALL HXCHKSUM ; UPDATE HEX CHECK SUM + 0561 7B 1203 LD A,E ; RECALL THE CHECKSUM BYTE + 0562 A7 1204 AND A ; IS IT ZERO? + 0563 CAr96s05 1205 JP Z,HXLOADEXIT ; MUST BE O K., GO BACK FOR SOME MORE, ELSE + 0566 18 19 1206 JR HXLOADERR ; CHECKSUMS DON'T ADD UP, ERROR OUT + 0568 1207 HXLOAD2: + 0568 7A 1208 LD A,D ; RETRIEVE LINE CHARACTER COUNTER + 0569 A7 1209 AND A ; ARE WE DONE WITH THIS LINE? + 056A 28 0B 1210 JR Z,HXLOAD3 ; GET TWO MORE ASCII CHARACTERS, BUILD A BYTE AND CHECKSUM + 056C CDr0As04 1211 CALL HEXINS ; GET NEXT TWO CHARS, CONVERT TO BYTE IN A, CHECKSUM IT + 056F CDr8As05 1212 CALL HXCHKSUM ; UPDATE HEX CHECK SUM + 0572 77 1213 LD (HL),A ; CHECKSUM OK, MOVE CONVERTED BYTE IN A TO MEMORY LOCATION + 0573 23 1214 INC HL ; INCREMENT POINTER TO NEXT MEMORY LOCATION + 0574 15 1215 DEC D ; DECREMENT LINE CHARACTER COUNTER + 0575 18 F1 1216 JR HXLOAD2 ; AND KEEP LOADING INTO MEMORY UNTIL LINE IS COMPLETE + 0577 1217 HXLOAD3: + 0577 CDr0As04 1218 CALL HEXINS ; GET TWO CHARS, BUILD BYTE AND CHECKSUM + 057A CDr8As05 1219 CALL HXCHKSUM ; UPDATE HEX CHECK SUM + 057D 7B 1220 LD A,E ; CHECK THE CHECKSUM VALUE + 057E A7 1221 AND A ; IS IT ZERO? + 057F 28 0F 1222 JR Z,HXLOADAGAIN ; IF THE CHECKSUM IS STILL OK, CONTINUE ON, ELSE + 0581 1223 HXLOADERR: + 0581 21rB5s0C 1224 LD HL,#TXT_CKSUMERR ; GET "CHECKSUM ERROR" MESSAGE + 0584 CDr8As04 1225 CALL MSG ; PRINT MESSAGE FROM (HL) AND TERMINATE THE LOAD + 0587 C3r96s05 1226 JP HXLOADEXIT ; RETURN TO PROMPT + 058A 1227 HXCHKSUM: + 058A 4F 1228 LD C,A ; BUILD THE CHECKSUM + 058B 7B 1229 LD A,E ; + 058C 91 1230 SUB C ; THE CHECKSUM SHOULD ALWAYS .EQUAL ZERO WHEN CHECKED + 058D 5F 1231 LD E,A ; SAVE THE CHECKSUM BACK WHERE IT CAME FROM + 058E 79 1232 LD A,C ; RETRIEVE THE BYTE AND GO BACK + 058F C9 1233 RET ; BACK TO CALLER + 0590 1234 HXLOADAGAIN: + 0590 CDrB4s03 1235 CALL KIN ; CATCH THE TRAILING CARRIAGE RETURN + 0593 C3r33s05 1236 JP HXLOAD0 ; LOAD ANOTHER LINE OF DATA + 0596 1237 HXLOADEXIT: + 0596 CDrB4s03 1238 CALL KIN ; CATCH ANY STRAY TRAILING CHARACTERS + 0599 C3r2Cs03 1239 JP SERIALCMDLOOP ; RETURN TO PROMPT + 1240 + 1241 + 1242 ;__MOVE__________________________________________________________________________________________________________________________ + 1243 ; + 1244 ; MOVE MEMORY, USER OPTION "M" + 1245 ;________________________________________________________________________________________________________________________________ + 1246 ; + 059C 1247 MOVE: + 059C 0E 03 1248 LD C,#3 + 1249 ; START GETNM REPLACEMENT + 1250 ; GET SOURCE STARTING MEMORY LOCATION + 059E 23 1251 INC HL ; SHOW EXAMINE READY + 059F E5 1252 PUSH HL ; + 05A0 CDrDDs03 1253 CALL LDHL ; LOAD IN HL REGS + 05A3 54 1254 LD D,H ; + 05A4 5D 1255 LD E,L ; + 05A5 E1 1256 POP HL ; + 05A6 D5 1257 PUSH DE ; PUSH MEMORY ADDRESS ON STACK + 05A7 23 1258 INC HL ; + 05A8 23 1259 INC HL ; + 05A9 23 1260 INC HL ; + 05AA 23 1261 INC HL ; + 05AB 23 1262 INC HL ; PRINT SPACE SEPARATOR + 05AC E5 1263 PUSH HL ; + 05AD CDrDDs03 1264 CALL LDHL ; LOAD IN HL REGS + 05B0 54 1265 LD D,H ; + 05B1 5D 1266 LD E,L ; + 05B2 E1 1267 POP HL ; + 05B3 D5 1268 PUSH DE ; PUSH MEMORY ADDRESS ON STACK + 05B4 23 1269 INC HL ; + 05B5 23 1270 INC HL ; + 05B6 23 1271 INC HL ; + 05B7 23 1272 INC HL ; + 05B8 23 1273 INC HL ; PRINT SPACE SEPARATOR + 05B9 CDrDDs03 1274 CALL LDHL ; LOAD IN HL REGS + 05BC E5 1275 PUSH HL ; PUSH MEMORY ADDRESS ON STACK + 1276 ; END GETNM REPLACEMENT + 05BD D1 1277 POP DE ; DEST + 05BE C1 1278 POP BC ; SOURCE END + 05BF E1 1279 POP HL ; SOURCE + 05C0 E5 1280 PUSH HL ; + 05C1 7D 1281 LD A,L ; + 05C2 2F 1282 CPL ; + 05C3 6F 1283 LD L,A ; + 05C4 7C 1284 LD A,H ; + 05C5 2F 1285 CPL ; + 05C6 67 1286 LD H,A ; + 05C7 23 1287 INC HL ; + 05C8 09 1288 ADD HL,BC ; + 05C9 4D 1289 LD C,L ; + 05CA 44 1290 LD B,H ; + 05CB E1 1291 POP HL ; + 05CC CDrD2s05 1292 CALL MOVE_LOOP ; + 05CF C3r2Cs03 1293 JP SERIALCMDLOOP ; EXIT MOVE COMMAND ROUTINE + 05D2 1294 MOVE_LOOP: + 05D2 7E 1295 LD A,(HL) ; FETCH + 05D3 12 1296 LD (DE),A ; DEPOSIT + 05D4 23 1297 INC HL ; BUMP SOURCE + 05D5 13 1298 INC DE ; BUMP DEST + 05D6 0B 1299 DEC BC ; DEC COUNT + 05D7 79 1300 LD A,C ; + 05D8 B0 1301 OR B ; + 05D9 C2rD2s05 1302 JP NZ,MOVE_LOOP ; TIL COUNT=0 + 05DC C9 1303 RET ; + 1304 + 1305 ;__FILL__________________________________________________________________________________________________________________________ + 1306 ; + 1307 ; FILL MEMORY, USER OPTION "M" + 1308 ;________________________________________________________________________________________________________________________________ + 1309 ; + 05DD 1310 FILL: + 05DD 0E 03 1311 LD C,#3 ; + 1312 ; START GETNM REPLACEMENT + 1313 ; GET FILL STARTING MEMORY LOCATION + 05DF 23 1314 INC HL ; SHOW EXAMINE READY + 05E0 E5 1315 PUSH HL ; + 05E1 CDrDDs03 1316 CALL LDHL ; LOAD IN HL REGS + 05E4 54 1317 LD D,H ; + 05E5 5D 1318 LD E,L ; + 05E6 E1 1319 POP HL ; + 05E7 D5 1320 PUSH DE ; PUSH MEMORY ADDRESS ON STACK + 05E8 23 1321 INC HL ; + 05E9 23 1322 INC HL ; + 05EA 23 1323 INC HL ; + 05EB 23 1324 INC HL ; + 05EC 23 1325 INC HL ; PRINT SPACE SEPARATOR + 1326 ; GET FILL ENDING MEMORY LOCATION + 05ED E5 1327 PUSH HL ; + 05EE CDrDDs03 1328 CALL LDHL ; LOAD IN HL REGS + 05F1 54 1329 LD D,H ; + 05F2 5D 1330 LD E,L ; + 05F3 E1 1331 POP HL ; + 05F4 D5 1332 PUSH DE ; PUSH MEMORY ADDRESS ON STACK + 05F5 23 1333 INC HL ; + 05F6 23 1334 INC HL ; + 05F7 23 1335 INC HL ; + 05F8 23 1336 INC HL ; + 05F9 23 1337 INC HL ; PRINT SPACE SEPARATOR + 1338 ; GET TARGET STARTING MEMORY LOCATION + 05FA CDrE9s03 1339 CALL HEXIN ; GET K B. AND MAKE HEX + 05FD 4F 1340 LD C,A ; PUT FILL VALUE IN F SO IT IS SAVED FOR LATER + 05FE C5 1341 PUSH BC ; PUSH FILL VALUE BYTE ON STACK + 1342 ; END GETNM REPLACEMENT + 05FF C1 1343 POP BC ; BYTE + 0600 D1 1344 POP DE ; END + 0601 E1 1345 POP HL ; START + 0602 71 1346 LD (HL),C ; + 0603 1347 FILL_LOOP: + 0603 71 1348 LD (HL),C ; + 0604 23 1349 INC HL ; + 0605 7B 1350 LD A,E ; + 0606 95 1351 SUB L ; + 0607 47 1352 LD B,A ; + 0608 7A 1353 LD A,D ; + 0609 94 1354 SUB H ; + 060A B0 1355 OR B ; + 060B C2r03s06 1356 JP NZ,FILL_LOOP ; + 060E C3r2Cs03 1357 JP SERIALCMDLOOP ; + 1358 + 1359 ;__GOCPM_________________________________________________________________________________________________________________________ + 1360 ; + 1361 ; BOOT CP/M FROM ROM DRIVE, USER OPTION "C" + 1362 ;________________________________________________________________________________________________________________________________ + 1363 ; + 0611 1364 GOCPM: + 1365 ;___________________________ + 1366 ; REMOVE COMMENTS WHEN BURNED IN ROM + 1367 ;___________________________ + 1368 + 1369 ; LD A,000000000b ; RESET MPCL LATCH TO DEFAULT ROM + 1370 ; OUT (MPCL),A ; + 1371 ; LD HL,ROMSTART_CPM ; WHERE IN ROM CP/M IS STORED (FIRST BYTE) + 1372 ; LD DE,RAMTARG_CPM ; WHERE IN RAM TO MOVE MONITOR TO (FIRST BYTE) + 1373 ; LD BC,MOVSIZ_CPM ; NUMBER OF BYTES TO MOVE FROM ROM TO RAM + 1374 ; LDIR ; PERFORM BLOCK COPY OF CP/M TO UPPER RAM PAGE + 1375 ; LD A,010000000b ; RESET MPCL LATCH TO DEFAULT CP/M WITH 64K SETTING + 1376 ; OUT (MPCL),A ; + 1377 + 0611 C3 00 EA 1378 JP 0x0EA00 ; CP/M COLD BOOT ENTRY POINT + 1379 + 1380 ; + 1381 ;__INIT_UART_____________________________________________________________________________________________________________________ + 1382 ; + 1383 ; INITIALIZE UART + 1384 ; PARAMS: SER_BAUD NEEDS TO BE SET TO BAUD RATE + 1385 ; 1200: 96 = 1,843,200 / ( 16 X 1200 ) + 1386 ; 2400: 48 = 1,843,200 / ( 16 X 2400 ) + 1387 ; 4800: 24 = 1,843,200 / ( 16 X 4800 ) + 1388 ; 9600: 12 = 1,843,200 / ( 16 X 9600 ) + 1389 ; 19K2: 06 = 1,843,200 / ( 16 X 19,200 ) + 1390 ; 38K4: 03 + 1391 ; 57K6: 02 + 1392 ; 115K2: 01 + 1393 ; + 1394 ;_________________________________________________________________________________________________________________________________ + 1395 ; + 0614 1396 INIT_UART: + 0614 3E 80 1397 LD A,#0x80 ; + 0616 D3 6B 1398 OUT (UART3),A ; SET DLAB FLAG + 0618 3Ar3As07 1399 LD A,(SER_BAUD) ; + 061B D3 68 1400 OUT (UART0),A ; + 061D 3E 00 1401 LD A,#0 ; + 061F D3 69 1402 OUT (UART1),A ; + 0621 3E 03 1403 LD A,#3 ; + 0623 D3 6B 1404 OUT (UART3),A ; SET 8 BIT DATA, 1 STOPBIT + 0625 3E 03 1405 LD A,#3 ; set DTR & RTS + 0627 D3 6C 1406 OUT (UART4),A ; + 0629 C9 1407 RET + 1408 + 1409 + 1410 ; + 1411 ;__FILL_MEM_______________________________________________________________________________________________________________________ + 1412 ; + 1413 ; FUNCTION : FILL MEMORY WITH A VALUE + 1414 ; INPUT : HL = START ADDRESS BLOCK + 1415 ; : BC = LENGTH OF BLOCK + 1416 ; : A = VALUE TO FILL WITH + 1417 ; USES : DE, BC + 1418 ; OUTPUT : + 1419 ; CALLS : + 1420 ; TESTED : 13 FEB 2007 + 1421 ;_________________________________________________________________________________________________________________________________ + 1422 ; + 062A 1423 FILL_MEM: + 062A 5D 1424 LD E,L ; + 062B 54 1425 LD D,H ; + 062C 13 1426 INC DE ; + 062D 77 1427 LD (HL),A ; INITIALISE FIRST BYTE OF BLOCK WITH DATA BYTE IN A + 062E 0B 1428 DEC BC ; + 062F ED B0 1429 LDIR ; FILL MEMORY + 0631 C9 1430 RET ; RETURN TO CALLER + 1431 + 1432 ; + 1433 ;__INITIALIZE_____________________________________________________________________________________________________________________ + 1434 ; + 1435 ; INITIALIZE SYSTEM + 1436 ;_________________________________________________________________________________________________________________________________ + 1437 ; + 0632 1438 INITIALIZE: + 0632 3E 0C 1439 LD A,#12 ; SPECIFY BAUD RATE 9600 BPS (9600,8,NONE,1) + 0634 32r3As07 1440 LD (SER_BAUD),A ; + 0637 CDr14s06 1441 CALL INIT_UART ; INIT THE UART + 063A C9 1442 RET ; + 1443 ; + 1444 + 1445 ;__MTERM_INIT________________________________________________________________________________________ + 1446 ; + 1447 ; SETUP 8255, MODE 0, PORT A=OUT, PORT B=IN, PORT C=OUT/OUT + 1448 ; + 1449 ;____________________________________________________________________________________________________ + 063B 1450 MTERM_INIT: + 063B 3E 82 1451 LD A,#0x82 + 063D D3 63 1452 OUT (PIOCONT),A + 063F C9 1453 RET + 1454 + 1455 ;__KB_GET____________________________________________________________________________________________ + 1456 ; + 1457 ; GET A SINGLE KEY AND DECODE + 1458 ; + 1459 ;____________________________________________________________________________________________________ + 0640 1460 KB_GET: + 0640 E5 1461 PUSH HL ; STORE HL + 0641 1462 KB_GET_LOOP: ; WAIT FOR KEY + 0641 CDr67s06 1463 CALL KB_SCAN ; SCAN KB ONCE + 0644 FE 00 1464 CP #0 ; NULL? + 0646 28 F9 1465 JR Z,KB_GET_LOOP ; LOOP WHILE NOT ZERO + 0648 57 1466 LD D,A ; STORE A + 0649 3E 4F 1467 LD A,#0x4F ; SCAN ALL COL LINES + 064B D3 62 1468 OUT (PORTC),A ; SEND TO COLUMN LINES + 064D CDrB4s06 1469 CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + 0650 1470 KB_CLEAR_LOOP: ; WAIT FOR KEY TO CLEAR + 0650 DB 61 1471 IN A,(PORTB) ; GET ROWS + 0652 FE 00 1472 CP #0 ; ANYTHING PRESSED? + 0654 20 FA 1473 JR NZ,KB_CLEAR_LOOP ; YES, EXIT + 0656 7A 1474 LD A,D ; RESTORE A + 0657 16 00 1475 LD D,#0x00 ; + 0659 21rE7s0C 1476 LD HL,#KB_DECODE ; POINT TO BEGINNING OF TABLE + 065C 1477 KB_GET_LLOOP: + 065C BE 1478 CP (HL) ; MATCH? + 065D 28 05 1479 JR Z,KB_GET_DONE ; FOUND, DONE + 065F 23 1480 INC HL + 0660 14 1481 INC D ; D + 1 + 0661 C2r5Cs06 1482 JP NZ,KB_GET_LLOOP ; NOT FOUND, LOOP UNTIL EOT + 0664 1483 KB_GET_DONE: + 0664 7A 1484 LD A,D ; RESULT INTO A + 0665 E1 1485 POP HL ; RESTORE HL + 0666 C9 1486 RET + 1487 + 1488 + 1489 + 1490 ;__KB_SCAN____________________________________________________________________________________________ + 1491 ; + 1492 ; SCAN KEYBOARD MATRIX FOR AN INPUT + 1493 ; + 1494 ;____________________________________________________________________________________________________ + 0667 1495 KB_SCAN: + 1496 + 0667 0E 00 1497 LD C,#0 + 0669 3E 41 1498 LD A,#0x41 ; SCAN COL ONE + 066B D3 62 1499 OUT (PORTC),A ; SEND TO COLUMN LINES + 066D CDrB4s06 1500 CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + 0670 DB 61 1501 IN A,(PORTB) ; GET ROWS + 0672 FE 00 1502 CP #0x00 ; ANYTHING PRESSED? + 0674 20 34 1503 JR NZ,KB_SCAN_FOUND ; YES, EXIT + 1504 + 0676 0E 40 1505 LD C,#0x0040 + 0678 3E 42 1506 LD A,#0x42 ; SCAN COL TWO + 067A D3 62 1507 OUT (PORTC),A ; SEND TO COLUMN LINES + 067C CDrB4s06 1508 CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + 067F DB 61 1509 IN A,(PORTB) ; GET ROWS + 0681 FE 00 1510 CP #0 ; ANYTHING PRESSED? + 0683 20 25 1511 JR NZ,KB_SCAN_FOUND ; YES, EXIT + 1512 + 0685 0E 80 1513 LD C,#0x0080 + 0687 3E 44 1514 LD A,#0x44 ; SCAN COL THREE + 0689 D3 62 1515 OUT (PORTC),A ; SEND TO COLUMN LINES + 068B CDrB4s06 1516 CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + 068E DB 61 1517 IN A,(PORTB) ; GET ROWS + 0690 FE 00 1518 CP #0x00 ; ANYTHING PRESSED? + 0692 20 16 1519 JR NZ,KB_SCAN_FOUND ; YES, EXIT + 1520 + 0694 0E C0 1521 LD C,#0x00C0 ; + 0696 3E 48 1522 LD A,#0x48 ; SCAN COL FOUR + 0698 D3 62 1523 OUT (PORTC),A ; SEND TO COLUMN LINES + 069A CDrB4s06 1524 CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + 069D DB 61 1525 IN A,(PORTB) ; GET ROWS + 069F FE 00 1526 CP #0x00 ; ANYTHING PRESSED? + 06A1 20 07 1527 JR NZ,KB_SCAN_FOUND ; YES, EXIT + 1528 + 06A3 3E 40 1529 LD A, #0x40 ; TURN OFF ALL COLUMNS + 06A5 D3 62 1530 OUT (PORTC),A ; SEND TO COLUMN LINES + 06A7 3E 00 1531 LD A, #0x00 ; RETURN NULL + 06A9 C9 1532 RET ; EXIT + 1533 + 06AA 1534 KB_SCAN_FOUND: + 06AA E6 3F 1535 AND #0x3F ; CLEAR TOP TWO BITS + 06AC B1 1536 OR C ; ADD IN ROW BITS + 06AD 4F 1537 LD C,A ; STORE VALUE + 06AE 3E 00 1538 LD A,#0x00 ; TURN OFF ALL COLUMNS + 06B0 D3 62 1539 OUT (PORTC),A ; SEND TO COLUMN LINES + 06B2 79 1540 LD A,C ; RESTORE VALUE + 06B3 C9 1541 RET + 1542 + 06B4 1543 PAUSE: + 06B4 1544 KB_SCAN_DELAY: + 06B4 00 1545 NOP + 06B5 00 1546 NOP + 06B6 00 1547 NOP + 06B7 00 1548 NOP + 06B8 00 1549 NOP + 06B9 00 1550 NOP + 06BA 00 1551 NOP + 06BB 00 1552 NOP + 06BC 00 1553 NOP + 06BD C9 1554 RET + 1555 + 1556 + 1557 + 1558 ;__HEXDISPLAY________________________________________________________________________________________ + 1559 ; + 1560 ; DISPLAY CONTENTS OF DISPLAYBUF IN DECODED HEX BITS 0-3 ARE DISPLAYED DIG, BIT 7 IS DP + 1561 ; + 1562 ;____________________________________________________________________________________________________ + 06BE 1563 HEXDISPLAY: + 06BE E5 1564 PUSH HL ; STORE HL + 06BF F5 1565 PUSH AF ; STORE AF + 06C0 C5 1566 PUSH BC ; STORE BC + 06C1 01 07 00 1567 LD BC,#0007 + 06C4 09 1568 ADD HL,BC + 06C5 06 08 1569 LD B,#0x08 ; SET DIGIT COUNT + 06C7 3E 40 1570 LD A,#0x40 ; SET CONTROL PORT 7218 TO OFF + 06C9 D3 62 1571 OUT (PORTC),A ; OUTPUT + 06CB CDrB4s06 1572 CALL PAUSE ; WAIT + 06CE 3E F0 1573 LD A,#0x0F0 ; SET CONTROL TO 1111 (DATA COMING, HEX DECODE,NO DECODE, NORMAL) + 06D0 D3 60 1574 OUT (PORTA),A ; OUTPUT TO PORT + 06D2 3E 80 1575 LD A,#0x80 ; STROBE WRITE PULSE WITH CONTROL=1 + 06D4 D3 62 1576 OUT (PORTC),A ; OUTPUT TO PORT + 06D6 CDrB4s06 1577 CALL PAUSE ; WAIT + 06D9 3E 40 1578 LD A,#0x40 ; SET CONTROL PORT 7218 TO OFF + 06DB D3 62 1579 OUT (PORTC),A ; OUTPUT + 06DD 1580 HEXDISPLAY_LP: + 06DD 7E 1581 LD A,(HL) ; GET DISPLAY DIGIT + 06DE CDrF8s06 1582 CALL DECODEDISPLAY ; DECODE DISPLAY + 06E1 D3 60 1583 OUT (PORTA),A ; OUT TO PORTA + 06E3 3E 00 1584 LD A,#0x00 ; SET WRITE STROBE + 06E5 D3 62 1585 OUT (PORTC),A ; OUT TO PORTC + 06E7 CDrB4s06 1586 CALL PAUSE ; DELAY + 06EA 3E 40 1587 LD A,#0x40 ; SET CONTROL PORT OFF + 06EC D3 62 1588 OUT (PORTC),A ; OUT TO PORTC + 06EE CDrB4s06 1589 CALL PAUSE ; WAIT + 06F1 2B 1590 DEC HL ; INC POINTER + 06F2 10 E9 1591 DJNZ HEXDISPLAY_LP ; LOOP FOR NEXT DIGIT + 06F4 C1 1592 POP BC ; RESTORE BC + 06F5 F1 1593 POP AF ; RESTORE AF + 06F6 E1 1594 POP HL ; RESTORE HL + 06F7 C9 1595 RET + 1596 + 1597 ;__DECODEDISPLAY_____________________________________________________________________________________ + 1598 ; + 1599 ; DISPLAY CONTENTS OF DISPLAYBUF IN DECODED HEX BITS 0-3 ARE DISPLAYED DIG, BIT 7 IS DP + 1600 ; + 1601 ;____________________________________________________________________________________________________ + 06F8 1602 DECODEDISPLAY: + 06F8 C5 1603 PUSH BC ; STORE BC + 06F9 E5 1604 PUSH HL ; STORE HL + 06FA 21rFFs0C 1605 LD HL,#SEGDECODE ; POINT HL TO DECODE TABLE + 06FD 06 00 1606 LD B,#0x00 ; RESET HIGH BYTE + 06FF 4F 1607 LD C,A ; CHAR INTO LOW BYTE + 0700 09 1608 ADD HL,BC ; SET TABLE POINTER + 0701 7E 1609 LD A,(HL) ; GET VALUE + 0702 E1 1610 POP HL ; RESTORE HL + 0703 C1 1611 POP BC ; RESTORE BC + 0704 C9 1612 RET + 1613 + 1614 + 1615 ;__SEGDISPLAY________________________________________________________________________________________ + 1616 ; + 1617 ; DISPLAY CONTENTS OF DISPLAYBUF IN DECODED HEX BITS 0-3 ARE DISPLAYED DIG, BIT 7 IS DP + 1618 ; + 1619 ;____________________________________________________________________________________________________ + 0705 1620 SEGDISPLAY: + 0705 F5 1621 PUSH AF ; STORE AF + 0706 C5 1622 PUSH BC ; STORE BC + 0707 01 07 00 1623 LD BC,#0x0007 + 070A 09 1624 ADD HL,BC + 070B 06 08 1625 LD B,#0x08 ; SET DIGIT COUNT + 070D 3E 40 1626 LD A,#0x40 ; SET CONTROL PORT 7218 TO OFF + 070F D3 62 1627 OUT (PORTC),A ; OUTPUT + 0711 CDrB4s06 1628 CALL PAUSE ; WAIT + 0714 3E F0 1629 LD A,#0x0F0 ; SET CONTROL TO 1111 (DATA COMING, HEX DECODE,NO DECODE, NORMAL) + 0716 D3 60 1630 OUT (PORTA),A ; OUTPUT TO PORT + 0718 3E 80 1631 LD A,#0x80 ; STROBE WRITE PULSE WITH CONTROL=1 + 071A D3 62 1632 OUT (PORTC),A ; OUTPUT TO PORT + 071C CDrB4s06 1633 CALL PAUSE ; WAIT + 071F 3E 40 1634 LD A,#0x40 ; SET CONTROL PORT 7218 TO OFF + 0721 D3 62 1635 OUT (PORTC),A ; OUTPUT + 0723 1636 SEGDISPLAY_LP: + 0723 7E 1637 LD A,(HL) ; GET DISPLAY DIGIT + 0724 D3 60 1638 OUT (PORTA),A ; OUT TO PORTA + 0726 3E 00 1639 LD A,#0x00 ; SET WRITE STROBE + 0728 D3 62 1640 OUT (PORTC),A ; OUT TO PORTC + 072A CDrB4s06 1641 CALL PAUSE ; DELAY + 072D 3E 40 1642 LD A,#0x40 ; SET CONTROL PORT OFF + 072F D3 62 1643 OUT (PORTC),A ; OUT TO PORTC + 0731 CDrB4s06 1644 CALL PAUSE ; WAIT + 0734 2B 1645 DEC HL ; INC POINTER + 0735 10 EC 1646 DJNZ SEGDISPLAY_LP ; LOOP FOR NEXT DIGIT + 0737 C1 1647 POP BC ; RESTORE BC + 0738 F1 1648 POP AF ; RESTORE AF + 0739 C9 1649 RET + 1650 + 1651 ; + 1652 ;__WORK_AREA___________________________________________________________________________________________________________________ + 1653 ; + 1654 ; RESERVED RAM FOR MONITOR WORKING AREA + 1655 ;_____________________________________________________________________________________________________________________________ + 1656 ; + 073A 1657 SER_BAUD: .DS 1 ; SPECIFY DESIRED UART COM RATE IN BPS + 073B 20 20 20 20 20 20 1658 KEYBUF: .ascii " " + 20 20 20 20 20 20 + 20 20 20 20 20 20 + 20 20 20 20 20 20 + 20 20 20 20 20 20 + 20 20 20 20 + 075D 20 20 20 20 20 20 1659 .ascii " " + 20 20 20 20 20 20 + 20 20 20 20 20 20 + 20 20 20 20 20 20 + 20 20 20 20 20 20 + 20 20 20 20 20 20 + 20 20 20 20 20 20 + 20 20 20 20 + 078B 00 00 00 00 00 00 1660 DISPLAYBUF: .DB 00,00,00,00,00,00,00,00 + 00 00 + 0793 01 1661 IDEDEVICE: .DB 1 ; IDE DRIVE SELECT FLAG (00H=PRIAMRY, 10H = SECONDARY) + 0794 1662 IDE_SECTOR_BUFFER: + 0794 1663 .DS 0x00200 + 1664 + 1665 + 1666 + 1667 + 1668 ; + 1669 ;__TEXT_STRINGS_________________________________________________________________________________________________________________ + 1670 ; + 1671 ; SYSTEM TEXT STRINGS + 1672 ;_____________________________________________________________________________________________________________________________ + 1673 ; + 0994 1674 TCRLF: + 0994 0D 0A FF 1675 .DB CR,LF,ENDT + 1676 + 0997 1677 PROMPT: + 0997 0D 0A 1678 .DB CR,LF + 0999 3E 1679 .ascii ">" + 099A FF 1680 .DB ENDT + 1681 + 099B 1682 TXT_READY: + 099B 0D 0A 1683 .DB CR,LF + 099D 20 20 20 20 20 20 1684 .ascii " NN NN 8888 VV VV EEEEEEEEEE MM MM" + 20 20 20 4E 4E 20 + 20 20 20 20 20 4E + 4E 20 20 20 20 20 + 20 38 38 38 38 20 + 20 20 20 20 20 56 + 56 20 20 20 20 20 + 20 56 56 20 20 20 + 20 45 45 45 45 45 + 45 45 45 45 45 20 + 20 20 4D 4D 20 20 + 20 20 20 20 20 20 + 20 20 4D 4D + 09E9 0D 0A 1685 .DB CR,LF + 09EB 20 20 20 20 20 20 1686 .ascii " NNNN NN 88 88 VV VV EE MMMM MMMM" + 20 20 4E 4E 4E 4E + 20 20 20 20 4E 4E + 20 20 20 20 38 38 + 20 20 20 20 38 38 + 20 20 20 20 56 56 + 20 20 20 20 20 20 + 56 56 20 20 20 20 + 45 45 20 20 20 20 + 20 20 20 20 20 20 + 20 4D 4D 4D 4D 20 + 20 20 20 20 20 4D + 4D 4D 4D + 0A36 0D 0A 1687 .DB CR,LF + 0A38 20 20 20 20 20 20 1688 .ascii " NN NN NN 88 88 VV VV EE MM MM MM MM" + 20 4E 4E 20 20 4E + 4E 20 20 4E 4E 20 + 20 20 20 38 38 20 + 20 20 20 38 38 20 + 20 20 20 56 56 20 + 20 20 20 20 20 56 + 56 20 20 20 20 45 + 45 20 20 20 20 20 + 20 20 20 20 20 20 + 4D 4D 20 20 4D 4D + 20 20 4D 4D 20 20 + 4D 4D + 0A82 0D 0A 1689 .DB CR,LF + 0A84 20 20 20 20 20 20 1690 .ascii " NN NNNN 88 88 VV VV EE MM MM MM" + 4E 4E 20 20 20 20 + 4E 4E 4E 4E 20 20 + 20 20 38 38 20 20 + 20 20 38 38 20 20 + 20 20 56 56 20 20 + 20 20 20 20 56 56 + 20 20 20 20 45 45 + 20 20 20 20 20 20 + 20 20 20 20 20 4D + 4D 20 20 20 20 4D + 4D 20 20 20 20 4D + 4D + 0ACD 0D 0A 1691 .DB CR,LF + 0ACF 20 20 20 20 20 4E 1692 .ascii " NN NN 8888 VV VV EEEEEEE MM MM" + 4E 20 20 20 20 20 + 20 4E 4E 20 20 20 + 20 20 20 38 38 38 + 38 20 20 20 20 20 + 20 56 56 20 20 20 + 20 20 20 56 56 20 + 20 20 20 45 45 45 + 45 45 45 45 20 20 + 20 20 20 20 4D 4D + 20 20 20 20 20 20 + 20 20 20 20 4D 4D + 0B17 0D 0A 1693 .DB CR,LF + 0B19 20 20 20 20 4E 4E 1694 .ascii " NN NN 88 88 VV VV EE MM MM" + 20 20 20 20 20 20 + 4E 4E 20 20 20 20 + 38 38 20 20 20 20 + 38 38 20 20 20 20 + 20 56 56 20 20 20 + 20 56 56 20 20 20 + 20 20 45 45 20 20 + 20 20 20 20 20 20 + 20 20 20 4D 4D 20 + 20 20 20 20 20 20 + 20 20 20 4D 4D + 0B60 0D 0A 1695 .DB CR,LF + 0B62 20 20 20 4E 4E 20 1696 .ascii " NN NN 88 88 VV VV EE MM MM" + 20 20 20 20 20 4E + 4E 20 20 20 20 38 + 38 20 20 20 20 38 + 38 20 20 20 20 20 + 20 56 56 20 20 56 + 56 20 20 20 20 20 + 20 45 45 20 20 20 + 20 20 20 20 20 20 + 20 20 4D 4D 20 20 + 20 20 20 20 20 20 + 20 20 4D 4D + 0BA8 0D 0A 1697 .DB CR,LF + 0BAA 20 20 4E 4E 20 20 1698 .ascii " NN NN 88 88 VVV EE MM MM" + 20 20 20 20 4E 4E + 20 20 20 20 38 38 + 20 20 20 20 38 38 + 20 20 20 20 20 20 + 20 20 56 56 56 20 + 20 20 20 20 20 20 + 45 45 20 20 20 20 + 20 20 20 20 20 20 + 20 4D 4D 20 20 20 + 20 20 20 20 20 20 + 20 4D 4D + 0BEF 0D 0A 1699 .DB CR,LF + 0BF1 20 4E 4E 20 20 20 1700 .ascii " NN NN 8888 V EEEEEEEEEE MM MM S B C" + 20 20 20 4E 4E 20 + 20 20 20 20 20 38 + 38 38 38 20 20 20 + 20 20 20 20 20 20 + 20 20 56 20 20 20 + 20 20 20 20 20 45 + 45 45 45 45 45 45 + 45 45 45 20 20 20 + 4D 4D 20 20 20 20 + 20 20 20 20 20 20 + 4D 4D 20 20 20 20 + 53 20 42 20 43 + 0C3E 0D 0A 1701 .DB CR,LF + 0C40 0D 0A 1702 .DB CR,LF + 0C42 20 2A 2A 2A 2A 2A 1703 .ascii " ****************************************************************************" + 2A 2A 2A 2A 2A 2A + 2A 2A 2A 2A 2A 2A + 2A 2A 2A 2A 2A 2A + 2A 2A 2A 2A 2A 2A + 2A 2A 2A 2A 2A 2A + 2A 2A 2A 2A 2A 2A + 2A 2A 2A 2A 2A 2A + 2A 2A 2A 2A 2A 2A + 2A 2A 2A 2A 2A 2A + 2A 2A 2A 2A 2A 2A + 2A 2A 2A 2A 2A 2A + 2A 2A 2A 2A 2A + 0C8F 0D 0A 1704 .DB CR,LF + 0C91 4D 4F 4E 49 54 4F 1705 .ascii "MONITOR READY " + 52 20 52 45 41 44 + 59 20 + 0C9F 0D 0A FF 1706 .DB CR,LF,ENDT + 1707 + 0CA2 1708 TXT_COMMAND: + 0CA2 0D 0A 1709 .DB CR,LF + 0CA4 55 4E 4B 4E 4F 57 1710 .ascii "UNKNOWN COMMAND." + 4E 20 43 4F 4D 4D + 41 4E 44 2E + 0CB4 FF 1711 .DB ENDT + 1712 + 0CB5 1713 TXT_CKSUMERR: + 0CB5 0D 0A 1714 .DB CR,LF + 0CB7 43 48 45 43 4B 53 1715 .ascii "CHECKSUM ERROR." + 55 4D 20 45 52 52 + 4F 52 2E + 0CC6 FF 1716 .DB ENDT + 0CC7 1717 CPUUP: + 0CC7 84 EE BB 80 BB EE 1718 .DB 0x084,0x0EE,0x0BB,0x080,0x0BB,0x0EE,0x0CB,0x084 + CB 84 + 0CCF 1719 ADDR: + 0CCF 00 00 00 00 8C BD 1720 .DB 0x00,0x00,0x00,0x00,0x08C,0x0BD,0x0BD,0x0FE + BD FE + 1721 + 1722 + 0CD7 1723 PORT: + 0CD7 00 00 80 80 94 8C 1724 .DB 0x00,0x00,0x80,0x80,0x094,0x08C,0x09D,0x0EE + 9D EE + 0CDF 1725 SEC: + 0CDF 80 80 80 80 80 CB 1726 .DB 0x80,0x80,0x80,0x80,0x80,0x0CB,0x0CF,0x0D7 + CF D7 + 1727 + 1728 + 1729 ;_KB DECODE TABLE__________________________________________________________________________________________________________ + 1730 ; + 1731 ; + 0CE7 1732 KB_DECODE: + 1733 ; 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0CE7 41 02 42 82 04 44 1734 .DB 0x41,0x02,0x42,0x82,0x04,0x44,0x84,0x08,0x48,0x88,0x10,0x50,0x90,0x20,0x60,0x0A0 + 84 08 48 88 10 50 + 90 20 60 A0 + 1735 ; FW BK CL EN DP EX GO BO + 0CF7 01 81 C1 C2 C4 C8 1736 .DB 0x01,0x81,0x0C1,0x0C2,0x0C4,0x0C8,0x0D0,0x0E0 + D0 E0 + 1737 ; + 1738 ; F-KEYS, + 1739 ; FW = FORWARD + 1740 ; BK = BACKWARD + 1741 ; CL = CLEAR + 1742 ; EN = ENTER + 1743 ; DP = DEPOSIT (INTO MEM) + 1744 ; EX = EXAMINE (MEM) + 1745 ; GO = GO + 1746 ; BO = BOOT + 1747 ;_________________________________________________________________________________________________________________________ + 1748 ;_HEX 7_SEG_DECODE_TABLE__________________________________________________________________________________________________ + 1749 ; + 1750 ; 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F, ,- + 1751 ; AND WITH 7FH TO TURN ON DP + 1752 ;_________________________________________________________________________________________________________________________ + 0CFF 1753 SEGDECODE: + 0CFF FB B0 ED F5 B6 D7 1754 .DB 0x0FB,0x0B0,0x0ED,0x0F5,0x0B6,0x0D7,0x0DF,0x0F0,0x0FF,0x0F7,0x0FE,0x09F,0x0CB,0x0BD,0x0CF,0x0CE,0x080,0x084,0x00,0x0EE,0x09D + DF F0 FF F7 FE 9F + CB BD CF CE 80 84 + 00 EE 9D + 1755 + 1756 ;********************* END OF PROGRAM *********************************** + 1757 + 1758 ;dwg; .ORG 08FFFh + 1759 ;dwg; .DB 000h + 1760 ;dwg; .END + 1761 + 0D14 1762 _dbgmon_end:: + 1763 .area _CODE + 1764 .area _CABS diff --git a/doug/src/dbgmon.rel b/doug/src/dbgmon.rel new file mode 100755 index 00000000..e2e39a62 --- /dev/null +++ b/doug/src/dbgmon.rel @@ -0,0 +1,838 @@ +XL +H 8 areas 4 global symbols +M dbgmon +O -mz80 +S .__.ABS. Def0000 +A _CODE size 0 flags 0 addr 0 +A _DATA size 0 flags 0 addr 0 +A _OVERLAY size 0 flags 0 addr 0 +A _HOME size 0 flags 0 addr 0 +A _GSINIT size 0 flags 0 addr 0 +A _GSFINAL size 0 flags 0 addr 0 +A _DBGMON size D14 flags 0 addr 0 +S _dbgmon Def0000 +S _dbgmon_start Def0000 +S _dbgmon_end Def0D14 +A _CABS size 0 flags 0 addr 0 +T 00 00 +R 00 00 06 00 +T 00 00 +R 00 00 06 00 +T 00 00 31 FF CF CD 32 06 CD 3B 06 21 C7 0C CD +R 00 00 06 00 00 06 06 00 00 09 06 00 00 0C 06 00 +T 0D 00 05 07 +R 00 00 06 00 00 02 06 00 +T 0F 00 +R 00 00 06 00 +T 0F 00 CD 40 06 FE 10 CA 3C 00 FE 11 CA 94 00 FE +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0D 06 00 +T 1D 00 14 CA D0 00 FE 15 CA 24 01 FE 16 CA CC 00 +R 00 00 06 00 00 04 06 00 00 09 06 00 00 0E 06 00 +T 2B 00 FE 17 CA 33 00 18 DD +R 00 00 06 00 00 05 06 00 +T 32 00 +R 00 00 06 00 +T 32 00 C9 +R 00 00 06 00 +T 33 00 +R 00 00 06 00 +T 33 00 3E 00 D3 7C D3 78 C3 00 00 +R 00 00 06 00 +T 3C 00 +R 00 00 06 00 +T 3C 00 CD 6C 02 +R 00 00 06 00 00 03 06 00 +T 3F 00 +R 00 00 06 00 +T 3F 00 4F CB 3F CB 3F CB 3F CB 3F 32 90 07 79 E6 +R 00 00 06 00 00 0C 06 00 +T 4D 00 0F 32 8F 07 ED 78 4F CB 3F CB 3F CB 3F CB +R 00 00 06 00 00 04 06 00 +T 5B 00 3F 32 8C 07 79 E6 0F 32 8B 07 3E 10 32 +R 00 00 06 00 00 04 06 00 00 0A 06 00 +T 68 00 8D 07 32 8E 07 3E 13 32 92 07 3E 14 32 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T 75 00 91 07 21 8B 07 CD BE 06 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 7D 00 +R 00 00 06 00 +T 7D 00 CD 40 06 FE 12 CA 8B 00 FE 10 28 B3 18 F2 +R 00 00 06 00 00 03 06 00 00 08 06 00 +T 8B 00 +R 00 00 06 00 +T 8B 00 21 C7 0C CD 05 07 C3 0F 00 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 94 00 +R 00 00 06 00 +T 94 00 CD 6C 02 +R 00 00 06 00 00 03 06 00 +T 97 00 +R 00 00 06 00 +T 97 00 4F CB 3F CB 3F CB 3F CB 3F 32 90 07 79 E6 +R 00 00 06 00 00 0C 06 00 +T A5 00 0F 32 8F 07 3E 10 32 8D 07 32 8E 07 3E 13 +R 00 00 06 00 00 04 06 00 00 09 06 00 00 0C 06 00 +T B3 00 32 92 07 3E 14 32 91 07 21 8B 07 CD +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0B 06 00 +T BF 00 CF 02 ED 79 21 C7 0C CD 05 07 C3 +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T CA 00 0F 00 +R 00 00 06 00 00 02 06 00 +T CC 00 +R 00 00 06 00 +T CC 00 CD 89 01 E9 +R 00 00 06 00 00 03 06 00 +T D0 00 +R 00 00 06 00 +T D0 00 CD 89 01 E5 +R 00 00 06 00 00 03 06 00 +T D4 00 +R 00 00 06 00 +T D4 00 7C CB 3F CB 3F CB 3F CB 3F 32 92 07 7C E6 +R 00 00 06 00 00 0C 06 00 +T E2 00 0F 32 91 07 7D CB 3F CB 3F CB 3F CB 3F 32 +R 00 00 06 00 00 04 06 00 +T F0 00 90 07 7D E6 0F 32 8F 07 3E 10 32 8E 07 21 +R 00 00 06 00 00 02 06 00 00 08 06 00 00 0D 06 00 +T FE 00 8B 07 CD CF 02 E1 77 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 05 01 +R 00 00 06 00 +T 05 01 CD 40 06 FE 12 CA 1B 01 FE 13 28 06 FE 14 +R 00 00 06 00 00 03 06 00 00 08 06 00 +T 13 01 28 BB 18 EE +R 00 00 06 00 +T 17 01 +R 00 00 06 00 +T 17 01 23 E5 18 B9 +R 00 00 06 00 +T 1B 01 +R 00 00 06 00 +T 1B 01 21 C7 0C CD 05 07 C3 0F 00 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 24 01 +R 00 00 06 00 +T 24 01 CD 89 01 E5 +R 00 00 06 00 00 03 06 00 +T 28 01 +R 00 00 06 00 +T 28 01 7C CB 3F CB 3F CB 3F CB 3F 32 92 07 7C E6 +R 00 00 06 00 00 0C 06 00 +T 36 01 0F 32 91 07 7D CB 3F CB 3F CB 3F CB 3F 32 +R 00 00 06 00 00 04 06 00 +T 44 01 90 07 7D E6 0F 32 8F 07 3E 10 32 8E 07 7E +R 00 00 06 00 00 02 06 00 00 08 06 00 00 0D 06 00 +T 52 01 CB 3F CB 3F CB 3F CB 3F 32 8C 07 7E E6 0F +R 00 00 06 00 00 0B 06 00 +T 60 01 32 8B 07 21 8B 07 CD BE 06 E1 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 6A 01 +R 00 00 06 00 +T 6A 01 CD 40 06 FE 12 CA 80 01 FE 13 28 06 FE 15 +R 00 00 06 00 00 03 06 00 00 08 06 00 +T 78 01 28 AA 18 EE +R 00 00 06 00 +T 7C 01 +R 00 00 06 00 +T 7C 01 23 E5 18 A8 +R 00 00 06 00 +T 80 01 +R 00 00 06 00 +T 80 01 21 C7 0C CD 05 07 C3 0F 00 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 89 01 +R 00 00 06 00 +T 89 01 C5 18 6A +R 00 00 06 00 +T 8C 01 +R 00 00 06 00 +T 8C 01 21 CF 0C CD 05 07 +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 92 01 +R 00 00 06 00 +T 92 01 CD 40 06 FE 10 FA DD 01 FE 13 28 06 FE 12 +R 00 00 06 00 00 03 06 00 00 08 06 00 +T A0 01 28 54 18 EE +R 00 00 06 00 +T A4 01 +R 00 00 06 00 +T A4 01 21 00 00 3A 8C 07 CB 27 CB 27 CB 27 CB 27 +R 00 00 06 00 00 06 06 00 +T B2 01 4F 3A 8B 07 E6 0F B1 6F 3A 8E 07 CB 27 CB +R 00 00 06 00 00 04 06 00 00 0B 06 00 +T C0 01 27 CB 27 CB 27 4F 3A 8D 07 E6 0F B1 67 3E +R 00 00 06 00 00 09 06 00 +T CE 01 10 32 8B 07 32 8C 07 32 8D 07 32 +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T D9 01 8E 07 C1 C9 +R 00 00 06 00 00 02 06 00 +T DD 01 +R 00 00 06 00 +T DD 01 4F 3A 8D 07 32 8E 07 3A 8C 07 32 +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0A 06 00 +T E8 01 8D 07 3A 8B 07 32 8C 07 79 32 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T F2 01 8B 07 18 0E +R 00 00 06 00 00 02 06 00 +T F6 01 +R 00 00 06 00 +T F6 01 3E 12 32 8B 07 32 8C 07 32 8D 07 32 +R 00 00 06 00 00 05 06 00 00 08 06 00 00 0B 06 00 +T 02 02 8E 07 +R 00 00 06 00 00 02 06 00 +T 04 02 +R 00 00 06 00 +T 04 02 3A 8B 07 CD F8 06 32 CF 0C 3A +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 0E 02 8C 07 CD F8 06 32 D0 0C 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 17 02 8D 07 CD F8 06 32 D1 0C 3A +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 20 02 8E 07 CD F8 06 32 D2 0C C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 29 02 8C 01 +R 00 00 06 00 00 02 06 00 +T 2B 02 +R 00 00 06 00 +T 2B 02 C5 E5 7C CB 3F CB 3F CB 3F CB 3F E6 0F CD +R 00 00 06 00 +T 39 02 F8 06 32 E2 0C 7C E6 0F CD F8 06 32 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0B 06 00 +T 45 02 E1 0C 7D E6 F0 CB 3F CB 3F CB 3F CB 3F E6 +R 00 00 06 00 00 02 06 00 +T 53 02 0F CD F8 06 32 E0 0C 7D E6 0F CD F8 06 32 +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0D 06 00 +T 61 02 DF 0C 21 DF 0C CD 05 07 E1 C1 C9 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T 6C 02 +R 00 00 06 00 +T 6C 02 C5 18 43 +R 00 00 06 00 +T 6F 02 +R 00 00 06 00 +T 6F 02 21 D7 0C CD 05 07 +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 75 02 +R 00 00 06 00 +T 75 02 CD 40 06 FE 10 FA A5 02 FE 13 28 06 FE 12 +R 00 00 06 00 00 03 06 00 00 08 06 00 +T 83 02 28 2D 18 EE +R 00 00 06 00 +T 87 02 +R 00 00 06 00 +T 87 02 3A 8C 07 CB 27 CB 27 CB 27 CB 27 4F 3A +R 00 00 06 00 00 03 06 00 +T 94 02 8B 07 E6 0F B1 4F 3E 10 32 8B 07 32 8C 07 +R 00 00 06 00 00 02 06 00 00 0B 06 00 00 0E 06 00 +T A2 02 79 C1 C9 +R 00 00 06 00 +T A5 02 +R 00 00 06 00 +T A5 02 4F 3A 8B 07 32 8C 07 79 32 8B 07 18 08 +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0B 06 00 +T B2 02 +R 00 00 06 00 +T B2 02 3E 12 32 8B 07 32 8C 07 +R 00 00 06 00 00 05 06 00 00 08 06 00 +T BA 02 +R 00 00 06 00 +T BA 02 3A 8B 07 CD F8 06 32 D7 0C 3A +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T C4 02 8C 07 CD F8 06 32 D8 0C C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 08 06 00 +T CD 02 6F 02 +R 00 00 06 00 00 02 06 00 +T CF 02 +R 00 00 06 00 +T CF 02 C5 18 40 +R 00 00 06 00 +T D2 02 +R 00 00 06 00 +T D2 02 CD BE 06 +R 00 00 06 00 00 03 06 00 +T D5 02 +R 00 00 06 00 +T D5 02 CD 40 06 FE 10 FA 05 03 FE 13 28 06 FE 12 +R 00 00 06 00 00 03 06 00 00 08 06 00 +T E3 02 28 2D 18 EE +R 00 00 06 00 +T E7 02 +R 00 00 06 00 +T E7 02 3A 8C 07 CB 27 CB 27 CB 27 CB 27 4F 3A +R 00 00 06 00 00 03 06 00 +T F4 02 8B 07 E6 0F B1 4F 3E 10 32 8B 07 32 8C 07 +R 00 00 06 00 00 02 06 00 00 0B 06 00 00 0E 06 00 +T 02 03 79 C1 C9 +R 00 00 06 00 +T 05 03 +R 00 00 06 00 +T 05 03 4F 3A 8B 07 32 8C 07 79 32 8B 07 18 C0 +R 00 00 06 00 00 04 06 00 00 07 06 00 00 0B 06 00 +T 12 03 +R 00 00 06 00 +T 12 03 3E 12 32 8B 07 32 8C 07 C3 D2 02 +R 00 00 06 00 00 05 06 00 00 08 06 00 00 0B 06 00 +T 1D 03 +R 00 00 06 00 +T 1D 03 31 FF CF CD 32 06 AF E5 21 9B 09 CD 8A 04 +R 00 00 06 00 00 06 06 00 00 0B 06 00 00 0E 06 00 +T 2B 03 E1 +R 00 00 06 00 +T 2C 03 +R 00 00 06 00 +T 2C 03 CD 81 04 21 3B 07 CD 81 03 21 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 36 03 3B 07 7E 23 FE 42 CA 33 00 FE 52 CA 98 04 +R 00 00 06 00 00 02 06 00 00 09 06 00 00 0E 06 00 +T 44 03 FE 50 CA 9D 04 FE 4F CA 63 04 FE 48 CA +R 00 00 06 00 00 05 06 00 00 0A 06 00 +T 51 03 30 05 FE 49 CA 71 04 FE 44 CA D4 04 FE 4B +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0C 06 00 +T 5F 03 CA 74 03 FE 4D CA 9C 05 FE 46 CA DD 05 21 +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0D 06 00 +T 6D 03 A2 0C CD 8A 04 18 B8 +R 00 00 06 00 00 02 06 00 00 05 06 00 +T 74 03 +R 00 00 06 00 +T 74 03 CD B4 03 CD C8 03 FE 1B 20 F6 C3 2C 03 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 0D 06 00 +T 81 03 +R 00 00 06 00 +T 81 03 0E 00 D5 +R 00 00 06 00 +T 84 03 +R 00 00 06 00 +T 84 03 CD B4 03 CD C8 03 FE 0D 28 22 FE 08 20 16 +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 92 03 79 FE 00 28 ED 2B 0D 3E 00 77 3E 20 CD +R 00 00 06 00 +T 9F 03 C8 03 3E 08 CD C8 03 18 DC +R 00 00 06 00 00 02 06 00 00 07 06 00 +T A8 03 +R 00 00 06 00 +T A8 03 77 23 0C 79 FE 4D 20 D4 +R 00 00 06 00 +T B0 03 +R 00 00 06 00 +T B0 03 36 00 D1 C9 +R 00 00 06 00 +T B4 03 +R 00 00 06 00 +T B4 03 DB 6D CB 47 CA B4 03 DB 68 E6 7F FE 41 D8 +R 00 00 06 00 00 07 06 00 +T C2 03 FE 7B D0 E6 5F C9 +R 00 00 06 00 +T C8 03 +R 00 00 06 00 +T C8 03 F5 +R 00 00 06 00 +T C9 03 +R 00 00 06 00 +T C9 03 DB 6D CB 6F CA C9 03 F1 D3 68 C9 +R 00 00 06 00 00 07 06 00 +T D4 03 +R 00 00 06 00 +T D4 03 E5 21 94 09 CD 8A 04 E1 C9 +R 00 00 06 00 00 04 06 00 00 07 06 00 +T DD 03 +R 00 00 06 00 +T DD 03 D5 CD E9 03 57 CD E9 03 6F 62 D1 C9 +R 00 00 06 00 00 04 06 00 00 08 06 00 +T E9 03 +R 00 00 06 00 +T E9 03 C5 CD FC 03 CB 07 CB 07 CB 07 CB 07 47 CD +R 00 00 06 00 00 04 06 00 +T F7 03 FC 03 80 C1 C9 +R 00 00 06 00 00 02 06 00 +T FC 03 +R 00 00 06 00 +T FC 03 7E 23 FE 40 30 03 E6 0F C9 +R 00 00 06 00 +T 05 04 +R 00 00 06 00 +T 05 04 E6 0F C6 09 C9 +R 00 00 06 00 +T 0A 04 +R 00 00 06 00 +T 0A 04 C5 CD 1D 04 CB 07 CB 07 CB 07 CB 07 47 CD +R 00 00 06 00 00 04 06 00 +T 18 04 1D 04 80 C1 C9 +R 00 00 06 00 00 02 06 00 +T 1D 04 +R 00 00 06 00 +T 1D 04 CD B4 03 23 FE 40 30 E0 E6 0F C9 +R 00 00 06 00 00 03 06 00 +T 28 04 +R 00 00 06 00 +T 28 04 C5 47 CB 07 CB 07 CB 07 CB 07 E6 0F C6 30 +R 00 00 06 00 +T 36 04 FE 3A 38 02 C6 07 +R 00 00 06 00 +T 3C 04 +R 00 00 06 00 +T 3C 04 CD C8 03 78 E6 0F C6 30 FE 3A 38 02 C6 07 +R 00 00 06 00 00 03 06 00 +T 4A 04 +R 00 00 06 00 +T 4A 04 CD C8 03 C1 C9 +R 00 00 06 00 00 03 06 00 +T 4F 04 +R 00 00 06 00 +T 4F 04 F5 3E 20 CD C8 03 F1 C9 +R 00 00 06 00 00 06 06 00 +T 57 04 +R 00 00 06 00 +T 57 04 7C CD 28 04 7D CD 28 04 CD 4F 04 C9 +R 00 00 06 00 00 04 06 00 00 08 06 00 00 0B 06 00 +T 63 04 +R 00 00 06 00 +T 63 04 +R 00 00 06 00 +T 63 04 23 CD E9 03 4F 23 CD E9 03 +R 00 00 06 00 00 04 06 00 00 09 06 00 +T 6C 04 +R 00 00 06 00 +T 6C 04 ED 79 C3 2C 03 +R 00 00 06 00 00 05 06 00 +T 71 04 +R 00 00 06 00 +T 71 04 23 CD E9 03 4F CD D4 03 ED 78 CD 28 04 C3 +R 00 00 06 00 00 04 06 00 00 08 06 00 00 0D 06 00 +T 7F 04 2C 03 +R 00 00 06 00 00 02 06 00 +T 81 04 +R 00 00 06 00 +T 81 04 E5 21 97 09 CD 8A 04 E1 C9 +R 00 00 06 00 00 04 06 00 00 07 06 00 +T 8A 04 +R 00 00 06 00 +T 8A 04 +R 00 00 06 00 +T 8A 04 7E FE FF CA 97 04 CD C8 03 23 C3 8A 04 +R 00 00 06 00 00 06 06 00 00 09 06 00 00 0D 06 00 +T 97 04 +R 00 00 06 00 +T 97 04 C9 +R 00 00 06 00 +T 98 04 +R 00 00 06 00 +T 98 04 23 CD DD 03 E9 +R 00 00 06 00 00 04 06 00 +T 9D 04 +R 00 00 06 00 +T 9D 04 23 E5 CD DD 03 54 5D E1 23 23 23 23 23 +R 00 00 06 00 00 05 06 00 +T AA 04 +R 00 00 06 00 +T AA 04 CD E9 03 12 13 CD 81 04 3E 50 CD C8 03 CD +R 00 00 06 00 00 03 06 00 00 08 06 00 00 0D 06 00 +T B8 04 4F 04 62 6B CD 57 04 21 3B 07 CD +R 00 00 06 00 00 02 06 00 00 07 06 00 00 0A 06 00 +T C3 04 81 03 21 3B 07 7E FE 00 CA D1 04 C3 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0B 06 00 +T CF 04 AA 04 +R 00 00 06 00 00 02 06 00 +T D1 04 +R 00 00 06 00 +T D1 04 C3 2C 03 +R 00 00 06 00 00 03 06 00 +T D4 04 +R 00 00 06 00 +T D4 04 23 E5 CD DD 03 54 5D E1 D5 23 23 23 23 23 +R 00 00 06 00 00 05 06 00 +T E2 04 CD DD 03 23 EB E1 +R 00 00 06 00 00 03 06 00 +T E8 04 +R 00 00 06 00 +T E8 04 CD D4 03 +R 00 00 06 00 00 03 06 00 +T EB 04 +R 00 00 06 00 +T EB 04 CD 57 04 0E 10 E5 +R 00 00 06 00 00 03 06 00 +T F1 04 +R 00 00 06 00 +T F1 04 D9 4B ED 78 D9 E6 7F FE 1B CA 2C 03 FE 13 +R 00 00 06 00 00 0C 06 00 +T FF 04 28 F0 7E CD 28 04 CD 4F 04 +R 00 00 06 00 00 06 06 00 00 09 06 00 +T 08 05 +R 00 00 06 00 +T 08 05 23 0D 20 E5 +R 00 00 06 00 +T 0C 05 +R 00 00 06 00 +T 0C 05 CD 4F 04 0E 10 E1 +R 00 00 06 00 00 03 06 00 +T 12 05 +R 00 00 06 00 +T 12 05 7E E6 60 7E 20 02 +R 00 00 06 00 +T 18 05 +R 00 00 06 00 +T 18 05 3E 2E +R 00 00 06 00 +T 1A 05 +R 00 00 06 00 +T 1A 05 CD C8 03 23 7A BC 20 05 7B BD CA 2C 03 +R 00 00 06 00 00 03 06 00 00 0D 06 00 +T 27 05 +R 00 00 06 00 +T 27 05 0D 20 E8 +R 00 00 06 00 +T 2A 05 +R 00 00 06 00 +T 2A 05 CD D4 03 C3 EB 04 +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 30 05 +R 00 00 06 00 +T 30 05 CD D4 03 +R 00 00 06 00 00 03 06 00 +T 33 05 +R 00 00 06 00 +T 33 05 CD B4 03 +R 00 00 06 00 00 03 06 00 +T 36 05 +R 00 00 06 00 +T 36 05 FE 3A 20 47 1E 00 CD 0A 04 CD 8A 05 57 CD +R 00 00 06 00 00 09 06 00 00 0C 06 00 +T 44 05 0A 04 CD 8A 05 67 CD 0A 04 CD +R 00 00 06 00 00 02 06 00 00 05 06 00 00 09 06 00 +T 4E 05 8A 05 6F CD 0A 04 CD 8A 05 FE 01 20 0D CD +R 00 00 06 00 00 02 06 00 00 06 06 00 00 09 06 00 +T 5C 05 0A 04 CD 8A 05 7B A7 CA 96 05 18 19 +R 00 00 06 00 00 02 06 00 00 05 06 00 00 0A 06 00 +T 68 05 +R 00 00 06 00 +T 68 05 7A A7 28 0B CD 0A 04 CD 8A 05 77 23 15 18 +R 00 00 06 00 00 07 06 00 00 0A 06 00 +T 76 05 F1 +R 00 00 06 00 +T 77 05 +R 00 00 06 00 +T 77 05 CD 0A 04 CD 8A 05 7B A7 28 0F +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 81 05 +R 00 00 06 00 +T 81 05 21 B5 0C CD 8A 04 C3 96 05 +R 00 00 06 00 00 03 06 00 00 06 06 00 00 09 06 00 +T 8A 05 +R 00 00 06 00 +T 8A 05 4F 7B 91 5F 79 C9 +R 00 00 06 00 +T 90 05 +R 00 00 06 00 +T 90 05 CD B4 03 C3 33 05 +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 96 05 +R 00 00 06 00 +T 96 05 CD B4 03 C3 2C 03 +R 00 00 06 00 00 03 06 00 00 06 06 00 +T 9C 05 +R 00 00 06 00 +T 9C 05 0E 03 23 E5 CD DD 03 54 5D E1 D5 23 23 23 +R 00 00 06 00 00 07 06 00 +T AA 05 23 23 E5 CD DD 03 54 5D E1 D5 23 23 23 23 +R 00 00 06 00 00 06 06 00 +T B8 05 23 CD DD 03 E5 D1 C1 E1 E5 7D 2F 6F 7C 2F +R 00 00 06 00 00 04 06 00 +T C6 05 67 23 09 4D 44 E1 CD D2 05 C3 2C 03 +R 00 00 06 00 00 09 06 00 00 0C 06 00 +T D2 05 +R 00 00 06 00 +T D2 05 7E 12 23 13 0B 79 B0 C2 D2 05 C9 +R 00 00 06 00 00 0A 06 00 +T DD 05 +R 00 00 06 00 +T DD 05 0E 03 23 E5 CD DD 03 54 5D E1 D5 23 23 23 +R 00 00 06 00 00 07 06 00 +T EB 05 23 23 E5 CD DD 03 54 5D E1 D5 23 23 23 23 +R 00 00 06 00 00 06 06 00 +T F9 05 23 CD E9 03 4F C5 C1 D1 E1 71 +R 00 00 06 00 00 04 06 00 +T 03 06 +R 00 00 06 00 +T 03 06 71 23 7B 95 47 7A 94 B0 C2 03 06 C3 2C 03 +R 00 00 06 00 00 0B 06 00 00 0E 06 00 +T 11 06 +R 00 00 06 00 +T 11 06 C3 00 EA +R 00 00 06 00 +T 14 06 +R 00 00 06 00 +T 14 06 3E 80 D3 6B 3A 3A 07 D3 68 3E 00 D3 69 3E +R 00 00 06 00 00 07 06 00 +T 22 06 03 D3 6B 3E 03 D3 6C C9 +R 00 00 06 00 +T 2A 06 +R 00 00 06 00 +T 2A 06 5D 54 13 77 0B ED B0 C9 +R 00 00 06 00 +T 32 06 +R 00 00 06 00 +T 32 06 3E 0C 32 3A 07 CD 14 06 C9 +R 00 00 06 00 00 05 06 00 00 08 06 00 +T 3B 06 +R 00 00 06 00 +T 3B 06 3E 82 D3 63 C9 +R 00 00 06 00 +T 40 06 +R 00 00 06 00 +T 40 06 E5 +R 00 00 06 00 +T 41 06 +R 00 00 06 00 +T 41 06 CD 67 06 FE 00 28 F9 57 3E 4F D3 62 CD +R 00 00 06 00 00 03 06 00 +T 4E 06 B4 06 +R 00 00 06 00 00 02 06 00 +T 50 06 +R 00 00 06 00 +T 50 06 DB 61 FE 00 20 FA 7A 16 00 21 E7 0C +R 00 00 06 00 00 0C 06 00 +T 5C 06 +R 00 00 06 00 +T 5C 06 BE 28 05 23 14 C2 5C 06 +R 00 00 06 00 00 08 06 00 +T 64 06 +R 00 00 06 00 +T 64 06 7A E1 C9 +R 00 00 06 00 +T 67 06 +R 00 00 06 00 +T 67 06 0E 00 3E 41 D3 62 CD B4 06 DB 61 FE 00 20 +R 00 00 06 00 00 09 06 00 +T 75 06 34 0E 40 3E 42 D3 62 CD B4 06 DB 61 FE 00 +R 00 00 06 00 00 0A 06 00 +T 83 06 20 25 0E 80 3E 44 D3 62 CD B4 06 DB 61 FE +R 00 00 06 00 00 0B 06 00 +T 91 06 00 20 16 0E C0 3E 48 D3 62 CD B4 06 DB 61 +R 00 00 06 00 00 0C 06 00 +T 9F 06 FE 00 20 07 3E 40 D3 62 3E 00 C9 +R 00 00 06 00 +T AA 06 +R 00 00 06 00 +T AA 06 E6 3F B1 4F 3E 00 D3 62 79 C9 +R 00 00 06 00 +T B4 06 +R 00 00 06 00 +T B4 06 +R 00 00 06 00 +T B4 06 00 00 00 00 00 00 00 00 00 C9 +R 00 00 06 00 +T BE 06 +R 00 00 06 00 +T BE 06 E5 F5 C5 01 07 00 09 06 08 3E 40 D3 62 CD +R 00 00 06 00 +T CC 06 B4 06 3E F0 D3 60 3E 80 D3 62 CD B4 06 3E +R 00 00 06 00 00 02 06 00 00 0D 06 00 +T DA 06 40 D3 62 +R 00 00 06 00 +T DD 06 +R 00 00 06 00 +T DD 06 7E CD F8 06 D3 60 3E 00 D3 62 CD B4 06 3E +R 00 00 06 00 00 04 06 00 00 0D 06 00 +T EB 06 40 D3 62 CD B4 06 2B 10 E9 C1 F1 E1 C9 +R 00 00 06 00 00 06 06 00 +T F8 06 +R 00 00 06 00 +T F8 06 C5 E5 21 FF 0C 06 00 4F 09 7E E1 C1 C9 +R 00 00 06 00 00 05 06 00 +T 05 07 +R 00 00 06 00 +T 05 07 F5 C5 01 07 00 09 06 08 3E 40 D3 62 CD +R 00 00 06 00 +T 12 07 B4 06 3E F0 D3 60 3E 80 D3 62 CD B4 06 3E +R 00 00 06 00 00 02 06 00 00 0D 06 00 +T 20 07 40 D3 62 +R 00 00 06 00 +T 23 07 +R 00 00 06 00 +T 23 07 7E D3 60 3E 00 D3 62 CD B4 06 3E 40 D3 62 +R 00 00 06 00 00 0A 06 00 +T 31 07 CD B4 06 2B 10 EC C1 F1 C9 +R 00 00 06 00 00 03 06 00 +T 3A 07 +R 00 00 06 00 +T 3B 07 20 20 20 20 20 20 20 20 20 20 20 20 20 20 +R 00 00 06 00 +T 49 07 20 20 20 20 20 20 20 20 20 20 20 20 20 20 +R 00 00 06 00 +T 57 07 20 20 20 20 20 20 20 20 20 20 20 20 20 20 +R 00 00 06 00 +T 65 07 20 20 20 20 20 20 20 20 20 20 20 20 20 20 +R 00 00 06 00 +T 73 07 20 20 20 20 20 20 20 20 20 20 20 20 20 20 +R 00 00 06 00 +T 81 07 20 20 20 20 20 20 20 20 20 20 00 00 00 00 +R 00 00 06 00 +T 8F 07 00 00 00 00 01 +R 00 00 06 00 +T 94 07 +R 00 00 06 00 +T 94 07 +R 00 00 06 00 +T 94 09 +R 00 00 06 00 +T 94 09 0D 0A FF +R 00 00 06 00 +T 97 09 +R 00 00 06 00 +T 97 09 0D 0A 3E FF +R 00 00 06 00 +T 9B 09 +R 00 00 06 00 +T 9B 09 0D 0A 20 20 20 20 20 20 20 20 20 4E 4E 20 +R 00 00 06 00 +T A9 09 20 20 20 20 20 4E 4E 20 20 20 20 20 20 38 +R 00 00 06 00 +T B7 09 38 38 38 20 20 20 20 20 20 56 56 20 20 20 +R 00 00 06 00 +T C5 09 20 20 20 56 56 20 20 20 20 45 45 45 45 45 +R 00 00 06 00 +T D3 09 45 45 45 45 45 20 20 20 4D 4D 20 20 20 20 +R 00 00 06 00 +T E1 09 20 20 20 20 20 20 4D 4D 0D 0A 20 20 20 20 +R 00 00 06 00 +T EF 09 20 20 20 20 4E 4E 4E 4E 20 20 20 20 4E 4E +R 00 00 06 00 +T FD 09 20 20 20 20 38 38 20 20 20 20 38 38 20 20 +R 00 00 06 00 +T 0B 0A 20 20 56 56 20 20 20 20 20 20 56 56 20 20 +R 00 00 06 00 +T 19 0A 20 20 45 45 20 20 20 20 20 20 20 20 20 20 +R 00 00 06 00 +T 27 0A 20 4D 4D 4D 4D 20 20 20 20 20 20 4D 4D 4D +R 00 00 06 00 +T 35 0A 4D 0D 0A 20 20 20 20 20 20 20 4E 4E 20 20 +R 00 00 06 00 +T 43 0A 4E 4E 20 20 4E 4E 20 20 20 20 38 38 20 20 +R 00 00 06 00 +T 51 0A 20 20 38 38 20 20 20 20 56 56 20 20 20 20 +R 00 00 06 00 +T 5F 0A 20 20 56 56 20 20 20 20 45 45 20 20 20 20 +R 00 00 06 00 +T 6D 0A 20 20 20 20 20 20 20 4D 4D 20 20 4D 4D 20 +R 00 00 06 00 +T 7B 0A 20 4D 4D 20 20 4D 4D 0D 0A 20 20 20 20 20 +R 00 00 06 00 +T 89 0A 20 4E 4E 20 20 20 20 4E 4E 4E 4E 20 20 20 +R 00 00 06 00 +T 97 0A 20 38 38 20 20 20 20 38 38 20 20 20 20 56 +R 00 00 06 00 +T A5 0A 56 20 20 20 20 20 20 56 56 20 20 20 20 45 +R 00 00 06 00 +T B3 0A 45 20 20 20 20 20 20 20 20 20 20 20 4D 4D +R 00 00 06 00 +T C1 0A 20 20 20 20 4D 4D 20 20 20 20 4D 4D 0D 0A +R 00 00 06 00 +T CF 0A 20 20 20 20 20 4E 4E 20 20 20 20 20 20 4E +R 00 00 06 00 +T DD 0A 4E 20 20 20 20 20 20 38 38 38 38 20 20 20 +R 00 00 06 00 +T EB 0A 20 20 20 56 56 20 20 20 20 20 20 56 56 20 +R 00 00 06 00 +T F9 0A 20 20 20 45 45 45 45 45 45 45 20 20 20 20 +R 00 00 06 00 +T 07 0B 20 20 4D 4D 20 20 20 20 20 20 20 20 20 20 +R 00 00 06 00 +T 15 0B 4D 4D 0D 0A 20 20 20 20 4E 4E 20 20 20 20 +R 00 00 06 00 +T 23 0B 20 20 4E 4E 20 20 20 20 38 38 20 20 20 20 +R 00 00 06 00 +T 31 0B 38 38 20 20 20 20 20 56 56 20 20 20 20 56 +R 00 00 06 00 +T 3F 0B 56 20 20 20 20 20 45 45 20 20 20 20 20 20 +R 00 00 06 00 +T 4D 0B 20 20 20 20 20 4D 4D 20 20 20 20 20 20 20 +R 00 00 06 00 +T 5B 0B 20 20 20 4D 4D 0D 0A 20 20 20 4E 4E 20 20 +R 00 00 06 00 +T 69 0B 20 20 20 20 4E 4E 20 20 20 20 38 38 20 20 +R 00 00 06 00 +T 77 0B 20 20 38 38 20 20 20 20 20 20 56 56 20 20 +R 00 00 06 00 +T 85 0B 56 56 20 20 20 20 20 20 45 45 20 20 20 20 +R 00 00 06 00 +T 93 0B 20 20 20 20 20 20 20 4D 4D 20 20 20 20 20 +R 00 00 06 00 +T A1 0B 20 20 20 20 20 4D 4D 0D 0A 20 20 4E 4E 20 +R 00 00 06 00 +T AF 0B 20 20 20 20 20 4E 4E 20 20 20 20 38 38 20 +R 00 00 06 00 +T BD 0B 20 20 20 38 38 20 20 20 20 20 20 20 20 56 +R 00 00 06 00 +T CB 0B 56 56 20 20 20 20 20 20 20 45 45 20 20 20 +R 00 00 06 00 +T D9 0B 20 20 20 20 20 20 20 20 4D 4D 20 20 20 20 +R 00 00 06 00 +T E7 0B 20 20 20 20 20 20 4D 4D 0D 0A 20 4E 4E 20 +R 00 00 06 00 +T F5 0B 20 20 20 20 20 4E 4E 20 20 20 20 20 20 38 +R 00 00 06 00 +T 03 0C 38 38 38 20 20 20 20 20 20 20 20 20 20 20 +R 00 00 06 00 +T 11 0C 56 20 20 20 20 20 20 20 20 45 45 45 45 45 +R 00 00 06 00 +T 1F 0C 45 45 45 45 45 20 20 20 4D 4D 20 20 20 20 +R 00 00 06 00 +T 2D 0C 20 20 20 20 20 20 4D 4D 20 20 20 20 53 20 +R 00 00 06 00 +T 3B 0C 42 20 43 0D 0A 0D 0A 20 2A 2A 2A 2A 2A 2A +R 00 00 06 00 +T 49 0C 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A +R 00 00 06 00 +T 57 0C 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A +R 00 00 06 00 +T 65 0C 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A +R 00 00 06 00 +T 73 0C 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A +R 00 00 06 00 +T 81 0C 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A +R 00 00 06 00 +T 8F 0C 0D 0A 4D 4F 4E 49 54 4F 52 20 52 45 41 44 +R 00 00 06 00 +T 9D 0C 59 20 0D 0A FF +R 00 00 06 00 +T A2 0C +R 00 00 06 00 +T A2 0C 0D 0A 55 4E 4B 4E 4F 57 4E 20 43 4F 4D 4D +R 00 00 06 00 +T B0 0C 41 4E 44 2E FF +R 00 00 06 00 +T B5 0C +R 00 00 06 00 +T B5 0C 0D 0A 43 48 45 43 4B 53 55 4D 20 45 52 52 +R 00 00 06 00 +T C3 0C 4F 52 2E FF +R 00 00 06 00 +T C7 0C +R 00 00 06 00 +T C7 0C 84 EE BB 80 BB EE CB 84 +R 00 00 06 00 +T CF 0C +R 00 00 06 00 +T CF 0C 00 00 00 00 8C BD BD FE +R 00 00 06 00 +T D7 0C +R 00 00 06 00 +T D7 0C 00 00 80 80 94 8C 9D EE +R 00 00 06 00 +T DF 0C +R 00 00 06 00 +T DF 0C 80 80 80 80 80 CB CF D7 +R 00 00 06 00 +T E7 0C +R 00 00 06 00 +T E7 0C 41 02 42 82 04 44 84 08 48 88 10 50 90 20 +R 00 00 06 00 +T F5 0C 60 A0 01 81 C1 C2 C4 C8 D0 E0 +R 00 00 06 00 +T FF 0C +R 00 00 06 00 +T FF 0C FB B0 ED F5 B6 D7 DF F0 FF F7 FE 9F CB BD +R 00 00 06 00 +T 0D 0D CF CE 80 84 00 EE 9D +R 00 00 06 00 +T 14 0D +R 00 00 06 00 diff --git a/doug/src/dbgmon.s b/doug/src/dbgmon.s new file mode 100755 index 00000000..cc6fb426 --- /dev/null +++ b/doug/src/dbgmon.s @@ -0,0 +1,1764 @@ + .title dbgmon.s derived from dbgmon.asm + .sbttl Ported by Douglas Goodall + + .module dbgmon + .optsdcc -mz80 + +;-------------------------------------------------------- +; Public variables in this module +;-------------------------------------------------------- + .globl _dbgmon +;-------------------------------------------------------- +; special function registers +;-------------------------------------------------------- +;-------------------------------------------------------- +; ram data +;-------------------------------------------------------- + .area _DATA +;-------------------------------------------------------- +; overlayable items in ram +;-------------------------------------------------------- + .area _OVERLAY +;-------------------------------------------------------- +; external initialized ram data +;-------------------------------------------------------- +;-------------------------------------------------------- +; global & static initialisations +;-------------------------------------------------------- + .area _HOME + .area _GSINIT + .area _GSFINAL + .area _GSINIT +;-------------------------------------------------------- +; Home +;-------------------------------------------------------- + .area _HOME + .area _HOME +;-------------------------------------------------------- +; code +;-------------------------------------------------------- + .area _DBGMON +_dbgmon_start:: +_dbgmon: + + +;___ROM_MONITOR_PROGRAM_____________________________________________________________________________________________________________ +; +; ORIGINAL CODE BY: ANDREW LYNCH (LYNCHAJ@YAHOO COM) 13 FEB 2007 +; +; MODIFIED BY : DAN WERNER 03 09.2009 +; +;__REFERENCES________________________________________________________________________________________________________________________ +; THOMAS SCHERRER BASIC HAR.DWARE TEST ASSEMBLER SOURCES FROM THE Z80 INFO PAGE +; INCLUDING ORIGINAL SCHEMATIC CONCEPT +; HTTP://Z80 INFO/Z80SOURC.TXT +; CODE SAMPLES FROM BRUCE JONES PUBLIC DOMAIN ROM MONITOR FOR THE SBC-200C +; HTTP://WWW RETROTECHNOLOGY.COM/HERBS_STUFF/SD_BRUCE_CODE.ZIP +; INSPIRATION FROM JOEL OWENS "Z-80 SPACE-TIME PRODUCTIONS SINGLE BOARD COMPUTER" +; HTTP://WWW JOELOWENS.ORG/Z80/Z80INDEX.HTML +; GREAT HELP AND TECHNICAL ADVICE FROM ALLISON AT ALPACA_DESIGNERS +; HTTP://GROUPS YAHOO.COM/GROUP/ALPACA_DESIGNERS +; INTEL SDK-85 ROM DEBUG MONITOR +; +;__HARDWARE_INTERFACES________________________________________________________________________________________________________________ +; +; PIO 82C55 I/O IS DECODED TO PORT 60-67 +; +PORTA = 0x60 +PORTB = 0x61 +PORTC = 0x62 +PIOCONT = 0x63 +; +; UART 16C450 SERIAL IS DECODED TO 68-6F +; +UART0 = 0x68 ; DATA IN/OUT +UART1 = 0x69 ; CHECK RX +UART2 = 0x6A ; INTERRUPTS +UART3 = 0x6B ; LINE CONTROL +UART4 = 0x6C ; MODEM CONTROL +UART5 = 0x6D ; LINE STATUS +UART6 = 0x6E ; MODEM STATUS +UART7 = 0x6F ; SCRATCH REG. +; +; MEMORY PAGE CONFIGURATION LATCH IS DECODED TO 78 +; +MPCL = 0x78 ; CONTROL PORT, SHOULD ONLY BE CHANGED WHILE +; IN UPPER MEMORY PAGE 08000h-$FFFF OR LIKELY +MPCL_RAM = 0x78 ; BASE IO ADDRESS OF RAM MEMORY PAGER CONFIGURATION LATCH +MPCL_ROM = 0x7C ; BASE IO ADDRESS OF ROM MEMORY PAGER CONFIGURATION LATCH +; LOSS OF CPU MEMORY CONTEXT +; +; MEMORY PAGE CONFIGURATION LATCH CONTROL PORT ( IO_Y3 ) INFORMATION +; +; 7 6 5 4 3 2 1 0 ONLY APPLICABLE TO THE LOWER MEMORY PAGE 00000h-$7FFF +; ^ ^ ^ ^ ^ ^ ^ ^ +; : : : : : : : :--0 = A15 RAM/ROM ADDRESS LINE DEFAULT IS 0 +; : : : : : : :----0 = A16 RAM/ROM ADDRESS LINE DEFAULT IS 0 +; : : : : : :------0 = A17 RAM/ROM ADDRESS LINE DEFAULT IS 0 +; : : : : :--------0 = A18 RAM/ROM ADDRESS LINE DEFAULT IS 0 +; : : : :-----------0 = A19 ROM ONLY ADDRESS LINE DEFAULT IS 0 +; : : :-------------0 = +; : :---------------0 = +; :-----------------0 = ROM SELECT (0=ROM, 1=RAM) DEFAULT IS 0 +; +; +;IDE REGISTER IO PORT ; FUNCTION +IDELO = 0x020 ; DATA PORT (LOW BYTE) +IDEERR = 0x021 ; READ: ERROR REGISTER; WRITE: PRECOMP +IDESECTC = 0x022 ; SECTOR COUNT +IDESECTN = 0x023 ; SECTOR NUMBER +IDECYLLO = 0x024 ; CYLINDER LOW +IDECYLHI = 0x025 ; CYLINDER HIGH +IDEHEAD = 0x026 ; DRIVE/HEAD +IDESTTS = 0x027 ; READ: STATUS; WRITE: COMMAND +IDEHI = 0x028 ; DATA PORT (HIGH BYTE) +IDECTRL = 0x02E ; READ: ALTERNATIVE STATUS; WRITE; DEVICE CONTROL +IDEADDR = 0x02F ; DRIVE ADDRESS (READ ONLY) + +; +; +;__CONSTANTS_________________________________________________________________________________________________________________________ +; +RAMTOP = 0x0FFFF ; HIGHEST ADDRESSABLE MEMORY LOCATION +STACKSTART = 0x0CFFF ; START OF STACK +RAMBOTTOM = 0x08000 ; START OF FIXED UPPER 32K PAGE OF 512KB X 8 RAM 8000H-FFFFH +MONSTARTCOLD = 0x08000 ; COLD START MONITOR IN HIGH RAM +ENDT = 0x0FF ; MARK END OF TEXT +CR = 0x0D ; ASCII CARRIAGE RETURN CHARACTER +LF = 0x0A ; ASCII LINE FEED CHARACTER +ESC = 0x1B ; ASCII ESCAPE CHARACTER +BS = 0x08 ; ASCII BACKSPACE CHARACTER + +ASCIIA = 0x41 +ASCIIB = 0x42 +ASCIIC = 0x43 +ASCIID = 0x44 +ASCIIE = 0x45 +ASCIIF = 0x46 +ASCIIG = 0x47 +ASCIIH = 0x48 +ASCIII = 0x49 +ASCIIJ = 0x4A +ASCIIK = 0x4B +ASCIIL = 0x4C +ASCIIM = 0x4D +ASCIIN = 0x4E +ASCIIO = 0x4F +ASCIIP = 0x50 +ASCIIQ = 0x51 +ASCIIR = 0x52 +ASCIIS = 0x53 +ASCIIT = 0x54 +ASCIIU = 0x55 +ASCIIV = 0x56 +ASCIIW = 0x57 +ASCIIX = 0x58 +ASCIIY = 0x59 +ASCIIZ = 0x5A + +; +; +; +;__MAIN_PROGRAM_____________________________________________________________________________________________________________________ +; +; ORG 00100h ; FOR DEBUG IN CP/M (AS .COM) + +;dwg; .ORG 8000H ; NORMAL OP + + LD SP,#STACKSTART ; SET THE STACK POINTER TO STACKSTART + CALL INITIALIZE ; INITIALIZE SYSTEM + + + +;__FRONT_PANEL_STARTUP___________________________________________________________________________________________________________ +; +; START UP THE SYSTEM WITH THE FRONT PANEL INTERFACE +; +;________________________________________________________________________________________________________________________________ +; + CALL MTERM_INIT ; INIT 8255 FOR MTERM + LD HL,#CPUUP ; SET POINTER TO DATA BUFFER + CALL SEGDISPLAY ; DISPLAY + + + +FRONTPANELLOOP: + CALL KB_GET ; GET KEY FROM KB + + CP #0x10 ; IS PORT READ? + JP Z,DOPORTREAD ; YES, JUMP + CP #0x11 ; IS PORT WRITE? + JP Z,DOPORTWRITE ; YES, JUMP + CP #0x14 ; IS DEPOSIT? + JP Z,DODEPOSIT ; YES, JUMP + CP #0x15 ; IS EXAMINE? + JP Z,DOEXAMINE ; YES, JUMP + CP #0x16 ; IS GO? + JP Z,DOGO ; YES, JUMP + CP #0x17 ; IS BO? + JP Z,DOBOOT ; YES, JUMP + + JR FRONTPANELLOOP ; LOOP +EXIT: + RET + + +;__DOBOOT________________________________________________________________________________________________________________________ +; +; PERFORM BOOT FRONT PANEL ACTION +;________________________________________________________________________________________________________________________________ +; +DOBOOT: + LD A,#0 ; LOAD VALUE TO SWITCH OUT ROM + OUT (MPCL_ROM),A ; SWITCH OUT ROM, BRING IN LOWER 32K RAM PAGE + ; + ; + OUT (MPCL_RAM),A ; + JP 0 ; GO TO CP/M + + +;__DOPORTREAD____________________________________________________________________________________________________________________ +; +; PERFORM PORT READ FRONT PANEL ACTION +;________________________________________________________________________________________________________________________________ +; +DOPORTREAD: + CALL GETPORT ; GET PORT INTO A +PORTREADLOOP: + LD C,A ; STORE PORT IN "C" + SRL A ; ROTATE HIGH NIB TO LOW + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+5),A ; SHOW HIGH NIB IN DISP 5 + LD A,C ; RESTORE PORT VALUE INTO "A" + AND #0x0F ; CLEAR HIGH NIB, LEAVING LOW + LD (DISPLAYBUF+4),A ; SHOW LOW NIB IN DISP 4 + IN A,(C) ; GET PORT VALUE FROM PORT IN "C" + LD C,A ; STORE VALUE IN "C" + SRL A ; ROTATE HIGH NIB TO LOW + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+1),A ; SHOW HIGH NIB IN DISP 1 + LD A,C ; RESTORE VALUE TO "A" + AND #0x0F ; CLEAR HIGH NIB, LEAVING LOW + LD (DISPLAYBUF),A ; DISPLAY LOW NIB IN DISP 0 + LD A,#0x10 ; CLEAR OTHER DISPLAYS + LD (DISPLAYBUF+2),A ; + LD (DISPLAYBUF+3),A ; + LD A,#0x13 ; "P" + LD (DISPLAYBUF+7),A ; STORE IN DISP 7 + LD A,#0x14 ; "O" + LD (DISPLAYBUF+6),A ; STORE IN DISP 6 + LD HL,#DISPLAYBUF ; SET POINTER TO DISPLAY BUFFER + CALL HEXDISPLAY ; DISPLAY BUFFER CONTENTS +PORTREADGETKEY: + CALL KB_GET ; GET KEY FROM KB + CP #0x12 ; [CL] PRESSED, EXIT + JP Z,PORTREADEXIT ; + CP #0x10 ; [PR] PRESSED, PROMPT FOR NEW PORT + JR Z,DOPORTREAD ; + JR PORTREADGETKEY ; NO VALID KEY, LOOP +PORTREADEXIT: + LD HL,#CPUUP ; SET POINTER TO DATA BUFFER + CALL SEGDISPLAY ; DISPLAY + JP FRONTPANELLOOP ; + +;__DOPORTWRITE____________________________________________________________________________________________________________________ +; +; PERFORM PORT WRITE FRONT PANEL ACTION +;________________________________________________________________________________________________________________________________ +; +DOPORTWRITE: + CALL GETPORT ; GET PORT INTO A +PORTWRITELOOP: + LD C,A ; STORE PORT IN "C" + SRL A ; ROTATE HIGH NIB INTO LOW + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+5),A ; DISPLAY HIGH NIB IN DISPLAY 5 + LD A,C ; RESTORE PORT VALUE INTO "A" + AND #0x0F ; CLEAR OUT HIGH NIB + LD (DISPLAYBUF+4),A ; DISPLAY LOW NIB IN DISPLAY 4 + LD A,#0x10 ; CLEAR OUT DISPLAYS 2 AND 3 + LD (DISPLAYBUF+2),A ; + LD (DISPLAYBUF+3),A ; + LD A,#0x13 ; DISPLAY "P" IN DISP 7 + LD (DISPLAYBUF+7),A ; + LD A,#0x14 ; DISPLAY "O" IN DISP 6 + LD (DISPLAYBUF+6),A ; + LD HL,#DISPLAYBUF ; POINT TO DISPLAY BUFFER + CALL GETVALUE ; INPUT A BYTE VALUE, RETURN IN "A" + OUT (C),A ; OUTPUT VALUE TO PORT STORED IN "C" + LD HL,#CPUUP ; SET POINTER TO DATA BUFFER + CALL SEGDISPLAY ; DISPLAY + JP FRONTPANELLOOP ; + + +;__DOGO__________________________________________________________________________________________________________________________ +; +; PERFORM GO FRONT PANEL ACTION +;________________________________________________________________________________________________________________________________ +; +DOGO: + CALL GETADDR ; GET ADDRESS INTO HL + JP (HL) ; GO THERE! + + + +;__DODEPOSIT________________________________________________________________________________________________________________________ +; +; PERFORM DEPOSIT FRONT PANEL ACTION +;________________________________________________________________________________________________________________________________ +; +DODEPOSIT: + CALL GETADDR ; GET ADDRESS INTO HL + PUSH HL +DEPOSITLOOP: + LD A,H ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+7),A ; + LD A,H ; + AND #0x0F ; + LD (DISPLAYBUF+6),A ; + LD A,L ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+5),A ; + LD A,L ; + AND #0x0F ; + LD (DISPLAYBUF+4),A ; + LD A,#0x10 ; + LD (DISPLAYBUF+3),A ; + LD HL,#DISPLAYBUF ; + CALL GETVALUE ; + POP HL ; + LD (HL),A ; +DEPOSITGETKEY: + CALL KB_GET ; GET KEY FROM KB + CP #0x12 ; [CL] PRESSED, EXIT + JP Z,DEPOSITEXIT ; + CP #0x13 ; [EN] PRESSED, INC ADDRESS AND LOOP + JR Z,DEPOSITFW ; + CP #0x14 ; [DE] PRESSED, PROMPT FOR NEW ADDRESS + JR Z,DODEPOSIT ; + JR DEPOSITGETKEY ; NO VALID KEY, LOOP +DEPOSITFW: + INC HL ; + PUSH HL ; STORE HL + JR DEPOSITLOOP ; +DEPOSITEXIT: + LD HL,#CPUUP ; SET POINTER TO DATA BUFFER + CALL SEGDISPLAY ; DISPLAY + JP FRONTPANELLOOP ; + + + + +;__DOEXAMINE________________________________________________________________________________________________________________________ +; +; PERFORM EXAMINE FRONT PANEL ACTION +;________________________________________________________________________________________________________________________________ +; +DOEXAMINE: + CALL GETADDR ; GET ADDRESS INTO HL + PUSH HL ; STORE HL +EXAMINELOOP: + LD A,H ; MOVE HIGH BYTE IN "A" + SRL A ; SHOW HIGH NIBBLE IN DISP 7 + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+7),A ; + LD A,H ; RESTORE HIGH BYTE + AND #0x0F ; CLEAR HIGH NIBBLE + LD (DISPLAYBUF+6),A ; DISPLAY LOW NIBBLE IN DISP 6 + LD A,L ; PUT LOW BYTE IN "A" + SRL A ; SHOW HIGH NIBBLE IN DISP 5 + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+5),A ; + LD A,L ; RESTORE LOW BYTE IN "A" + AND #0x0F ; CLEAR OUT HIGH NIBBLE + LD (DISPLAYBUF+4),A ; DISPLAY LOW NIBBLE IN DISP 4 + LD A,#0x10 ; CLEAR OUT DISP 3 + LD (DISPLAYBUF+3),A ; + LD A,(HL) ; GET VALUE FROM ADDRESS IN HL + SRL A ; DISPLAY HIGH NIB IN DISPLAY 1 + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+1),A ; + LD A,(HL) ; GET VALUE FROM ADDRESS IN HL + AND #0x0F ; CLEAR OUT HIGH NIBBLE + LD (DISPLAYBUF),A ; DISPLAY LOW NIBBLE IN DISPLAY 0 + LD HL,#DISPLAYBUF ; POINT TO DISPLAY BUFFER + CALL HEXDISPLAY ; DISPLAY BUFFER ON DISPLAYS + POP HL ; RESTORE HL +EXAMINEGETKEY: + CALL KB_GET ; GET KEY FROM KB + CP #0x12 ; [CL] PRESSED, EXIT + JP Z,EXAMINEEXIT ; + CP #0x13 ; [EN] PRESSED, INC ADDRESS AND LOOP + JR Z,EXAMINEFW ; + CP #0x15 ; [DE] PRESSED, PROMPT FOR NEW ADDRESS + JR Z,DOEXAMINE ; + JR EXAMINEGETKEY ; NO VALID KEY, LOOP +EXAMINEFW: + INC HL ; HL++ + PUSH HL ; STORE HL + JR EXAMINELOOP ; +EXAMINEEXIT: + LD HL,#CPUUP ; SET POINTER TO DATA BUFFER + CALL SEGDISPLAY ; DISPLAY + JP FRONTPANELLOOP ; + + +;__GETADDR_______________________________________________________________________________________________________________________ +; +; GET ADDRESS FROM FRONT PANEL +;________________________________________________________________________________________________________________________________ +; +GETADDR: + PUSH BC ; STORE BC + JR GETADDRCLEAR ; +GETADDR1: + LD HL,#ADDR ; DISPLAY PROMPT + CALL SEGDISPLAY ; +GETADDRLOOP: + CALL KB_GET ; + CP #0x10 ; + JP M,GETADDRNUM ; NUMBER PRESSED, STORE IT + CP #0x13 ; EN PRESSED, DONE + JR Z,GETADDRDONE ; + CP #0x12 ; CLEAR PRESSED, CLEAR + JR Z,GETADDRCLEAR ; + JR GETADDRLOOP ; INVALID KEY, LOOP +GETADDRDONE: + LD HL,#0 ; HL=0 + LD A,(DISPLAYBUF+1) ; GET DIGIT IN DISPLAY 1 + SLA A ; ROTATE IT TO HIGH NIBBLE + SLA A ; + SLA A ; + SLA A ; + LD C,A ; STORE IT IN "C" + LD A,(DISPLAYBUF) ; GET DIGIT IN DISPLAY 0 + AND #0x0F ; CLEAR HIGH NIBBLE + OR C ; ADD IN NIBBLE STORED IN C + LD L,A ; STORE IT IN LOW BYTE OF ADDRESS POINTER + LD A,(DISPLAYBUF+3) ; GET DIGIT IN DISPLAY 3 + SLA A ; ROTATE IT TO HIGH NIBBLE + SLA A ; + SLA A ; + SLA A ; + LD C,A ; STORE IT IN "C" + LD A,(DISPLAYBUF+2) ; GET DIGIT IN DISPLAY 2 + AND #0x0F ; CLEAR HIGH NIBBLE + OR C ; ADD IN NIBBLE STORED IN "C" + LD H,A ; STORE BYTE IN HIGH BYTE OF ADDRESS POINTER + LD A,#0x10 ; CLEAR OUT DISPLAYS 0,1,2 & 3 + LD (DISPLAYBUF),A ; + LD (DISPLAYBUF+1),A ; + LD (DISPLAYBUF+2),A ; + LD (DISPLAYBUF+3),A ; + POP BC ; RESTORE BC + RET +GETADDRNUM: + LD C,A ; + LD A,(DISPLAYBUF+2) ; SHIFT BYTES IN DISPLAY BUF TO THE LEFT + LD (DISPLAYBUF+3),A ; + LD A,(DISPLAYBUF+1) ; + LD (DISPLAYBUF+2),A ; + LD A,(DISPLAYBUF) ; + LD (DISPLAYBUF+1),A ; + LD A,C ; DISPLAY KEYSTROKE IN RIGHT MOST DISPLAY (0) + LD (DISPLAYBUF+0),A ; + JR GETADDRDISP ; +GETADDRCLEAR: + LD A,#0x12 ; CLEAR OUT DISPLAYS 0,1,2 & 3 + LD (DISPLAYBUF),A ; + LD (DISPLAYBUF+1),A ; + LD (DISPLAYBUF+2),A ; + LD (DISPLAYBUF+3),A ; +GETADDRDISP: + LD A,(DISPLAYBUF) ; ENCODE DIGITS IN DISPLAY BUFFER TO DISPLAY + CALL DECODEDISPLAY ; + LD (ADDR),A ; + LD A,(DISPLAYBUF+1) ; + CALL DECODEDISPLAY ; + LD (ADDR+1),A ; + LD A,(DISPLAYBUF+2) ; + CALL DECODEDISPLAY ; + LD (ADDR+2),A ; + LD A,(DISPLAYBUF+3) ; + CALL DECODEDISPLAY ; + LD (ADDR+3),A ; + JP GETADDR1 ; + + + +;__DSPSECTOR_______________________________________________________________________________________________________________________ +; +; DISPLAY SECTOR IN HL ON FRONT PANEL +;________________________________________________________________________________________________________________________________ +; +DSPSECTOR: + PUSH BC ; STORE BC + PUSH HL ; STORE HL + LD A,H ; DISPLAY HIGH BYTE, HIGH NIBBLE + SRL A ; + SRL A ; + SRL A ; + SRL A ; + AND #0x0F ; + CALL DECODEDISPLAY ; + LD (SEC+3),A ; + LD A,H ; DISPLAY HIGH BYTE, LOW NIBBLE + AND #0x0F ; + CALL DECODEDISPLAY ; + LD (SEC+2),A ; + LD A,L ; DISPLAY LOW BYTE, HIGH NIBBLE + AND #0x0F0 ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + AND #0x0F ; + CALL DECODEDISPLAY ; + LD (SEC+1),A ; DISPLAY LOW BYTE, LOW NIBBLE + LD A,L ; + AND #0x0F ; + CALL DECODEDISPLAY ; + LD (SEC),A ; + LD HL,#SEC ; DISPLAY PROMPT + CALL SEGDISPLAY ; + POP HL ; RESTORE HL + POP BC ; RESTORE BC + RET + + + +;__GETPORT_______________________________________________________________________________________________________________________ +; +; GET PORT FROM FRONT PANEL +;________________________________________________________________________________________________________________________________ +; +GETPORT: + PUSH BC ; STORE BC + JR GETPORTCLEAR ; +GETPORT1: + LD HL,#PORT ; DISPLAY PROMPT + CALL SEGDISPLAY ; +GETPORTLOOP: + CALL KB_GET ; + CP #0x10 ; + JP M,GETPORTNUM ; NUMBER PRESSED, STORE IT + CP #0x13 ; EN PRESSED, DONE + JR Z,GETPORTDONE ; + CP #0x12 ; CLEAR PRESSED, CLEAR + JR Z,GETPORTCLEAR ; + JR GETPORTLOOP ; INVALID KEY, LOOP +GETPORTDONE: + LD A,(DISPLAYBUF+1) ; + SLA A ; + SLA A ; + SLA A ; + SLA A ; + LD C,A ; + LD A,(DISPLAYBUF) ; + AND #0x0F ; + OR C ; + LD C,A ; + LD A,#0x10 ; + LD (DISPLAYBUF),A ; + LD (DISPLAYBUF+1),A ; + LD A,C ; + POP BC ; RESTORE BC + RET +GETPORTNUM: + LD C,A ; + LD A,(DISPLAYBUF) ; + LD (DISPLAYBUF+1),A ; + LD A,C ; + LD (DISPLAYBUF+0),A ; + JR GETPORTDISP ; +GETPORTCLEAR: + LD A,#0x12 ; + LD (DISPLAYBUF),A ; + LD (DISPLAYBUF+1),A ; +GETPORTDISP: + LD A,(DISPLAYBUF) ; + CALL DECODEDISPLAY ; + LD (PORT),A ; + LD A,(DISPLAYBUF+1) ; + CALL DECODEDISPLAY ; + LD (PORT+1),A ; + JP GETPORT1 ; + + +;__GETVALUE______________________________________________________________________________________________________________________ +; +; GET VALUE FROM FRONT PANEL +;________________________________________________________________________________________________________________________________ +; +GETVALUE: + PUSH BC ; STORE BC + JR GETVALUECLEAR ; +GETVALUE1: + CALL HEXDISPLAY ; + +GETVALUELOOP: + CALL KB_GET ; + CP #0x10 ; + JP M,GETVALUENUM ; NUMBER PRESSED, STORE IT + CP #0x13 ; EN PRESSED, DONE + JR Z,GETVALUEDONE ; + CP #0x12 ; CLEAR PRESSED, CLEAR + JR Z,GETVALUECLEAR ; + JR GETVALUELOOP ; INVALID KEY, LOOP +GETVALUEDONE: + LD A,(DISPLAYBUF+1) ; + SLA A ; + SLA A ; + SLA A ; + SLA A ; + LD C,A ; + LD A,(DISPLAYBUF) ; + AND #0x0F ; + OR C ; + LD C,A ; + LD A,#0x10 ; + LD (DISPLAYBUF),A ; + LD (DISPLAYBUF+1),A ; + LD A,C ; + POP BC ; RESTORE BC + RET +GETVALUENUM: + LD C,A ; + LD A,(DISPLAYBUF) ; + LD (DISPLAYBUF+1),A ; + LD A,C ; + LD (DISPLAYBUF+0),A ; + JR GETVALUE1 ; +GETVALUECLEAR: + LD A,#0x12 ; + LD (DISPLAYBUF),A ; + LD (DISPLAYBUF+1),A ; + JP GETVALUE1 ; + + +;__MONSTARTWARM___________________________________________________________________________________________________________________ +; +; SERIAL MONITOR STARTUP +;________________________________________________________________________________________________________________________________ +; + +MONSTARTWARM: ; CALL HERE FOR SERIAL MONITOR WARM START + LD SP,#STACKSTART ; SET THE STACK POINTER TO STACKSTART + CALL INITIALIZE ; INITIALIZE SYSTEM + + XOR A ;ZERO OUT ACCUMULATOR (ADDED) + PUSH HL ;PROTECT HL FROM OVERWRITE + LD HL,#TXT_READY ;POINT AT TEXT + CALL MSG ;SHOW WE'RE HERE + POP HL ;PROTECT HL FROM OVERWRITE + +; +;__SERIAL_MONITOR_COMMANDS_________________________________________________________________________________________________________ +; +; B XX BOOT CPM FROM DRIVE XX +; D XXXXH YYYYH DUMP MEMORY FROM XXXX TO YYYY +; F XXXXH YYYYH ZZH FILL MEMORY FROM XXXX TO YYYY WITH ZZ +; H LOAD INTEL HEX FORMAT DATA +; I INPUT FROM PORT AND SHOW HEX DATA +; K ECHO KEYBOARD INPUT +; M XXXXH YYYYH ZZZZH MOVE MEMORY BLOCK XXXX TO YYYY TO ZZZZ +; O OUTPUT TO PORT HEX DATA +; P XXXXH YYH PROGRAM RAM FROM XXXXH WITH VALUE IN YYH, WILL PROMPT FOR NEXT LINES FOLLOWING UNTIL CR +; R RUN A PROGRAM FROM CURRENT LOCATION + + + +;__COMMAND_PARSE_________________________________________________________________________________________________________________ +; +; PROMPT USER FOR COMMANDS, THEN PARSE THEM +;________________________________________________________________________________________________________________________________ +; + +SERIALCMDLOOP: + CALL CRLFA ; CR,LF,> + LD HL,#KEYBUF ; SET POINTER TO KEYBUF AREA + CALL GETLN ; GET A LINE OF INPUT FROM THE USER + LD HL,#KEYBUF ; RESET POINTER TO START OF KEYBUF + LD A,(HL) ; LOAD FIRST CHAR INTO A (THIS SHOULD BE THE COMMAND) + INC HL ; INC POINTER + + CP #ASCIIB ; IS IT "B" (Y/N) + JP Z,DOBOOT ; IF YES DO BOOT + CP #ASCIIR ; IS IT "R" (Y/N) + JP Z,RUN ; IF YES GO RUN ROUTINE + CP #ASCIIP ; IS IT "P" (Y/N) + JP Z,PROGRM ; IF YES GO PROGRAM ROUTINE + CP #ASCIIO ; IS IT AN "O" (Y/N) + JP Z,POUT ; PORT OUTPUT + CP #ASCIIH ; IS IT A "H" (Y/N) + JP Z,HXLOAD ; INTEL HEX FORMAT LOAD DATA + CP #ASCIII ; IS IT AN "I" (Y/N) + JP Z,PIN ; PORT INPUT + CP #ASCIID ; IS IT A "D" (Y/N) + JP Z,DUMP ; DUMP MEMORY + CP #ASCIIK + JP Z,KLOP ; LOOP ON KEYBOARD + CP #ASCIIM ; IS IT A "M" (Y/N) + JP Z,MOVE ; MOVE MEMORY COMMAND + CP #ASCIIF ; IS IT A "F" (Y/N) + JP Z,FILL ; FILL MEMORY COMMAND + LD HL,#TXT_COMMAND ; POINT AT ERROR TEXT + CALL MSG ; PRINT COMMAND LABEL + + JR SERIALCMDLOOP + + + + + +;__KLOP__________________________________________________________________________________________________________________________ +; +; READ FROM THE SERIAL PORT AND ECHO, MONITOR COMMAND "K" +;________________________________________________________________________________________________________________________________ +; +KLOP: + CALL KIN ; GET A KEY + CALL COUT ; OUTPUT KEY TO SCREEN + CP #ESC ; IS ? + JR NZ,KLOP ; NO, LOOP + JP SERIALCMDLOOP ; + +;__GETLN_________________________________________________________________________________________________________________________ +; +; READ A LINE(80) OF TEXT FROM THE SERIAL PORT, HANDLE , TERM ON +; EXIT IF TOO MANY CHARS STORE RESULT IN HL. CHAR COUNT IN C. +;________________________________________________________________________________________________________________________________ +; +GETLN: + LD C,#0 ; ZERO CHAR COUNTER + PUSH DE ; STORE DE +GETLNLOP: + CALL KIN ; GET A KEY + CALL COUT ; OUTPUT KEY TO SCREEN + CP #CR ; IS ? + JR Z,GETLNDONE ; YES, EXIT + CP #BS ; IS ? + JR NZ,GETLNSTORE ; NO, STORE CHAR + LD A,C ; A=C + CP #0 ; + JR Z,GETLNLOP ; NOTHING TO BACKSPACE, IGNORE & GET NEXT KEY + DEC HL ; PERFORM BACKSPACE + DEC C ; LOWER CHAR COUNTER + LD A,#0 ; + LD (HL),A ; STORE NULL IN BUFFER + LD A,#0x20 ; BLANK OUT CHAR ON TERM + CALL COUT ; + LD A,#BS ; + CALL COUT ; + JR GETLNLOP ; GET NEXT KEY +GETLNSTORE: + LD (HL),A ; STORE CHAR IN BUFFER + INC HL ; INC POINTER + INC C ; INC CHAR COUNTER + LD A,C ; A=C + CP #0x4D ; OUT OF BUFFER SPACE? + JR NZ,GETLNLOP ; NOPE, GET NEXT CHAR +GETLNDONE: + LD (HL),#0 ; STORE NULL IN BUFFER + POP DE ; RESTORE DE + RET ; + + +;__KIN___________________________________________________________________________________________________________________________ +; +; READ FROM THE SERIAL PORT AND ECHO & CONVERT INPUT TO UCASE +;________________________________________________________________________________________________________________________________ +; +KIN: + IN A,(UART5) ; READ LINE STATUS REGISTER + BIT 0,A ; TEST IF DATA IN RECEIVE BUFFER + JP Z,KIN ; LOOP UNTIL DATA IS READY + IN A,(UART0) ; THEN READ THE CHAR FROM THE UART + AND #0x7F ; STRIP HI BIT + CP #ASCIIA ; KEEP NUMBERS, CONTROLS + RET C ; AND UPPER CASE + CP #0x7B ; SEE IF NOT LOWER CASE + RET NC ; + AND #0x5F ; MAKE UPPER CASE + RET + + +;__COUT__________________________________________________________________________________________________________________________ +; +; WRITE THE VALUE IN "A" TO THE SERIAL PORT +;________________________________________________________________________________________________________________________________ +; +COUT: + PUSH AF ; STORE AF +TX_BUSYLP: + IN A,(UART5) ; READ LINE STATUS REGISTER + BIT 5,A ; TEST IF UART IS READY TO SEND + JP Z,TX_BUSYLP ; IF NOT REPEAT + POP AF ; RESTORE AF + OUT (UART0),A ; THEN WRITE THE CHAR TO UART + RET ; DONE + + +;__CRLF__________________________________________________________________________________________________________________________ +; +; SEND CR & LF TO THE SERIAL PORT +;________________________________________________________________________________________________________________________________ +; +CRLF: + PUSH HL ; PROTECT HL FROM OVERWRITE + LD HL,#TCRLF ; LOAD MESSAGE POINTER + CALL MSG ; SEBD MESSAGE TO SERIAL PORT + POP HL ; PROTECT HL FROM OVERWRITE + RET ; + + +;__LDHL__________________________________________________________________________________________________________________________ +; +; GET ONE WORD OF HEX DATA FROM BUFFER POINTED TO BY HL SERIAL PORT, RETURN IN HL +;________________________________________________________________________________________________________________________________ +; +LDHL: + PUSH DE ; STORE DE + CALL HEXIN ; GET K B. AND MAKE HEX + LD D,A ; THATS THE HI BYTE + CALL HEXIN ; DO HEX AGAIN + LD L,A ; THATS THE LOW BYTE + LD H,D ; MOVE TO HL + POP DE ; RESTORE BC + RET ; GO BACK WITH ADDRESS + + +;__HEXIN__________________________________________________________________________________________________________________________ +; +; GET ONE BYTE OF HEX DATA FROM BUFFER IN HL, RETURN IN A +;________________________________________________________________________________________________________________________________ +; +HEXIN: + PUSH BC ;SAVE BC REGS + CALL NIBL ;DO A NIBBLE + RLC A ;MOVE FIRST BYTE UPPER NIBBLE + RLC A ; + RLC A ; + RLC A ; + LD B,A ; SAVE ROTATED BYTE + CALL NIBL ; DO NEXT NIBBLE + ADD A,B ; COMBINE NIBBLES IN ACC + POP BC ; RESTORE BC + RET ; DONE +NIBL: + LD A,(HL) ; GET K B. DATA + INC HL ; INC KB POINTER + CP #0x40 ; TEST FOR ALPHA + JR NC,ALPH ; + AND #0x0F ; GET THE BITS + RET ; +ALPH: + AND #0x0F ; GET THE BITS + ADD A,#9 ; MAKE IT HEX A-F + RET ; + + +;__HEXINS_________________________________________________________________________________________________________________________ +; +; GET ONE BYTE OF HEX DATA FROM SERIAL PORT, RETURN IN A +;________________________________________________________________________________________________________________________________ +; +HEXINS: + PUSH BC ;SAVE BC REGS + CALL NIBLS ;DO A NIBBLE + RLC A ;MOVE FIRST BYTE UPPER NIBBLE + RLC A ; + RLC A ; + RLC A ; + LD B,A ; SAVE ROTATED BYTE + CALL NIBLS ; DO NEXT NIBBLE + ADD A,B ; COMBINE NIBBLES IN ACC + POP BC ; RESTORE BC + RET ; DONE +NIBLS: + CALL KIN ; GET K B. DATA + INC HL ; INC KB POINTER + CP #0x40 ; TEST FOR ALPHA + JR NC,ALPH ; + AND #0x0F ; GET THE BITS + RET ; + + +;__HXOUT_________________________________________________________________________________________________________________________ +; +; PRINT THE ACCUMULATOR CONTENTS AS HEX DATA ON THE SERIAL PORT +;________________________________________________________________________________________________________________________________ +; +HXOUT: + PUSH BC ; SAVE BC + LD B,A ; + RLC A ; DO HIGH NIBBLE FIRST + RLC A ; + RLC A ; + RLC A ; + AND #0x0F ; ONLY THIS NOW + ADD A,#0x30 ; TRY A NUMBER + CP #0x3A ; TEST IT + JR C,OUT1 ; IF CY SET PRINT 'NUMBER' + ADD A,#0x07 ; MAKE IT AN ALPHA +OUT1: + CALL COUT ; SCREEN IT + LD A,B ; NEXT NIBBLE + AND #0x0F ; JUST THIS + ADD A,#0x30 ; TRY A NUMBER + CP #0x3A ; TEST IT + JR C,OUT2 ; PRINT 'NUMBER' + ADD A,#7 ; MAKE IT ALPHA +OUT2: + CALL COUT ; SCREEN IT + POP BC ; RESTORE BC + RET ; + + +;__SPACE_________________________________________________________________________________________________________________________ +; +; PRINT A SPACE CHARACTER ON THE SERIAL PORT +;________________________________________________________________________________________________________________________________ +; +SPACE: + PUSH AF ; STORE AF + LD A,#0x20 ; LOAD A "SPACE" + CALL COUT ; SCREEN IT + POP AF ; RESTORE AF + RET ; DONE + +;__PHL_________________________________________________________________________________________________________________________ +; +; PRINT THE HL REG ON THE SERIAL PORT +;________________________________________________________________________________________________________________________________ +; +PHL: + LD A,H ; GET HI BYTE + CALL HXOUT ; DO HEX OUT ROUTINE + LD A,L ; GET LOW BYTE + CALL HXOUT ; HEX IT + CALL SPACE ; + RET ; DONE + +;__POUT__________________________________________________________________________________________________________________________ +; +; OUTPUT TO AN I/O PORT, MONITOR COMMAND "O" +;________________________________________________________________________________________________________________________________ +; +POUT: +POUT1: + INC HL ; + CALL HEXIN ; GET PORT + LD C,A ; SAVE PORT POINTER + INC HL ; + CALL HEXIN ; GET DATA +OUTIT: + OUT (C),A ; + JP SERIALCMDLOOP ; + + +;__PIN___________________________________________________________________________________________________________________________ +; +; INPUT FROM AN I/O PORT, MONITOR COMMAND "I" +;________________________________________________________________________________________________________________________________ +; +PIN: + INC HL ; + CALL HEXIN ; GET PORT + LD C,A ; SAVE PORT POINTER + CALL CRLF ; + IN A,(C) ; GET DATA + CALL HXOUT ; SHOW IT + JP SERIALCMDLOOP ; + + + + + +;__CRLFA_________________________________________________________________________________________________________________________ +; +; PRINT COMMAND PROMPT TO THE SERIAL PORT +;________________________________________________________________________________________________________________________________ +; +CRLFA: + PUSH HL ; PROTECT HL FROM OVERWRITE + LD HL,#PROMPT ; + CALL MSG ; + POP HL ; PROTECT HL FROM OVERWRITE + RET ; DONE + + +;__MSG___________________________________________________________________________________________________________________________ +; +; PRINT A STRING TO THE SERIAL PORT +;________________________________________________________________________________________________________________________________ +; +MSG: + +TX_SERLP: + LD A,(HL) ; GET CHARACTER TO A + CP #ENDT ; TEST FOR END BYTE + JP Z,TX_END ; JUMP IF END BYTE IS FOUND + CALL COUT ; + INC HL ; INC POINTER, TO NEXT CHAR + JP TX_SERLP ; TRANSMIT LOOP +TX_END: + RET ;ELSE DONE + +;__RUN___________________________________________________________________________________________________________________________ +; +; TRANSFER OUT OF MONITOR, USER OPTION "R" +;________________________________________________________________________________________________________________________________ +; +RUN: + INC HL ; SHOW READY + CALL LDHL ; GET START ADDRESS + JP (HL) ; + + +;__PROGRM________________________________________________________________________________________________________________________ +; +; PROGRAM RAM LOCATIONS, USER OPTION "P" +;________________________________________________________________________________________________________________________________ +; +PROGRM: + INC HL ; SHOW READY + PUSH HL ; STORE HL + CALL LDHL ; GET START ADDRESS + LD D,H ; + LD E,L ; DE POINTS TO ADDRESS TO PROGRAM + POP HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; +PROGRMLP: + CALL HEXIN ; GET NEXT HEX NUMBER + LD (DE),A ; STORE IT + INC DE ; NEXT ADDRESS; + CALL CRLFA ; CR,LF,> + LD A,#ASCIIP ; + CALL COUT ; + CALL SPACE ; + LD H,D ; + LD L,E ; + CALL PHL ; + LD HL,#KEYBUF ; SET POINTER TO KEYBUF AREA + CALL GETLN ; GET A LINE OF INPUT FROM THE USER + LD HL,#KEYBUF ; RESET POINTER TO START OF KEYBUF + LD A,(HL) ; LOAD FIRST CHAR INTO A + CP #0 ; END OF LINE? + JP Z,PROGRMEXIT ; YES, EXIT + JP PROGRMLP ; NO, LOOP +PROGRMEXIT: + JP SERIALCMDLOOP + + + + + + + +;__DUMP__________________________________________________________________________________________________________________________ +; +; PRINT A MEMORY DUMP, USER OPTION "D" +;________________________________________________________________________________________________________________________________ +; +DUMP: + INC HL ; SHOW READY + PUSH HL ; STORE HL + CALL LDHL ; GET START ADDRESS + LD D,H ; + LD E,L ; + POP HL ; + PUSH DE ; SAVE START + INC HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; + CALL LDHL ; GET END ADDRESS + INC HL ; ADD ONE MORE FOR LATER COMPARE + EX DE,HL ; PUT END ADDRESS IN DE + POP HL ; GET BACK START +GDATA: + CALL CRLF ; +BLKRD: + CALL PHL ; PRINT START LOCATION + LD C,#16 ; SET FOR 16 LOCS + PUSH HL ; SAVE STARTING HL +NXTONE: + EXX ; + LD C,E ; + IN A,(C) ; + EXX ; + AND #0x7F ; + CP #ESC ; + JP Z,SERIALCMDLOOP ; + CP #19 ; + JR Z,NXTONE ; + LD A,(HL) ; GET BYTE + CALL HXOUT ; PRINT IT + CALL SPACE ; +UPDH: + INC HL ; POINT NEXT + DEC C ; DEC LOC COUNT + JR NZ,NXTONE ; IF LINE NOT DONE + ; NOW PRINT 'DECODED' DATA TO RIGHT OF DUMP +PCRLF: + CALL SPACE ; SPACE IT + LD C,#16 ; SET FOR 16 CHARS + POP HL ; GET BACK START +PCRLF0: + LD A,(HL) ; GET BYTE + AND #0x060 ; SEE IF A 'DOT' + LD A,(HL) ; O K. TO GET + JR NZ,PDOT ; +DOT: + LD A,#0x2E ; LOAD A DOT +PDOT: + CALL COUT ; PRINT IT + INC HL ; + LD A,D ; + CP H ; + JR NZ,UPDH1 ; + LD A,E ; + CP L ; + JP Z,SERIALCMDLOOP ; +; +;IF BLOCK NOT DUMPED, DO NEXT CHARACTER OR LINE +UPDH1: + DEC C ; DEC CHAR COUNT + JR NZ,PCRLF0 ; DO NEXT +CONTD: + CALL CRLF ; + JP BLKRD ; + + +;__HXLOAD__________________________________________________________________________________________________________________________ +; +; LOAD INTEL HEX FORMAT FILE FROM THE SERIAL PORT, USER OPTION "H" +; +; [INTEL HEX FORMAT IS: +; 1) COLON (FRAME 0) +; 2) RECORD LENGTH FIELD (FRAMES 1 AND 2) +; 3) LOAD ADDRESS FIELD (FRAMES 3,4,5,6) +; 4) RECORD TYPE FIELD (FRAMES 7 AND 8) +; 5) DATA FIELD (FRAMES 9 TO 9+2*(RECORD LENGTH)-1 +; 6) CHECKSUM FIELD - SUM OF ALL BYTE VALUES FROM RECORD LENGTH TO AND +; INCLUDING CHECKSUM FIELD = 0 ] +; +; EXAMPLE OF INTEL HEX FORMAT FILE +; EACH LINE CONTAINS A CARRIAGE RETURN AS THE LAST CHARACTER +; :18F900002048454C4C4F20574F524C4420FF0D0AFF0D0A3EFF0D0A54BF +; :18F918006573742050726F746F7479706520524F4D204D6F6E69746FF1 +; :18F9300072205265616479200D0AFF0D0A434F4D4D414E4420524543F2 +; :18F948004549564544203AFF0D0A434845434B53554D204552524F52CD +; :16F96000FF0A0D20202D454E442D4F462D46494C452D20200A0DA4 +; :00000001FF +;________________________________________________________________________________________________________________________________ +HXLOAD: + CALL CRLF ; SHOW READY +HXLOAD0: + CALL KIN ; GET THE FIRST CHARACTER, EXPECTING A ':' +HXLOAD1: + CP #0x3A ; IS IT COLON ':'? START OF LINE OF INTEL HEX FILE + JR NZ,HXLOADERR ; IF NOT, MUST BE ERROR, ABORT ROUTINE + LD E,#0 ; FIRST TWO CHARACTERS IS THE RECORD LENGTH FIELD + CALL HEXINS ; GET US TWO CHARACTERS INTO BC, CONVERT IT TO A BYTE + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + LD D,A ; LOAD RECORD LENGTH COUNT INTO D + CALL HEXINS ; GET NEXT TWO CHARACTERS, MEMORY LOAD ADDRESS + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + LD H,A ; PUT VALUE IN H REGISTER + CALL HEXINS ; GET NEXT TWO CHARACTERS, MEMORY LOAD ADDRESS + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + LD L,A ; PUT VALUE IN L REGISTER + CALL HEXINS ; GET NEXT TWO CHARACTERS, RECORD FIELD TYPE + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + CP #1 ; RECORD FIELD TYPE 00 IS DATA, 01 IS END OF FILE + JR NZ,HXLOAD2 ; MUST BE THE END OF THAT FILE + CALL HEXINS ; GET NEXT TWO CHARACTERS, ASSEMBLE INTO BYTE + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + LD A,E ; RECALL THE CHECKSUM BYTE + AND A ; IS IT ZERO? + JP Z,HXLOADEXIT ; MUST BE O K., GO BACK FOR SOME MORE, ELSE + JR HXLOADERR ; CHECKSUMS DON'T ADD UP, ERROR OUT +HXLOAD2: + LD A,D ; RETRIEVE LINE CHARACTER COUNTER + AND A ; ARE WE DONE WITH THIS LINE? + JR Z,HXLOAD3 ; GET TWO MORE ASCII CHARACTERS, BUILD A BYTE AND CHECKSUM + CALL HEXINS ; GET NEXT TWO CHARS, CONVERT TO BYTE IN A, CHECKSUM IT + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + LD (HL),A ; CHECKSUM OK, MOVE CONVERTED BYTE IN A TO MEMORY LOCATION + INC HL ; INCREMENT POINTER TO NEXT MEMORY LOCATION + DEC D ; DECREMENT LINE CHARACTER COUNTER + JR HXLOAD2 ; AND KEEP LOADING INTO MEMORY UNTIL LINE IS COMPLETE +HXLOAD3: + CALL HEXINS ; GET TWO CHARS, BUILD BYTE AND CHECKSUM + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + LD A,E ; CHECK THE CHECKSUM VALUE + AND A ; IS IT ZERO? + JR Z,HXLOADAGAIN ; IF THE CHECKSUM IS STILL OK, CONTINUE ON, ELSE +HXLOADERR: + LD HL,#TXT_CKSUMERR ; GET "CHECKSUM ERROR" MESSAGE + CALL MSG ; PRINT MESSAGE FROM (HL) AND TERMINATE THE LOAD + JP HXLOADEXIT ; RETURN TO PROMPT +HXCHKSUM: + LD C,A ; BUILD THE CHECKSUM + LD A,E ; + SUB C ; THE CHECKSUM SHOULD ALWAYS .EQUAL ZERO WHEN CHECKED + LD E,A ; SAVE THE CHECKSUM BACK WHERE IT CAME FROM + LD A,C ; RETRIEVE THE BYTE AND GO BACK + RET ; BACK TO CALLER +HXLOADAGAIN: + CALL KIN ; CATCH THE TRAILING CARRIAGE RETURN + JP HXLOAD0 ; LOAD ANOTHER LINE OF DATA +HXLOADEXIT: + CALL KIN ; CATCH ANY STRAY TRAILING CHARACTERS + JP SERIALCMDLOOP ; RETURN TO PROMPT + + +;__MOVE__________________________________________________________________________________________________________________________ +; +; MOVE MEMORY, USER OPTION "M" +;________________________________________________________________________________________________________________________________ +; +MOVE: + LD C,#3 + ; START GETNM REPLACEMENT + ; GET SOURCE STARTING MEMORY LOCATION + INC HL ; SHOW EXAMINE READY + PUSH HL ; + CALL LDHL ; LOAD IN HL REGS + LD D,H ; + LD E,L ; + POP HL ; + PUSH DE ; PUSH MEMORY ADDRESS ON STACK + INC HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; PRINT SPACE SEPARATOR + PUSH HL ; + CALL LDHL ; LOAD IN HL REGS + LD D,H ; + LD E,L ; + POP HL ; + PUSH DE ; PUSH MEMORY ADDRESS ON STACK + INC HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; PRINT SPACE SEPARATOR + CALL LDHL ; LOAD IN HL REGS + PUSH HL ; PUSH MEMORY ADDRESS ON STACK + ; END GETNM REPLACEMENT + POP DE ; DEST + POP BC ; SOURCE END + POP HL ; SOURCE + PUSH HL ; + LD A,L ; + CPL ; + LD L,A ; + LD A,H ; + CPL ; + LD H,A ; + INC HL ; + ADD HL,BC ; + LD C,L ; + LD B,H ; + POP HL ; + CALL MOVE_LOOP ; + JP SERIALCMDLOOP ; EXIT MOVE COMMAND ROUTINE +MOVE_LOOP: + LD A,(HL) ; FETCH + LD (DE),A ; DEPOSIT + INC HL ; BUMP SOURCE + INC DE ; BUMP DEST + DEC BC ; DEC COUNT + LD A,C ; + OR B ; + JP NZ,MOVE_LOOP ; TIL COUNT=0 + RET ; + +;__FILL__________________________________________________________________________________________________________________________ +; +; FILL MEMORY, USER OPTION "M" +;________________________________________________________________________________________________________________________________ +; +FILL: + LD C,#3 ; + ; START GETNM REPLACEMENT + ; GET FILL STARTING MEMORY LOCATION + INC HL ; SHOW EXAMINE READY + PUSH HL ; + CALL LDHL ; LOAD IN HL REGS + LD D,H ; + LD E,L ; + POP HL ; + PUSH DE ; PUSH MEMORY ADDRESS ON STACK + INC HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; PRINT SPACE SEPARATOR + ; GET FILL ENDING MEMORY LOCATION + PUSH HL ; + CALL LDHL ; LOAD IN HL REGS + LD D,H ; + LD E,L ; + POP HL ; + PUSH DE ; PUSH MEMORY ADDRESS ON STACK + INC HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; PRINT SPACE SEPARATOR + ; GET TARGET STARTING MEMORY LOCATION + CALL HEXIN ; GET K B. AND MAKE HEX + LD C,A ; PUT FILL VALUE IN F SO IT IS SAVED FOR LATER + PUSH BC ; PUSH FILL VALUE BYTE ON STACK + ; END GETNM REPLACEMENT + POP BC ; BYTE + POP DE ; END + POP HL ; START + LD (HL),C ; +FILL_LOOP: + LD (HL),C ; + INC HL ; + LD A,E ; + SUB L ; + LD B,A ; + LD A,D ; + SUB H ; + OR B ; + JP NZ,FILL_LOOP ; + JP SERIALCMDLOOP ; + +;__GOCPM_________________________________________________________________________________________________________________________ +; +; BOOT CP/M FROM ROM DRIVE, USER OPTION "C" +;________________________________________________________________________________________________________________________________ +; +GOCPM: +;___________________________ +; REMOVE COMMENTS WHEN BURNED IN ROM +;___________________________ + +; LD A,000000000b ; RESET MPCL LATCH TO DEFAULT ROM +; OUT (MPCL),A ; +; LD HL,ROMSTART_CPM ; WHERE IN ROM CP/M IS STORED (FIRST BYTE) +; LD DE,RAMTARG_CPM ; WHERE IN RAM TO MOVE MONITOR TO (FIRST BYTE) +; LD BC,MOVSIZ_CPM ; NUMBER OF BYTES TO MOVE FROM ROM TO RAM +; LDIR ; PERFORM BLOCK COPY OF CP/M TO UPPER RAM PAGE +; LD A,010000000b ; RESET MPCL LATCH TO DEFAULT CP/M WITH 64K SETTING +; OUT (MPCL),A ; + + JP 0x0EA00 ; CP/M COLD BOOT ENTRY POINT + +; +;__INIT_UART_____________________________________________________________________________________________________________________ +; +; INITIALIZE UART +; PARAMS: SER_BAUD NEEDS TO BE SET TO BAUD RATE +; 1200: 96 = 1,843,200 / ( 16 X 1200 ) +; 2400: 48 = 1,843,200 / ( 16 X 2400 ) +; 4800: 24 = 1,843,200 / ( 16 X 4800 ) +; 9600: 12 = 1,843,200 / ( 16 X 9600 ) +; 19K2: 06 = 1,843,200 / ( 16 X 19,200 ) +; 38K4: 03 +; 57K6: 02 +; 115K2: 01 +; +;_________________________________________________________________________________________________________________________________ +; +INIT_UART: + LD A,#0x80 ; + OUT (UART3),A ; SET DLAB FLAG + LD A,(SER_BAUD) ; + OUT (UART0),A ; + LD A,#0 ; + OUT (UART1),A ; + LD A,#3 ; + OUT (UART3),A ; SET 8 BIT DATA, 1 STOPBIT + LD A,#3 ; set DTR & RTS + OUT (UART4),A ; + RET + + +; +;__FILL_MEM_______________________________________________________________________________________________________________________ +; +; FUNCTION : FILL MEMORY WITH A VALUE +; INPUT : HL = START ADDRESS BLOCK +; : BC = LENGTH OF BLOCK +; : A = VALUE TO FILL WITH +; USES : DE, BC +; OUTPUT : +; CALLS : +; TESTED : 13 FEB 2007 +;_________________________________________________________________________________________________________________________________ +; +FILL_MEM: + LD E,L ; + LD D,H ; + INC DE ; + LD (HL),A ; INITIALISE FIRST BYTE OF BLOCK WITH DATA BYTE IN A + DEC BC ; + LDIR ; FILL MEMORY + RET ; RETURN TO CALLER + +; +;__INITIALIZE_____________________________________________________________________________________________________________________ +; +; INITIALIZE SYSTEM +;_________________________________________________________________________________________________________________________________ +; +INITIALIZE: + LD A,#12 ; SPECIFY BAUD RATE 9600 BPS (9600,8,NONE,1) + LD (SER_BAUD),A ; + CALL INIT_UART ; INIT THE UART + RET ; +; + +;__MTERM_INIT________________________________________________________________________________________ +; +; SETUP 8255, MODE 0, PORT A=OUT, PORT B=IN, PORT C=OUT/OUT +; +;____________________________________________________________________________________________________ +MTERM_INIT: + LD A,#0x82 + OUT (PIOCONT),A + RET + +;__KB_GET____________________________________________________________________________________________ +; +; GET A SINGLE KEY AND DECODE +; +;____________________________________________________________________________________________________ +KB_GET: + PUSH HL ; STORE HL +KB_GET_LOOP: ; WAIT FOR KEY + CALL KB_SCAN ; SCAN KB ONCE + CP #0 ; NULL? + JR Z,KB_GET_LOOP ; LOOP WHILE NOT ZERO + LD D,A ; STORE A + LD A,#0x4F ; SCAN ALL COL LINES + OUT (PORTC),A ; SEND TO COLUMN LINES + CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE +KB_CLEAR_LOOP: ; WAIT FOR KEY TO CLEAR + IN A,(PORTB) ; GET ROWS + CP #0 ; ANYTHING PRESSED? + JR NZ,KB_CLEAR_LOOP ; YES, EXIT + LD A,D ; RESTORE A + LD D,#0x00 ; + LD HL,#KB_DECODE ; POINT TO BEGINNING OF TABLE +KB_GET_LLOOP: + CP (HL) ; MATCH? + JR Z,KB_GET_DONE ; FOUND, DONE + INC HL + INC D ; D + 1 + JP NZ,KB_GET_LLOOP ; NOT FOUND, LOOP UNTIL EOT +KB_GET_DONE: + LD A,D ; RESULT INTO A + POP HL ; RESTORE HL + RET + + + +;__KB_SCAN____________________________________________________________________________________________ +; +; SCAN KEYBOARD MATRIX FOR AN INPUT +; +;____________________________________________________________________________________________________ +KB_SCAN: + + LD C,#0 + LD A,#0x41 ; SCAN COL ONE + OUT (PORTC),A ; SEND TO COLUMN LINES + CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + IN A,(PORTB) ; GET ROWS + CP #0x00 ; ANYTHING PRESSED? + JR NZ,KB_SCAN_FOUND ; YES, EXIT + + LD C,#0x0040 + LD A,#0x42 ; SCAN COL TWO + OUT (PORTC),A ; SEND TO COLUMN LINES + CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + IN A,(PORTB) ; GET ROWS + CP #0 ; ANYTHING PRESSED? + JR NZ,KB_SCAN_FOUND ; YES, EXIT + + LD C,#0x0080 + LD A,#0x44 ; SCAN COL THREE + OUT (PORTC),A ; SEND TO COLUMN LINES + CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + IN A,(PORTB) ; GET ROWS + CP #0x00 ; ANYTHING PRESSED? + JR NZ,KB_SCAN_FOUND ; YES, EXIT + + LD C,#0x00C0 ; + LD A,#0x48 ; SCAN COL FOUR + OUT (PORTC),A ; SEND TO COLUMN LINES + CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + IN A,(PORTB) ; GET ROWS + CP #0x00 ; ANYTHING PRESSED? + JR NZ,KB_SCAN_FOUND ; YES, EXIT + + LD A, #0x40 ; TURN OFF ALL COLUMNS + OUT (PORTC),A ; SEND TO COLUMN LINES + LD A, #0x00 ; RETURN NULL + RET ; EXIT + +KB_SCAN_FOUND: + AND #0x3F ; CLEAR TOP TWO BITS + OR C ; ADD IN ROW BITS + LD C,A ; STORE VALUE + LD A,#0x00 ; TURN OFF ALL COLUMNS + OUT (PORTC),A ; SEND TO COLUMN LINES + LD A,C ; RESTORE VALUE + RET + +PAUSE: +KB_SCAN_DELAY: + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + RET + + + +;__HEXDISPLAY________________________________________________________________________________________ +; +; DISPLAY CONTENTS OF DISPLAYBUF IN DECODED HEX BITS 0-3 ARE DISPLAYED DIG, BIT 7 IS DP +; +;____________________________________________________________________________________________________ +HEXDISPLAY: + PUSH HL ; STORE HL + PUSH AF ; STORE AF + PUSH BC ; STORE BC + LD BC,#0007 + ADD HL,BC + LD B,#0x08 ; SET DIGIT COUNT + LD A,#0x40 ; SET CONTROL PORT 7218 TO OFF + OUT (PORTC),A ; OUTPUT + CALL PAUSE ; WAIT + LD A,#0x0F0 ; SET CONTROL TO 1111 (DATA COMING, HEX DECODE,NO DECODE, NORMAL) + OUT (PORTA),A ; OUTPUT TO PORT + LD A,#0x80 ; STROBE WRITE PULSE WITH CONTROL=1 + OUT (PORTC),A ; OUTPUT TO PORT + CALL PAUSE ; WAIT + LD A,#0x40 ; SET CONTROL PORT 7218 TO OFF + OUT (PORTC),A ; OUTPUT +HEXDISPLAY_LP: + LD A,(HL) ; GET DISPLAY DIGIT + CALL DECODEDISPLAY ; DECODE DISPLAY + OUT (PORTA),A ; OUT TO PORTA + LD A,#0x00 ; SET WRITE STROBE + OUT (PORTC),A ; OUT TO PORTC + CALL PAUSE ; DELAY + LD A,#0x40 ; SET CONTROL PORT OFF + OUT (PORTC),A ; OUT TO PORTC + CALL PAUSE ; WAIT + DEC HL ; INC POINTER + DJNZ HEXDISPLAY_LP ; LOOP FOR NEXT DIGIT + POP BC ; RESTORE BC + POP AF ; RESTORE AF + POP HL ; RESTORE HL + RET + +;__DECODEDISPLAY_____________________________________________________________________________________ +; +; DISPLAY CONTENTS OF DISPLAYBUF IN DECODED HEX BITS 0-3 ARE DISPLAYED DIG, BIT 7 IS DP +; +;____________________________________________________________________________________________________ +DECODEDISPLAY: + PUSH BC ; STORE BC + PUSH HL ; STORE HL + LD HL,#SEGDECODE ; POINT HL TO DECODE TABLE + LD B,#0x00 ; RESET HIGH BYTE + LD C,A ; CHAR INTO LOW BYTE + ADD HL,BC ; SET TABLE POINTER + LD A,(HL) ; GET VALUE + POP HL ; RESTORE HL + POP BC ; RESTORE BC + RET + + +;__SEGDISPLAY________________________________________________________________________________________ +; +; DISPLAY CONTENTS OF DISPLAYBUF IN DECODED HEX BITS 0-3 ARE DISPLAYED DIG, BIT 7 IS DP +; +;____________________________________________________________________________________________________ +SEGDISPLAY: + PUSH AF ; STORE AF + PUSH BC ; STORE BC + LD BC,#0x0007 + ADD HL,BC + LD B,#0x08 ; SET DIGIT COUNT + LD A,#0x40 ; SET CONTROL PORT 7218 TO OFF + OUT (PORTC),A ; OUTPUT + CALL PAUSE ; WAIT + LD A,#0x0F0 ; SET CONTROL TO 1111 (DATA COMING, HEX DECODE,NO DECODE, NORMAL) + OUT (PORTA),A ; OUTPUT TO PORT + LD A,#0x80 ; STROBE WRITE PULSE WITH CONTROL=1 + OUT (PORTC),A ; OUTPUT TO PORT + CALL PAUSE ; WAIT + LD A,#0x40 ; SET CONTROL PORT 7218 TO OFF + OUT (PORTC),A ; OUTPUT +SEGDISPLAY_LP: + LD A,(HL) ; GET DISPLAY DIGIT + OUT (PORTA),A ; OUT TO PORTA + LD A,#0x00 ; SET WRITE STROBE + OUT (PORTC),A ; OUT TO PORTC + CALL PAUSE ; DELAY + LD A,#0x40 ; SET CONTROL PORT OFF + OUT (PORTC),A ; OUT TO PORTC + CALL PAUSE ; WAIT + DEC HL ; INC POINTER + DJNZ SEGDISPLAY_LP ; LOOP FOR NEXT DIGIT + POP BC ; RESTORE BC + POP AF ; RESTORE AF + RET + +; +;__WORK_AREA___________________________________________________________________________________________________________________ +; +; RESERVED RAM FOR MONITOR WORKING AREA +;_____________________________________________________________________________________________________________________________ +; +SER_BAUD: .DS 1 ; SPECIFY DESIRED UART COM RATE IN BPS +KEYBUF: .ascii " " + .ascii " " +DISPLAYBUF: .DB 00,00,00,00,00,00,00,00 +IDEDEVICE: .DB 1 ; IDE DRIVE SELECT FLAG (00H=PRIAMRY, 10H = SECONDARY) +IDE_SECTOR_BUFFER: + .DS 0x00200 + + + + +; +;__TEXT_STRINGS_________________________________________________________________________________________________________________ +; +; SYSTEM TEXT STRINGS +;_____________________________________________________________________________________________________________________________ +; +TCRLF: + .DB CR,LF,ENDT + +PROMPT: + .DB CR,LF + .ascii ">" + .DB ENDT + +TXT_READY: + .DB CR,LF + .ascii " NN NN 8888 VV VV EEEEEEEEEE MM MM" + .DB CR,LF + .ascii " NNNN NN 88 88 VV VV EE MMMM MMMM" + .DB CR,LF + .ascii " NN NN NN 88 88 VV VV EE MM MM MM MM" + .DB CR,LF + .ascii " NN NNNN 88 88 VV VV EE MM MM MM" + .DB CR,LF + .ascii " NN NN 8888 VV VV EEEEEEE MM MM" + .DB CR,LF + .ascii " NN NN 88 88 VV VV EE MM MM" + .DB CR,LF + .ascii " NN NN 88 88 VV VV EE MM MM" + .DB CR,LF + .ascii " NN NN 88 88 VVV EE MM MM" + .DB CR,LF + .ascii " NN NN 8888 V EEEEEEEEEE MM MM S B C" + .DB CR,LF + .DB CR,LF + .ascii " ****************************************************************************" + .DB CR,LF + .ascii "MONITOR READY " + .DB CR,LF,ENDT + +TXT_COMMAND: + .DB CR,LF + .ascii "UNKNOWN COMMAND." + .DB ENDT + +TXT_CKSUMERR: + .DB CR,LF + .ascii "CHECKSUM ERROR." + .DB ENDT +CPUUP: + .DB 0x084,0x0EE,0x0BB,0x080,0x0BB,0x0EE,0x0CB,0x084 +ADDR: + .DB 0x00,0x00,0x00,0x00,0x08C,0x0BD,0x0BD,0x0FE + + +PORT: + .DB 0x00,0x00,0x80,0x80,0x094,0x08C,0x09D,0x0EE +SEC: + .DB 0x80,0x80,0x80,0x80,0x80,0x0CB,0x0CF,0x0D7 + + +;_KB DECODE TABLE__________________________________________________________________________________________________________ +; +; +KB_DECODE: +; 0 1 2 3 4 5 6 7 8 9 A B C D E F + .DB 0x41,0x02,0x42,0x82,0x04,0x44,0x84,0x08,0x48,0x88,0x10,0x50,0x90,0x20,0x60,0x0A0 +; FW BK CL EN DP EX GO BO + .DB 0x01,0x81,0x0C1,0x0C2,0x0C4,0x0C8,0x0D0,0x0E0 +; +; F-KEYS, +; FW = FORWARD +; BK = BACKWARD +; CL = CLEAR +; EN = ENTER +; DP = DEPOSIT (INTO MEM) +; EX = EXAMINE (MEM) +; GO = GO +; BO = BOOT +;_________________________________________________________________________________________________________________________ +;_HEX 7_SEG_DECODE_TABLE__________________________________________________________________________________________________ +; +; 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F, ,- +; AND WITH 7FH TO TURN ON DP +;_________________________________________________________________________________________________________________________ +SEGDECODE: + .DB 0x0FB,0x0B0,0x0ED,0x0F5,0x0B6,0x0D7,0x0DF,0x0F0,0x0FF,0x0F7,0x0FE,0x09F,0x0CB,0x0BD,0x0CF,0x0CE,0x080,0x084,0x00,0x0EE,0x09D + +;********************* END OF PROGRAM *********************************** + +;dwg; .ORG 08FFFh +;dwg; .DB 000h +;dwg; .END + +_dbgmon_end:: + .area _CODE + .area _CABS diff --git a/doug/src/dbgmon.sym b/doug/src/dbgmon.sym new file mode 100755 index 00000000..0caa3602 --- /dev/null +++ b/doug/src/dbgmon.sym @@ -0,0 +1,83 @@ + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 1. +dbgmon.s derived from dbgmon.asm +Symbol Table + + .__.ABS.= 0000 G | 6 ADDR 0CCF R | 6 ALPH 0405 R + ASCIIA = 0041 | ASCIIB = 0042 | ASCIIC = 0043 + ASCIID = 0044 | ASCIIE = 0045 | ASCIIF = 0046 + ASCIIG = 0047 | ASCIIH = 0048 | ASCIII = 0049 + ASCIIJ = 004A | ASCIIK = 004B | ASCIIL = 004C + ASCIIM = 004D | ASCIIN = 004E | ASCIIO = 004F + ASCIIP = 0050 | ASCIIQ = 0051 | ASCIIR = 0052 + ASCIIS = 0053 | ASCIIT = 0054 | ASCIIU = 0055 + ASCIIV = 0056 | ASCIIW = 0057 | ASCIIX = 0058 + ASCIIY = 0059 | ASCIIZ = 005A | 6 BLKRD 04EB R + BS = 0008 | 6 CONTD 052A R | 6 COUT 03C8 R + 6 CPUUP 0CC7 R | CR = 000D | 6 CRLF 03D4 R + 6 CRLFA 0481 R | 6 DECODEDI 06F8 R | 6 DEPOSITE 011B R + 6 DEPOSITF 0117 R | 6 DEPOSITG 0105 R | 6 DEPOSITL 00D4 R + 6 DISPLAYB 078B R | 6 DOBOOT 0033 R | 6 DODEPOSI 00D0 R + 6 DOEXAMIN 0124 R | 6 DOGO 00CC R | 6 DOPORTRE 003C R + 6 DOPORTWR 0094 R | 6 DOT 0518 R | 6 DSPSECTO 022B R + 6 DUMP 04D4 R | ENDT = 00FF | ESC = 001B + 6 EXAMINEE 0180 R | 6 EXAMINEF 017C R | 6 EXAMINEG 016A R + 6 EXAMINEL 0128 R | 6 EXIT 0032 R | 6 FILL 05DD R + 6 FILL_LOO 0603 R | 6 FILL_MEM 062A R | 6 FRONTPAN 000F R + 6 GDATA 04E8 R | 6 GETADDR 0189 R | 6 GETADDR1 018C R + 6 GETADDRC 01F6 R | 6 GETADDRD 0204 R | 6 GETADDRD 01A4 R + 6 GETADDRL 0192 R | 6 GETADDRN 01DD R | 6 GETLN 0381 R + 6 GETLNDON 03B0 R | 6 GETLNLOP 0384 R | 6 GETLNSTO 03A8 R + 6 GETPORT 026C R | 6 GETPORT1 026F R | 6 GETPORTC 02B2 R + 6 GETPORTD 02BA R | 6 GETPORTD 0287 R | 6 GETPORTL 0275 R + 6 GETPORTN 02A5 R | 6 GETVALUE 02CF R | 6 GETVALUE 02D2 R + 6 GETVALUE 0312 R | 6 GETVALUE 02E7 R | 6 GETVALUE 02D5 R + 6 GETVALUE 0305 R | 6 GOCPM 0611 R | 6 HEXDISPL 06BE R + 6 HEXDISPL 06DD R | 6 HEXIN 03E9 R | 6 HEXINS 040A R + 6 HXCHKSUM 058A R | 6 HXLOAD 0530 R | 6 HXLOAD0 0533 R + 6 HXLOAD1 0536 R | 6 HXLOAD2 0568 R | 6 HXLOAD3 0577 R + 6 HXLOADAG 0590 R | 6 HXLOADER 0581 R | 6 HXLOADEX 0596 R + 6 HXOUT 0428 R | IDEADDR = 002F | IDECTRL = 002E + IDECYLHI= 0025 | IDECYLLO= 0024 | 6 IDEDEVIC 0793 R + IDEERR = 0021 | IDEHEAD = 0026 | IDEHI = 0028 + IDELO = 0020 | IDESECTC= 0022 | IDESECTN= 0023 + IDESTTS = 0027 | 6 IDE_SECT 0794 R | 6 INITIALI 0632 R + 6 INIT_UAR 0614 R | 6 KB_CLEAR 0650 R | 6 KB_DECOD 0CE7 R + 6 KB_GET 0640 R | 6 KB_GET_D 0664 R | 6 KB_GET_L 065C R + 6 KB_GET_L 0641 R | 6 KB_SCAN 0667 R | 6 KB_SCAN_ 06B4 R + 6 KB_SCAN_ 06AA R | 6 KEYBUF 073B R | 6 KIN 03B4 R + 6 KLOP 0374 R | 6 LDHL 03DD R | LF = 000A + MONSTART= 8000 | 6 MONSTART 031D R | 6 MOVE 059C R + 6 MOVE_LOO 05D2 R | MPCL = 0078 | MPCL_RAM= 0078 + MPCL_ROM= 007C | 6 MSG 048A R | 6 MTERM_IN 063B R + 6 NIBL 03FC R | 6 NIBLS 041D R | 6 NXTONE 04F1 R + 6 OUT1 043C R | 6 OUT2 044A R | 6 OUTIT 046C R + 6 PAUSE 06B4 R | 6 PCRLF 050C R | 6 PCRLF0 0512 R + 6 PDOT 051A R | 6 PHL 0457 R | 6 PIN 0471 R + PIOCONT = 0063 | 6 PORT 0CD7 R | PORTA = 0060 + PORTB = 0061 | PORTC = 0062 | 6 PORTREAD 008B R + 6 PORTREAD 007D R | 6 PORTREAD 003F R | 6 PORTWRIT 0097 R + 6 POUT 0463 R | 6 POUT1 0463 R | 6 PROGRM 049D R + 6 PROGRMEX 04D1 R | 6 PROGRMLP 04AA R | 6 PROMPT 0997 R + RAMBOTTO= 8000 | RAMTOP = FFFF | 6 RUN 0498 R + 6 SEC 0CDF R | 6 SEGDECOD 0CFF R | 6 SEGDISPL 0705 R + 6 SEGDISPL 0723 R | 6 SERIALCM 032C R | 6 SER_BAUD 073A R + 6 SPACE 044F R | STACKSTA= CFFF | 6 TCRLF 0994 R + 6 TXT_CKSU 0CB5 R | 6 TXT_COMM 0CA2 R | 6 TXT_READ 099B R + 6 TX_BUSYL 03C9 R | 6 TX_END 0497 R | 6 TX_SERLP 048A R + UART0 = 0068 | UART1 = 0069 | UART2 = 006A + UART3 = 006B | UART4 = 006C | UART5 = 006D + UART6 = 006E | UART7 = 006F | 6 UPDH 0508 R + 6 UPDH1 0527 R | 6 _dbgmon 0000 GR | 6 _dbgmon_ 0D14 GR + 6 _dbgmon_ 0000 GR + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 2. +dbgmon.s derived from dbgmon.asm +Area Table + + 0 _CODE size 0 flags 0 + 1 _DATA size 0 flags 0 + 2 _OVERLAY size 0 flags 0 + 3 _HOME size 0 flags 0 + 4 _GSINIT size 0 flags 0 + 5 _GSFINAL size 0 flags 0 + 6 _DBGMON size D14 flags 0 + 7 _CABS size 0 flags 0 diff --git a/doug/src/dribdos.lst b/doug/src/dribdos.lst new file mode 100755 index 00000000..c4d9e863 --- /dev/null +++ b/doug/src/dribdos.lst @@ -0,0 +1,2838 @@ + 1 ;-------------------------------------------------------- + 2 ; File Created by SDCC : free open source ANSI-C Compiler + 3 ; Version 3.0.2 #6489 (May 10 2011) (Mac OS X x86_64) + 4 ; This file was generated Sun May 29 01:02:12 2011 + 5 ;-------------------------------------------------------- + 6 .module dribdos + 7 .optsdcc -mz80 + 8 + 9 ;-------------------------------------------------------- + 10 ; Public variables in this module + 11 ;-------------------------------------------------------- + 12 .globl _bdos + 13 ;-------------------------------------------------------- + 14 ; special function registers + 15 ;-------------------------------------------------------- + 16 ;-------------------------------------------------------- + 17 ; ram data + 18 ;-------------------------------------------------------- + 19 .area _DATA + 20 ;-------------------------------------------------------- + 21 ; overlayable items in ram + 22 ;-------------------------------------------------------- + 23 .area _OVERLAY + 24 ;-------------------------------------------------------- + 25 ; external initialized ram data + 26 ;-------------------------------------------------------- + 27 ;-------------------------------------------------------- + 28 ; global & static initialisations + 29 ;-------------------------------------------------------- + 30 .area _HOME + 31 .area _GSINIT + 32 .area _GSFINAL + 33 .area _GSINIT + 34 ;-------------------------------------------------------- + 35 ; Home + 36 ;-------------------------------------------------------- + 37 .area _HOME + 38 .area _HOME + 39 ;-------------------------------------------------------- + 40 ; code + 41 ;-------------------------------------------------------- + 42 .area _BDOS + 43 ;dribdos.c:4: void bdos(int argc,char **argv) + 44 ; --------------------------------- + 45 ; Function bdos + 46 ; --------------------------------- + 0000 47 _bdos_start:: + 0000 48 _bdos: + 49 ;; push ix + 50 ;; ld ix,#0 + 51 ;; add ix,sp + 52 ;; ;dribdos.c:7: } + 53 ;; pop ix + 54 ;; ret + 55 + 56 ;; dwg ; begin DRI source code here + 57 + 58 .title 'Bdos Interface, Bdos, Version 2.2 Feb, 1980' + 59 + 60 ;;dwg;;: .Z80 + 61 ;; aseg +o 0000 62 org 100h +o 0000 63 maclib MEMCFG.LIB ; define configuration parameters +o 0000 64 .phase bdosph +o 0000 65 bios equ biosph + 66 + 67 ;***************************************************************** + 68 ;***************************************************************** + 69 ;** ** + 70 ;** B a s i c D i s k O p e r a t i n g S y s t e m ** + 71 ;** I n t e r f a c e M o d u l e ** + 72 ;** ** + 73 ;***************************************************************** + 74 ;***************************************************************** + 75 + 76 ; Copyright (c) 1978, 1979, 1980 + 77 ; Digital Research + 78 ; Box 579, Pacific Grove + 79 ; California + 80 + 81 + 82 ; 20 january 1980 + 83 +o 0000 84 ssize equ 24 ;24 level stack + 85 + 86 ; low memory locations +o 0000 87 reboot equ 0000h ;reboot system +o 0000 88 ioloc equ 0003h ;i/o byte location +o 0000 89 bdosa equ 0006h ;address field of jp BDOS + 90 + 91 ; bios access constants +o 0000 92 bootf defl bios+3*0 ;cold boot function +o 0000 93 wbootf defl bios+3*1 ;warm boot function +o 0000 94 constf defl bios+3*2 ;console status function +o 0000 95 coninf defl bios+3*3 ;console input function +o 0000 96 conoutf defl bios+3*4 ;console output function +o 0000 97 listf defl bios+3*5 ;list output function +o 0000 98 punchf defl bios+3*6 ;punch output function +o 0000 99 readerf defl bios+3*7 ;reader input function +o 0000 100 homef defl bios+3*8 ;disk home function +o 0000 101 seldskf defl bios+3*9 ;select disk function +o 0000 102 settrkf defl bios+3*10 ;set track function +o 0000 103 setsecf defl bios+3*11 ;set sector function +o 0000 104 setdmaf defl bios+3*12 ;set dma function +o 0000 105 readf defl bios+3*13 ;read disk function +o 0000 106 writef defl bios+3*14 ;write disk function +o 0000 107 liststf defl bios+3*15 ;list status function +o 0000 108 sectran defl bios+3*16 ;sector translate + 109 + 110 ; equates for non graphic characters +o 0000 111 ctlc equ 03h ;control c +o 0000 112 ctle equ 05h ;physical eol +o 0000 113 ctlh equ 08h ;backspace +o 0000 114 ctlp equ 10h ;prnt toggle +o 0000 115 ctlr equ 12h ;repeat line +o 0000 116 ctls equ 13h ;stop/start screen +o 0000 117 ctlu equ 15h ;line delete +o 0000 118 ctlx equ 18h ;=ctl-u +o 0000 119 ctlz equ 1ah ;end of file +o 0000 120 rubout equ 7fh ;char delete +o 0000 121 tab equ 09h ;tab char +o 0000 122 cr equ 0dh ;carriage return +o 0000 123 lf equ 0ah ;line feed +o 0000 124 ctl equ 5eh ;up arrow + 125 + 0000 00 00 00 00 00 00 126 .db 0,0,0,0,0,0 + 127 + 128 ; enter here from the user's program with function number in c, + 129 ; and information address in d,e + 0006 C3r11s00 130 jp bdose ;past parameter block + 131 + 132 ; ************************************************ + 133 ; *** relative locations 0009 - 000e *** + 134 ; ************************************************ + 0009r37s00 135 pererr: .dw persub ;permanent error subroutine + 000Br3Es00 136 selerr: .dw selsub ;select error subroutine + 000Dr41s00 137 roderr: .dw rodsub ;ro disk error subroutine + 000Fr44s00 138 roferr: .dw rofsub ;ro file error subroutine + 139 + 140 + 0011 EB 141 bdose: ex de,hl ;arrive here from user programs + 0012 22rFCs01 142 ld (info),hl + 0015 EB 143 ex de,hl ;info=DE, DE=info + 0016 7B 144 ld a,e + 0017 32rC6s0A 145 ld (linfo),a ;linfo = low(info) - don't equ +a 001A 146 ld hl,0 + 001A 22rFCs01 147 ld (aret),hl ;return value defaults to 0000 + 148 ;save user's stack pointer, set to local stack + 001D 39 149 add hl,sp + 001E 22rFCs01 150 ld (entsp),hl ;entsp = stackptr +a 0021 151 ld sp,lstack ;local stack setup + 0021 AF 152 xor a + 0022 32rC6s0A 153 ld (fcbdsk),a + 0025 32rC6s0A 154 ld (resel),a ;fcbdsk,resel=false +a 0028 155 ld hl,goback ;return here after all functions + 0028 E5 156 push hl ;jmp goback equivalent to ret + 0029 79 157 ld a,c +ua 002A 158 cp nfuncs + 002A D0 159 ret nc ;skip if invalid # + 002B 4B 160 ld c,e ;possible output character to C +a 002C 161 ld hl,functab + 002C 5F 162 ld e,a +a 002D 163 ld d,0 ;DE=func, HL=.ciotab + 002D 19 164 add hl,de + 002E 19 165 add hl,de + 002F 5E 166 ld e,(hl) + 0030 23 167 inc hl + 0031 56 168 ld d,(hl) ;DE=functab(func) + 0032 2ArFCs01 169 ld hl,(info) ;info in DE for later xchg + 0035 EB 170 ex de,hl + 0036 E9 171 jp (hl) ;dispatched + 172 + 173 ; dispatch table for functions + 0037 174 functab: +o 0037 175 dw wbootf, func1, func2, func3 +o 0037 176 dw punchf, listf, func6, func7 +o 0037 177 dw func8, func9, func10,func11 +o 0037 178 diskf equ ($-functab)/2 ;disk funcs +o 0037 179 dw func12,func13,func14,func15 +o 0037 180 dw func16,func17,func18,func19 +o 0037 181 dw func20,func21,func22,func23 +o 0037 182 dw func24,func25,func26,func27 +o 0037 183 dw func28,func29,func30,func31 +o 0037 184 dw func32,func33,func34,func35 +o 0037 185 dw func36,func37,func38,func39 +o 0037 186 dw func40 +o 0037 187 nfuncs equ ($-functab)/2 + 188 + 189 + 190 ; error subroutines +a 0037 191 persub: ld hl,permsg ;report permanent error + 0037 CDr4As00 192 call errflg ;to report the error +ua 003A 193 cp ctlc +u 003A CA 00 00 194 jp z,reboot ;reboot if response is ctlc + 003D C9 195 ret ;and ignore the error + 196 +a 003E 197 selsub: ld hl,selmsg ;report select error + 003E C3r44s00 198 jp wait$err ;wait console before boot + 199 +a 0041 200 rodsub: ld hl,rodmsg ;report write to read/only disk + 0041 C3r44s00 201 jp wait$err ;wait console + 202 + 0044 203 rofsub: ;report read/only file +a 0044 204 ld hl,rofmsg ;drop through to wait for console + 205 + 0044 206 wait$err: ;wait for response before boot + 0044 CDr4As00 207 call errflg +u 0047 C3 00 00 208 jp reboot + 209 + 210 ; error messages +o 004A 211 dskmsg: db 'Bdos Err On ' +o 004A 212 dskerr: db ' : $' ;filled in by errflg +o 004A 213 permsg: db 'Bad Sector$' +o 004A 214 selmsg: db 'Select$' +o 004A 215 rofmsg: db 'File ' +o 004A 216 rodmsg: db 'R/O$' + 217 + 218 + 004A E5 219 errflg: push hl ;report error to console, message address in HL + 004B CDrF0s00 220 call crlf ;stack mssg address, new line + 004E 3ArFCs01 221 ld a,(curdsk) +aq 0051 222 add a,'A' + 0051 32r4As00 223 ld (dskerr),a ;current disk name +a 0054 224 ld bc,dskmsg + 0054 CDrF6s00 225 call print ;the error message + 0057 C1 226 pop bc + 0058 CDrF6s00 227 call print ;error mssage tail + 228 ; jp conin ;to get the input character + 229 ;(drop through to conin) + 230 ; ret + 231 + 232 + 233 ; console handlers +a 005B 234 conin: ld hl,kbchar ;read console character to A + 005B 7E 235 ld a,(hl) +a 005C 236 ld (hl),0 + 005C B7 237 or a + 005D C0 238 ret nz + 239 ;no previous keyboard character ready +u 005E C3 00 00 240 jp coninf ;get character externally + 241 ; ret + 0061 CDr5Bs00 242 conech: call conin ;read character with echo + 0064 CDr6Fs00 243 call echoc + 0067 D8 244 ret c ;echo character? + 245 ;character must be echoed before return + 0068 F5 246 push af + 0069 4F 247 ld c,a + 006A CDrC8s00 248 call tabout + 006D F1 249 pop af + 006E C9 250 ret ;with character in A + 251 + 006F 252 echoc: ;echo character if graphic +ua 006F 253 cp cr ;cr, lf, tab, or backspace + 006F C8 254 ret z ;carriage return? +ua 0070 255 cp lf + 0070 C8 256 ret z ;line feed? +ua 0071 257 cp tab + 0071 C8 258 ret z ;tab? +ua 0072 259 cp ctlh + 0072 C8 260 ret z ;backspace? +q 0073 261 cp ' ' + 0073 C9 262 ret ;carry set if not graphic + 263 + 0074 264 conbrk: ;check for character ready + 0074 3ArFCs01 265 ld a,(kbchar) + 0077 B7 266 or a + 0078 C2r90s00 267 jp nz,conb1 ;skip if active kbchar + 268 ;no active kbchar, check external break +u 007B CD 00 00 269 call constf +a 007E 270 and 1 + 007E C8 271 ret z ;return if no char ready + 272 ;character ready, read it +u 007F CD 00 00 273 call coninf ;to A +ua 0082 274 cp ctls + 0082 C2r8Ds00 275 jp nz,conb0 ;check stop screen function + 276 ;found ctls, read next character +u 0085 CD 00 00 277 call coninf ;to A +ua 0088 278 cp ctlc +u 0088 CA 00 00 279 jp z,reboot ;ctlc implies re-boot + 280 ;not a reboot, act as if nothing has happened + 008B AF 281 xor a + 008C C9 282 ret ;with zero in accumulator + 008D 283 conb0: + 284 ;character in accum, save it + 008D 32rFCs01 285 ld (kbchar),a + 0090 286 conb1: + 287 ;return with true set in accumulator +a 0090 288 ld a,1 + 0090 C9 289 ret + 290 + 0091 291 conout: ;compute character position/write console char from C + 292 ;compcol = true if computing column position + 0091 3ArFCs01 293 ld a,(compcol) + 0094 B7 294 or a + 0095 C2rABs00 295 jp nz,compout + 296 ;write the character, then compute the column + 297 ;write console character from C + 0098 C5 298 push bc + 0099 CDr74s00 299 call conbrk ;check for screen stop function + 009C C1 300 pop bc + 009D C5 301 push bc ;recall/save character +u 009E CD 00 00 302 call conoutf ;externally, to console + 00A1 C1 303 pop bc + 00A2 C5 304 push bc ;recall/save character + 305 ;may be copying to the list device + 00A3 3ArFCs01 306 ld a,(listcp) + 00A6 B7 307 or a +u 00A7 C4 00 00 308 call nz,listf ;to printer, if so + 00AA C1 309 pop bc ;recall the character + 00AB 310 compout: + 00AB 79 311 ld a,c ;recall the character + 312 ;and compute column position +a 00AC 313 ld hl,column ;A = char, HL = .column +ua 00AC 314 cp rubout + 00AC C8 315 ret z ;no column change if nulls + 00AD 34 316 inc (hl) ;column = column + 1 +q 00AE 317 cp ' ' + 00AE D0 318 ret nc ;return if graphic + 319 ;not graphic, reset column position + 00AF 35 320 dec (hl) ;column = column - 1 + 00B0 7E 321 ld a,(hl) + 00B1 B7 322 or a + 00B2 C8 323 ret z ;return if at zero + 324 ;not at zero, may be backspace or end line + 00B3 79 325 ld a,c ;character back to A +ua 00B4 326 cp ctlh + 00B4 C2rB9s00 327 jp nz,notbacksp + 328 ;backspace character + 00B7 35 329 dec (hl) ;column = column - 1 + 00B8 C9 330 ret + 331 + 00B9 332 notbacksp: ;not a backspace character, eol? +ua 00B9 333 cp lf + 00B9 C0 334 ret nz ;return if not + 335 ;end of line, column = 0 +a 00BA 336 ld (hl),0 ;column = 0 + 00BA C9 337 ret + 338 + 00BB 339 ctlout: ;send C character with possible preceding up-arrow + 00BB 79 340 ld a,c + 00BC CDr6Fs00 341 call echoc ;cy if not graphic (or special case) + 00BF D2rC8s00 342 jp nc,tabout ;skip if graphic, tab, cr, lf, or ctlh + 343 ;send preceding up arrow + 00C2 F5 344 push af +ua 00C3 345 ld c,ctl + 00C3 CDr91s00 346 call conout ;up arrow + 00C6 F1 347 pop af +q 00C7 348 or 40h ;becomes graphic letter + 00C7 4F 349 ld c,a ;ready to print + 350 ;(drop through to tabout) + 351 + 00C8 352 tabout: ;expand tabs to console + 00C8 79 353 ld a,c +ua 00C9 354 cp tab + 00C9 C2r91s00 355 jp nz,conout ;direct to conout if not + 356 ;tab encountered, move to next tab position +aq 00CC 357 tab0: ld c,' ' + 00CC CDr91s00 358 call conout ;another blank + 00CF 3ArFCs01 359 ld a,(column) +q 00D2 360 and 111b ;column mod 8 = 0 ? + 00D2 C2rCCs00 361 jp nz,tab0 ;back for another if not + 00D5 C9 362 ret + 363 + 00D6 364 backup: ;back-up one screen position + 00D6 CDrDCs00 365 call pctlh +aq 00D9 366 ld c,' ' +u 00D9 CD 00 00 367 call conoutf + 368 ; (drop through to pctlh) + 00DC 369 pctlh: ;send ctlh to console without affecting column count +ua 00DC 370 ld c,ctlh +u 00DC C3 00 00 371 jp conoutf + 372 ; ret + 00DF 373 crlfp: ;print #, cr, lf for ctlx, ctlu, ctlr functions + 374 ;then move to strtcol (starting column) +aq 00DF 375 ld c,'#' + 00DF CDr91s00 376 call conout + 00E2 CDrF0s00 377 call crlf ;column = 0, move to position strtcol + 00E5 3ArFCs01 378 crlfp0: ld a,(column) +a 00E8 379 ld hl,strtcol + 00E8 BE 380 cp (hl) + 00E9 D0 381 ret nc ;stop when column reaches strtcol +aq 00EA 382 ld c,' ' + 00EA CDr91s00 383 call conout ;print blank + 00ED C3rE5s00 384 jp crlfp0 + 385 +ua 00F0 386 crlf: ld c,cr ;carriage return line feed sequence + 00F0 CDr91s00 387 call conout +ua 00F3 388 ld c,lf + 00F3 C3r91s00 389 jp conout + 390 ; ret + 00F6 0A 391 print: ld a,(bc) ;print message until M(BC) = '$' +q 00F7 392 cp '$' + 00F7 C8 393 ret z ;stop on $ + 394 ;more to print + 00F8 03 395 inc bc + 00F9 C5 396 push bc + 00FA 4F 397 ld c,a ;char to C + 00FB CDrC8s00 398 call tabout ;another character printed + 00FE C1 399 pop bc + 00FF C3rF6s00 400 jp print + 401 + 0102 402 read: ;read to info address (max length, current length, buffer) + 0102 3ArFCs01 403 ld a,(column) + 0105 32rFCs01 404 ld (strtcol),a ;save start for ctl-x, ctl-h + 0108 2ArFCs01 405 ld hl,(info) + 010B 4E 406 ld c,(hl) + 010C 23 407 inc hl + 010D E5 408 push hl +a 010E 409 ld b,0 + 410 ;B = current buffer length, + 411 ;C = maximum buffer length, + 412 ;HL= next to fill - 1 + 010E 413 readnx: ;read next character, BC, HL active + 010E C5 414 push bc + 010F E5 415 push hl ;blen, cmax, HL saved + 0110 CDr5Bs00 416 readn0: call conin ;next char in A +q 0113 417 and 7fh ;mask parity bit + 0113 E1 418 pop hl + 0114 C1 419 pop bc ;reactivate counters +ua 0115 420 cp cr + 0115 CArBAs01 421 jp z,readen ;end of line? +ua 0118 422 cp lf + 0118 CArBAs01 423 jp z,readen ;also end of line +ua 011B 424 cp ctlh + 011B C2r2Ds01 425 jp nz,noth ;backspace? + 426 ;do we have any characters to back over? + 011E 78 427 ld a,b + 011F B7 428 or a + 0120 CAr0Es01 429 jp z,readnx + 430 ;characters remain in buffer, backup one + 0123 05 431 dec b ;remove one character + 0124 3ArFCs01 432 ld a,(column) + 0127 32rFCs01 433 ld (compcol),a ;col > 0 + 434 ;compcol > 0 marks repeat as length compute + 012A C3r73s01 435 jp linelen ;uses same code as repeat + 436 + 012D 437 noth: ;not a backspace +ua 012D 438 cp rubout + 012D C2r3Bs01 439 jp nz,notrub ;rubout char? + 440 ;rubout encountered, rubout if possible + 0130 78 441 ld a,b + 0131 B7 442 or a + 0132 CAr0Es01 443 jp z,readnx ;skip if len=0 + 444 ;buffer has characters, resend last char + 0135 7E 445 ld a,(hl) + 0136 05 446 dec b + 0137 2B 447 dec hl ;A = last char + 448 ;blen=blen-1, next to fill - 1 decremented + 0138 C3rA6s01 449 jp rdech1 ;act like this is an echo + 450 + 013B 451 notrub: ;not a rubout character, check end line +ua 013B 452 cp ctle + 013B C2r4As01 453 jp nz,note ;physical end line? + 454 ;yes, save active counters and force eol + 013E C5 455 push bc + 013F E5 456 push hl + 0140 CDrF0s00 457 call crlf + 0143 AF 458 xor a + 0144 32rFCs01 459 ld (strtcol),a ;start position = 00 + 0147 C3r10s01 460 jp readn0 ;for another character + 461 + 014A 462 note: ;not end of line, list toggle? +ua 014A 463 cp ctlp + 014A C2r54s01 464 jp nz,notp ;skip if not ctlp + 465 ;list toggle - change parity + 014D E5 466 push hl ;save next to fill - 1 +a 014E 467 ld hl,listcp ;HL=.listcp flag +a 014E 468 ld a,1 + 014E 96 469 sub (hl) ;True-listcp + 014F 77 470 ld (hl),a ;listcp = not listcp + 0150 E1 471 pop hl + 0151 C3r0Es01 472 jp readnx ;for another char + 473 + 0154 474 notp: ;not a ctlp, line delete? +ua 0154 475 cp ctlx + 0154 C2r66s01 476 jp nz,notx + 0157 E1 477 pop hl ;discard start position + 478 ;loop while column > strtcol + 0158 3ArFCs01 479 backx: ld a,(strtcol) +a 015B 480 ld hl,column + 015B BE 481 cp (hl) + 015C D2r02s01 482 jp nc,read ;start again + 015F 35 483 dec (hl) ;column = column - 1 + 0160 CDrD6s00 484 call backup ;one position + 0163 C3r58s01 485 jp backx + 486 + 0166 487 notx: ;not a control x, control u? + 488 ;not control-X, control-U? +ua 0166 489 cp ctlu + 0166 C2r70s01 490 jp nz,notu ;skip if not + 491 ;delete line (ctlu) + 0169 CDrDFs00 492 call crlfp ;physical eol + 016C E1 493 pop hl ;discard starting position + 016D C3r02s01 494 jp read ;to start all over + 495 + 0170 496 notu: ;not line delete, repeat line? +ua 0170 497 cp ctlr + 0170 C2rA3s01 498 jp nz,notr + 0173 499 linelen: ;repeat line, or compute line len (ctlh) + 500 ;if compcol > 0 + 0173 C5 501 push bc + 0174 CDrDFs00 502 call crlfp ;save line length + 0177 C1 503 pop bc + 0178 E1 504 pop hl + 0179 E5 505 push hl + 017A C5 506 push bc + 507 ;bcur, cmax active, beginning buff at HL + 017B 78 508 rep0: ld a,b + 017C B7 509 or a + 017D CAr8Ds01 510 jp z,rep1 ;count len to 00 + 0180 23 511 inc hl + 0181 4E 512 ld c,(hl) ;next to print + 0182 05 513 dec b + 0183 C5 514 push bc + 0184 E5 515 push hl ;count length down + 0185 CDrBBs00 516 call ctlout ;character echoed + 0188 E1 517 pop hl + 0189 C1 518 pop bc ;recall remaining count + 018A C3r7Bs01 519 jp rep0 ;for the next character + 520 + 018D 521 rep1: ;end of repeat, recall lengths + 522 ;original BC still remains pushed + 018D E5 523 push hl ;save next to fill + 018E 3ArFCs01 524 ld a,(compcol) + 0191 B7 525 or a ;>0 if computing length + 0192 CAr10s01 526 jp z,readn0 ;for another char if so + 527 ;column position computed for ctlh +a 0195 528 ld hl,column + 0195 96 529 sub (hl) ;diff > 0 + 0196 32rFCs01 530 ld (compcol),a ;count down below + 531 ;move back compcol-column spaces + 0199 532 backsp: ;move back one more space + 0199 CDrD6s00 533 call backup ;one space +a 019C 534 ld hl,compcol + 019C 35 535 dec (hl) + 019D C2r99s01 536 jp nz,backsp + 01A0 C3r10s01 537 jp readn0 ;for next character + 538 + 01A3 539 notr: ;not a ctlr, place into buffer + 01A3 23 540 rdecho: inc hl + 01A4 77 541 ld (hl),a ;character filled to mem + 01A5 04 542 inc b ;blen = blen + 1 + 01A6 543 rdech1: ;look for a random control character + 01A6 C5 544 push bc + 01A7 E5 545 push hl ;active values saved + 01A8 4F 546 ld c,a ;ready to print + 01A9 CDrBBs00 547 call ctlout ;may be up-arrow C + 01AC E1 548 pop hl + 01AD C1 549 pop bc + 01AE 7E 550 ld a,(hl) ;recall char +ua 01AF 551 cp ctlc ;set flags for reboot test + 01AF 78 552 ld a,b ;move length to A + 01B0 C2rB6s01 553 jp nz,notc ;skip if not a control c +a 01B3 554 cp 1 ;control C, must be length 1 +u 01B3 CA 00 00 555 jp z,reboot ;reboot if blen = 1 + 556 ;length not one, so skip reboot + 01B6 557 notc: ;not reboot, are we at end of buffer? + 01B6 B9 558 cp c + 01B7 DAr0Es01 559 jp c,readnx ;go for another if not + 01BA 560 readen: ;end of read operation, store blen + 01BA E1 561 pop hl + 01BB 70 562 ld (hl),b ;M(current len) = B +ua 01BC 563 ld c,cr + 01BC C3r91s00 564 jp conout ;return carriage + 565 ; ret + 01BF 566 func1: ;return console character with echo + 01BF CDr61s00 567 call conech + 01C2 C3rF5s01 568 jp sta$ret + 569 +o 01C5 570 func2 equ tabout + 571 ;write console character with tab expansion + 572 + 01C5 573 func3: ;return reader character +u 01C5 CD 00 00 574 call readerf + 01C8 C3rF5s01 575 jp sta$ret + 576 + 577 ;func4: equated to punchf + 578 ;write punch character + 579 + 580 ;func5: equated to listf + 581 ;write list character + 582 ;write to list device + 583 + 01CB 584 func6: ;direct console i/o - read if 0ffh + 01CB 79 585 ld a,c + 01CC 3C 586 inc a + 01CD CArD7s01 587 jp z,dirinp ;0ffh => 00h, means input mode + 01D0 3C 588 inc a +u 01D1 CA 00 00 589 jp z,constf ;0feH in C for status + 590 ;direct output function +u 01D4 C3 00 00 591 jp conoutf + 592 +u 01D7 CD 00 00 593 dirinp: call constf ;status check + 01DA B7 594 or a + 01DB CArAFs0A 595 jp z,retmon ;skip, return 00 if not ready + 596 ;character is ready, get it +u 01DE CD 00 00 597 call coninf ;to A + 01E1 C3rF5s01 598 jp sta$ret + 599 + 01E4 600 func7: ;return io byte +u 01E4 3A 00 00 601 ld a,(ioloc) + 01E7 C3rF5s01 602 jp sta$ret + 603 + 01EA 604 func8: ;set i/o byte +ua 01EA 605 ld hl,ioloc + 01EA 71 606 ld (hl),c + 01EB C9 607 ret ;jmp goback + 608 + 01EC 609 func9: ;write line until $ encountered + 01EC EB 610 ex de,hl ;was lhld info + 01ED 4D 611 ld c,l + 01EE 44 612 ld b,h ;BC=string address + 01EF C3rF6s00 613 jp print ;out to console + 614 +o 01F2 615 func10 equ read + 616 ;read a buffered console line + 617 + 01F2 618 func11: ;check console status + 01F2 CDr74s00 619 call conbrk + 620 ;(drop through to sta$ret) + 01F5 621 sta$ret: ;store the A register to aret + 01F5 32rFCs01 622 ld (aret),a + 01F8 623 func$ret: + 01F8 C9 624 ret ;jmp goback (pop stack for non cp/m functions) + 625 + 01F9 626 setlret1: ;set lret = 1 +a 01F9 627 ld a,1 + 01F9 C3rF5s01 628 jp sta$ret + 629 + 630 + 631 + 632 ; data areas + 633 + 01FC 634 compcol: +o 01FC 635 db 0 ;true if computing column position + 01FC 636 strtcol: +o 01FC 637 db 0 ;starting column position after read +o 01FC 638 column: db 0 ;column position +o 01FC 639 listcp: db 0 ;listing toggle +o 01FC 640 kbchar: db 0 ;initial key char = 00 +o 01FC 641 entsp: ds 2 ;entry stack pointer +o 01FC 642 ds ssize*2 ;stack size + 01FC 643 lstack: + 644 ; end of Basic I/O System + 645 + 646 ;***************************************************************** + 647 ;***************************************************************** + 648 + 649 ; common values shared between bdosi and bdos + 01FC 650 usrcode: +o 01FC 651 db 0 ;current user number +o 01FC 652 curdsk: db 0 ;current disk number +o 01FC 653 info: ds 2 ;information address +o 01FC 654 aret: ds 2 ;address value to return +o 01FC 655 lret equ aret ;low(aret) + 656 + 657 ;***************************************************************** + 658 ;***************************************************************** + 659 ;** ** + 660 ;** B a s i c D i s k O p e r a t i n g S y s t e m ** + 661 ;** ** + 662 ;***************************************************************** + 663 ;***************************************************************** + 664 +o 01FC 665 dvers equ 22h ;version 2.2 + 666 ; module addresses + 667 + 668 ; literal constants +o 01FC 669 true equ 0ffh ;constant true +o 01FC 670 false equ 000h ;constant false +o 01FC 671 enddir equ 0ffffh ;end of directory +o 01FC 672 byte equ 1 ;number of bytes for "byte" type +o 01FC 673 word equ 2 ;number of bytes for "word" type + 674 + 675 ; fixed addresses in low memory +o 01FC 676 tfcb equ 005ch ;default fcb location +o 01FC 677 tbuff equ 0080h ;default buffer location + 678 + 679 ; fixed addresses referenced in bios module are + 680 ; pererr (0009), selerr (000c), roderr (000f) + 681 + 682 ; error message handlers + 683 + 684 ;per$error: ;report permanent error to user + 685 ; ld hl,pererr + 686 ; jp goerr + 687 + 688 ;rod$error: ;report read/only disk error + 689 ; ld hl,roderr + 690 ; jp goerr + 691 + 692 ;rof$error: ;report read/only file error + 693 ; ld hl,roferr + 694 ; jp goerr + 695 + 01FC 696 sel$error: ;report select error +a 01FC 697 ld hl,selerr + 698 + 699 + 01FC 700 goerr: ;HL = .errorhandler, call subroutine + 01FC 5E 701 ld e,(hl) + 01FD 23 702 inc hl + 01FE 56 703 ld d,(hl) ;address of routine in DE + 01FF EB 704 ex de,hl + 0200 E9 705 jp (hl) ;to subroutine + 706 + 707 + 708 + 709 ; local subroutines for bios interface + 710 + 0201 711 move: ;move data length of length C from source DE to + 712 ;destination given by HL + 0201 0C 713 inc c ;in case it is zero + 0202 0D 714 move0: dec c + 0203 C8 715 ret z ;more to move + 0204 1A 716 ld a,(de) + 0205 77 717 ld (hl),a ;one byte moved + 0206 13 718 inc de + 0207 23 719 inc hl ;to next byte + 0208 C3r02s02 720 jp move0 + 721 + 020B 722 selectdisk: ;select the disk drive given by curdsk, and fill + 723 ;the base addresses curtrka - alloca, then fill + 724 ;the values of the disk parameter block + 020B 3ArFCs01 725 ld a,(curdsk) + 020E 4F 726 ld c,a ;current disk# to c + 727 ;lsb of e = 0 if not yet logged - in +u 020F CD 00 00 728 call seldskf ;HL filled by call + 729 ;HL = 0000 if error, otherwise disk headers + 0212 7C 730 ld a,h + 0213 B5 731 or l + 0214 C8 732 ret z ;return with 0000 in HL and z flag + 733 ;disk header block address in hl + 0215 5E 734 ld e,(hl) + 0216 23 735 inc hl + 0217 56 736 ld d,(hl) + 0218 23 737 inc hl ;DE=.tran + 0219 22rC6s0A 738 ld (cdrmaxa),hl + 021C 23 739 inc hl + 021D 23 740 inc hl ;.cdrmax + 021E 22rC6s0A 741 ld (curtrka),hl + 0221 23 742 inc hl + 0222 23 743 inc hl ;HL=.currec + 0223 22rC6s0A 744 ld (curreca),hl + 0226 23 745 inc hl + 0227 23 746 inc hl ;HL=.buffa + 747 ;DE still contains .tran + 0228 EB 748 ex de,hl + 0229 22rC6s0A 749 ld (tranv),hl ;.tran vector +a 022C 750 ld hl,buffa ;DE= source for move, HL=dest +ua 022C 751 ld c,addlist + 022C CDr01s02 752 call move ;addlist filled + 753 ;now fill the disk parameter block + 022F 2ArC6s0A 754 ld hl,(dpbaddr) + 0232 EB 755 ex de,hl ;DE is source +a 0233 756 ld hl,sectpt ;HL is destination +ua 0233 757 ld c,dpblist + 0233 CDr01s02 758 call move ;data filled + 759 ;now set single/double map mode + 0236 2ArC6s0A 760 ld hl,(maxall) ;largest allocation number + 0239 7C 761 ld a,h ;00 indicates < 255 +a 023A 762 ld hl,single +ua 023A 763 ld (hl),true ;assume a=00 + 023A B7 764 or a + 023B CAr3Es02 765 jp z,retselect + 766 ;high order of maxall not zero, use double dm +ua 023E 767 ld (hl),false + 023E 768 retselect: +ua 023E 769 ld a,true + 023E B7 770 or a + 023F C9 771 ret ;select disk function ok + 772 + 0240 773 home: ;move to home position, then offset to start of dir +u 0240 CD 00 00 774 call homef ;move to track 00, sector 00 reference + 775 ;lxi h,offset ;mov c,m ;inx h ;mov b,m ;call settrkf + 776 ;first directory position selected + 0243 AF 777 xor a ;constant zero to accumulator + 0244 2ArC6s0A 778 ld hl,(curtrka) + 0247 77 779 ld (hl),a + 0248 23 780 inc hl + 0249 77 781 ld (hl),a ;curtrk=0000 + 024A 2ArC6s0A 782 ld hl,(curreca) + 024D 77 783 ld (hl),a + 024E 23 784 inc hl + 024F 77 785 ld (hl),a ;currec=0000 + 786 ;curtrk, currec both set to 0000 + 0250 C9 787 ret + 788 + 0251 789 rdbuff: ;read buffer and check condition +u 0251 CD 00 00 790 call readf ;current drive, track, sector, dma + 0254 C3r5As02 791 jp diocomp ;check for i/o errors + 792 + 0257 793 wrbuff: ;write buffer and check condition + 794 ;write type (wrtype) is in register C + 795 ;wrtype = 0 => normal write operation + 796 ;wrtype = 1 => directory write operation + 797 ;wrtype = 2 => start of new block +u 0257 CD 00 00 798 call writef ;current drive, track, sector, dma + 025A 799 diocomp: ;check for disk errors + 025A B7 800 or a + 025B C8 801 ret z +a 025C 802 ld hl,pererr + 025C C3rFCs01 803 jp goerr + 804 + 025F 805 seek$dir: ;seek the record containing the current dir entry + 025F 2ArC6s0A 806 ld hl,(dcnt) ;directory counter to HL +ua 0262 807 ld c,dskshf + 0262 CDr6As03 808 call hlrotr ;value to HL + 0265 22rC6s0A 809 ld (arecord),hl + 0268 22rC6s0A 810 ld (drec),hl ;ready for seek + 811 ; jp seek + 812 ; ret + 813 + 814 + 026B 815 seek: ;seek the track given by arecord (actual record) + 816 ;local equates for registers + 817 ;load the registers from memory +a 026B 818 ld hl,arecord + 026B 4E 819 ld c,(hl) + 026C 23 820 inc hl + 026D 46 821 ld b,(hl) + 026E 2ArC6s0A 822 ld hl,(curreca) + 0271 5E 823 ld e,(hl) + 0272 23 824 inc hl + 0273 56 825 ld d,(hl) + 0274 2ArC6s0A 826 ld hl,(curtrka) + 0277 7E 827 ld a,(hl) + 0278 23 828 inc hl + 0279 66 829 ld h,(hl) + 027A 6F 830 ld l,a + 831 ;loop while arecord < currec + 027B 79 832 seek0: ld a,c + 027C 93 833 sub e + 027D 78 834 ld a,b + 027E 9A 835 sbc a,d + 027F D2r91s02 836 jp nc,seek1 ;skip if arecord >= currec + 837 ;currec = currec - sectpt + 0282 E5 838 push hl + 0283 2ArC6s0A 839 ld hl,(sectpt) + 0286 7B 840 ld a,e + 0287 95 841 sub l + 0288 5F 842 ld e,a + 0289 7A 843 ld a,d + 028A 9C 844 sbc a,h + 028B 57 845 ld d,a + 028C E1 846 pop hl + 847 ;curtrk = curtrk - 1 + 028D 2B 848 dec hl + 028E C3r7Bs02 849 jp seek0 ;for another try + 850 + 0291 851 seek1: ;look while arecord >= (t:=currec + sectpt) + 0291 E5 852 push hl + 0292 2ArC6s0A 853 ld hl,(sectpt) + 0295 19 854 add hl,de ;HL = currec+sectpt + 0296 DArA6s02 855 jp c,seek2 ;can be > FFFFH + 0299 79 856 ld a,c + 029A 95 857 sub l + 029B 78 858 ld a,b + 029C 9C 859 sbc a,h + 029D DArA6s02 860 jp c,seek2 ;skip if t > arecord + 861 ;currec = t + 02A0 EB 862 ex de,hl + 863 ;curtrk = curtrk + 1 + 02A1 E1 864 pop hl + 02A2 23 865 inc hl + 02A3 C3r91s02 866 jp seek1 ;for another try + 867 + 02A6 E1 868 seek2: pop hl + 869 ;arrive here with updated values in each register + 02A7 C5 870 push bc + 02A8 D5 871 push de + 02A9 E5 872 push hl ;to stack for later + 873 ;stack contains (lowest) BC=arecord, DE=currec, HL=curtrk + 02AA EB 874 ex de,hl + 02AB 2ArC6s0A 875 ld hl,(offset) + 02AE 19 876 add hl,de ;HL = curtrk+offset + 02AF 44 877 ld b,h + 02B0 4D 878 ld c,l +u 02B1 CD 00 00 879 call settrkf ;track set up + 880 ;note that BC - curtrk is difference to move in bios + 02B4 D1 881 pop de ;recall curtrk + 02B5 2ArC6s0A 882 ld hl,(curtrka) + 02B8 73 883 ld (hl),e + 02B9 23 884 inc hl + 02BA 72 885 ld (hl),d ;curtrk updated + 886 ;now compute sector as arecord-currec + 02BB D1 887 pop de ;recall currec + 02BC 2ArC6s0A 888 ld hl,(curreca) + 02BF 73 889 ld (hl),e + 02C0 23 890 inc hl + 02C1 72 891 ld (hl),d + 02C2 C1 892 pop bc ;BC=arecord, DE=currec + 02C3 79 893 ld a,c + 02C4 93 894 sub e + 02C5 4F 895 ld c,a + 02C6 78 896 ld a,b + 02C7 9A 897 sbc a,d + 02C8 47 898 ld b,a + 02C9 2ArC6s0A 899 ld hl,(tranv) + 02CC EB 900 ex de,hl ;BC=sector#, DE=.tran +u 02CD CD 00 00 901 call sectran ;HL = tran(sector) + 02D0 4D 902 ld c,l + 02D1 44 903 ld b,h ;BC = tran(sector) +u 02D2 C3 00 00 904 jp setsecf ;sector selected + 905 ; ret + 906 + 907 ; file control block (fcb) constants +o 02D5 908 empty equ 0e5h ;empty directory entry +o 02D5 909 lstrec equ 127 ;last record# in extent +o 02D5 910 recsiz equ 128 ;record size +o 02D5 911 fcblen equ 32 ;file control block size +o 02D5 912 dirrec equ recsiz/fcblen ;directory elts / record +o 02D5 913 dskshf equ 2 ;log2(dirrec) +o 02D5 914 dskmsk equ dirrec-1 +o 02D5 915 fcbshf equ 5 ;log2(fcblen) + 916 +o 02D5 917 extnum equ 12 ;extent number field +o 02D5 918 maxext equ 31 ;largest extent number +o 02D5 919 ubytes equ 13 ;unfilled bytes field +o 02D5 920 modnum equ 14 ;data module number +o 02D5 921 maxmod equ 15 ;largest module number +o 02D5 922 fwfmsk equ 80h ;file write flag is high order modnum +o 02D5 923 namlen equ 15 ;name length +o 02D5 924 reccnt equ 15 ;record count field +o 02D5 925 dskmap equ 16 ;disk map field +o 02D5 926 lstfcb equ fcblen-1 +o 02D5 927 nxtrec equ fcblen +o 02D5 928 ranrec equ nxtrec+1 ;random record field (2 bytes) + 929 + 930 ; reserved file indicators +o 02D5 931 rofile equ 9 ;high order of first type char +o 02D5 932 invis equ 10 ;invisible file in dir command + 933 ; equ 11 ;reserved + 934 + 935 ; utility functions for file access + 936 + 02D5 937 dm$position: ;compute disk map position for vrecord to HL +a 02D5 938 ld hl,blkshf + 02D5 4E 939 ld c,(hl) ;shift count to C + 02D6 3ArC6s0A 940 ld a,(vrecord) ;current virtual record to A + 02D9 B7 941 dmpos0: or a + 02DA 1F 942 rra + 02DB 0D 943 dec c + 02DC C2rD9s02 944 jp nz,dmpos0 + 945 ;A = shr(vrecord,blkshf) = vrecord/2**(sect/block) + 02DF 47 946 ld b,a ;save it for later addition +a 02E0 947 ld a,8 + 02E0 96 948 sub (hl) ;8-blkshf to accumulator + 02E1 4F 949 ld c,a ;extent shift count in register c + 02E2 3ArC6s0A 950 ld a,(extval) ;extent value ani extmsk + 02E5 951 dmpos1: + 952 ;blkshf = 3,4,5,6,7, C=5,4,3,2,1 + 953 ;shift is 4,3,2,1,0 + 02E5 0D 954 dec c + 02E6 CArEEs02 955 jp z,dmpos2 + 02E9 B7 956 or a + 02EA 17 957 rla + 02EB C3rE5s02 958 jp dmpos1 + 959 + 02EE 960 dmpos2: ;arrive here with A = shl(ext and extmsk,7-blkshf) + 02EE 80 961 add a,b ;add the previous shr(vrecord,blkshf) value + 962 ;A is one of the following values, depending upon alloc + 963 ;bks blkshf + 964 ;1k 3 v/8 + extval * 16 + 965 ;2k 4 v/16+ extval * 8 + 966 ;4k 5 v/32+ extval * 4 + 967 ;8k 6 v/64+ extval * 2 + 968 ;16k 7 v/128+extval * 1 + 02EF C9 969 ret ;with dm$position in A + 970 + 02F0 971 getdm: ;return disk map value from position given by BC + 02F0 2ArFCs01 972 ld hl,(info) ;base address of file control block +ua 02F3 973 ld de,dskmap + 02F3 19 974 add hl,de ;HL =.diskmap + 02F4 09 975 add hl,bc ;index by a single byte value + 02F5 3ArC6s0A 976 ld a,(single) ;single byte/map entry? + 02F8 B7 977 or a + 02F9 CArFEs02 978 jp z,getdmd ;get disk map single byte + 02FC 6E 979 ld l,(hl) +a 02FD 980 ld h,0 + 02FD C9 981 ret ;with HL=00bb + 02FE 982 getdmd: + 02FE 09 983 add hl,bc ;HL=.fcb(dm+i*2) + 984 ;double precision value returned + 02FF 5E 985 ld e,(hl) + 0300 23 986 inc hl + 0301 56 987 ld d,(hl) + 0302 EB 988 ex de,hl + 0303 C9 989 ret + 990 + 0304 991 index: ;compute disk block number from current fcb + 0304 CDrD5s02 992 call dm$position ;0...15 in register A + 0307 4F 993 ld c,a +a 0308 994 ld b,0 + 0308 CDrF0s02 995 call getdm ;value to HL + 030B 22rC6s0A 996 ld (arecord),hl + 030E C9 997 ret + 998 + 030F 999 allocated: ;called following index to see if block allocated + 030F 2ArC6s0A 1000 ld hl,(arecord) + 0312 7D 1001 ld a,l + 0313 B4 1002 or h + 0314 C9 1003 ret + 1004 + 0315 1005 atran: ;compute actual record address, assuming index called + 0315 3ArC6s0A 1006 ld a,(blkshf) ;shift count to reg A + 0318 2ArC6s0A 1007 ld hl,(arecord) + 031B 29 1008 atran0: add hl,hl + 031C 3D 1009 dec a + 031D C2r1Bs03 1010 jp nz,atran0 ;shl(arecord,blkshf) + 0320 22rC6s0A 1011 ld (arecord1),hl ;save shifted block # + 0323 3ArC6s0A 1012 ld a,(blkmsk) + 0326 4F 1013 ld c,a ;mask value to C + 0327 3ArC6s0A 1014 ld a,(vrecord) + 032A A1 1015 and c ;masked value in A + 032B B5 1016 or l + 032C 6F 1017 ld l,a ;to HL + 032D 22rC6s0A 1018 ld (arecord),hl ;arecord=HL or (vrecord and blkmsk) + 0330 C9 1019 ret + 1020 + 0331 1021 getexta: ;get current extent field address to A + 0331 2ArFCs01 1022 ld hl,(info) +ua 0334 1023 ld de,extnum + 0334 19 1024 add hl,de ;HL=.fcb(extnum) + 0335 C9 1025 ret + 1026 + 0336 1027 getfcba: ;compute reccnt and nxtrec addresses for get/setfcb + 0336 2ArFCs01 1028 ld hl,(info) +ua 0339 1029 ld de,reccnt + 0339 19 1030 add hl,de + 033A EB 1031 ex de,hl ;DE=.fcb(reccnt) +ua 033B 1032 ld hl,nxtrec-reccnt + 033B 19 1033 add hl,de ;HL=.fcb(nxtrec) + 033C C9 1034 ret + 1035 + 033D 1036 getfcb: ;set variables from currently addressed fcb + 033D CDr36s03 1037 call getfcba ;addresses in DE, HL + 0340 7E 1038 ld a,(hl) + 0341 32rC6s0A 1039 ld (vrecord),a ;vrecord=fcb(nxtrec) + 0344 EB 1040 ex de,hl + 0345 7E 1041 ld a,(hl) + 0346 32rC6s0A 1042 ld (rcount),a ;rcount=fcb(reccnt) + 0349 CDr31s03 1043 call getexta ;HL=.fcb(extnum) + 034C 3ArC6s0A 1044 ld a,(extmsk) ;extent mask to a + 034F A6 1045 and (hl) ;fcb(extnum) and extmsk + 0350 32rC6s0A 1046 ld (extval),a + 0353 C9 1047 ret + 1048 + 0354 1049 setfcb: ;place values back into current fcb + 0354 CDr36s03 1050 call getfcba ;addresses to DE, HL + 0357 3ArC6s0A 1051 ld a,(seqio) +a 035A 1052 cp 02 + 035A C2r5Es03 1053 jp nz,setfcb1 + 035D AF 1054 xor a ;check ranfill + 035E 1055 setfcb1: + 035E 4F 1056 ld c,a ;=1 if sequential i/o + 035F 3ArC6s0A 1057 ld a,(vrecord) + 0362 81 1058 add a,c + 0363 77 1059 ld (hl),a ;fcb(nxtrec)=vrecord+seqio + 0364 EB 1060 ex de,hl + 0365 3ArC6s0A 1061 ld a,(rcount) + 0368 77 1062 ld (hl),a ;fcb(reccnt)=rcount + 0369 C9 1063 ret + 1064 + 036A 1065 hlrotr: ;hl rotate right by amount C + 036A 0C 1066 inc c ;in case zero + 036B 1067 hlrotr0: + 036B 0D 1068 dec c + 036C C8 1069 ret z ;return when zero + 036D 7C 1070 ld a,h + 036E B7 1071 or a + 036F 1F 1072 rra + 0370 67 1073 ld h,a ;high byte + 0371 7D 1074 ld a,l + 0372 1F 1075 rra + 0373 6F 1076 ld l,a ;low byte + 0374 C3r6Bs03 1077 jp hlrotr0 + 1078 + 0377 1079 compute$cs: ;compute checksum for current directory buffer +ua 0377 1080 ld c,recsiz ;size of directory buffer + 0377 2ArC6s0A 1081 ld hl,(buffa) ;current directory buffer + 037A AF 1082 xor a ;clear checksum value + 037B 1083 computecs0: + 037B 86 1084 add a,(hl) + 037C 23 1085 inc hl + 037D 0D 1086 dec c ;cs=cs+buff(recsiz-C) + 037E C2r7Bs03 1087 jp nz,computecs0 + 0381 C9 1088 ret ;with checksum in A + 1089 + 0382 1090 hlrotl: ;rotate the mask in HL by amount in C + 0382 0C 1091 inc c ;may be zero + 0383 1092 hlrotl0: + 0383 0D 1093 dec c + 0384 C8 1094 ret z ;return if zero + 0385 29 1095 add hl,hl + 0386 C3r83s03 1096 jp hlrotl0 + 1097 + 0389 1098 set$cdisk: ;set a "1" value in curdsk position of BC + 0389 C5 1099 push bc ;save input parameter + 038A 3ArFCs01 1100 ld a,(curdsk) + 038D 4F 1101 ld c,a ;ready parameter for shift +a 038E 1102 ld hl,1 ;number to shift + 038E CDr82s03 1103 call hlrotl ;HL = mask to integrate + 0391 C1 1104 pop bc ;original mask + 0392 79 1105 ld a,c + 0393 B5 1106 or l + 0394 6F 1107 ld l,a + 0395 78 1108 ld a,b + 0396 B4 1109 or h + 0397 67 1110 ld h,a ;HL = mask or rol(1,curdsk) + 0398 C9 1111 ret + 1112 + 0399 1113 nowrite: ;return true if dir checksum difference occurred + 0399 2ArC6s0A 1114 ld hl,(rodsk) + 039C 3ArFCs01 1115 ld a,(curdsk) + 039F 4F 1116 ld c,a + 03A0 CDr6As03 1117 call hlrotr + 03A3 7D 1118 ld a,l +q 03A4 1119 and 1b + 03A4 C9 1120 ret ;non zero if nowrite + 1121 + 03A5 1122 set$ro: ;set current disk to read only +a 03A5 1123 ld hl,rodsk + 03A5 4E 1124 ld c,(hl) + 03A6 23 1125 inc hl + 03A7 46 1126 ld b,(hl) + 03A8 CDr89s03 1127 call set$cdisk ;sets bit to 1 + 03AB 22rC6s0A 1128 ld (rodsk),hl + 1129 ;high water mark in directory goes to max + 03AE 2ArC6s0A 1130 ld hl,(dirmax) + 03B1 23 1131 inc hl + 03B2 EB 1132 ex de,hl ;DE = directory max + 03B3 2ArC6s0A 1133 ld hl,(cdrmaxa) ;HL = .cdrmax + 03B6 73 1134 ld (hl),e + 03B7 23 1135 inc hl + 03B8 72 1136 ld (hl),d ;cdrmax = dirmax + 03B9 C9 1137 ret + 1138 + 03BA 1139 check$rodir: ;check current directory element for read/only status + 03BA CDrCBs03 1140 call getdptra ;address of element + 1141 + 03BD 1142 check$rofile: ;check current buff(dptr) or fcb(0) for r/o status +ua 03BD 1143 ld de,rofile + 03BD 19 1144 add hl,de ;offset to ro bit + 03BE 7E 1145 ld a,(hl) + 03BF 17 1146 rla + 03C0 D0 1147 ret nc ;return if not set +a 03C1 1148 ld hl,roferr + 03C1 C3rFCs01 1149 jp goerr + 1150 ; jp rof$error ;exit to read only disk message + 1151 + 1152 + 03C4 1153 check$write: ;check for write protected disk + 03C4 CDr99s03 1154 call nowrite + 03C7 C8 1155 ret z ;ok to write if not rodsk +a 03C8 1156 ld hl,roderr + 03C8 C3rFCs01 1157 jp goerr + 1158 ; jp rod$error ;read only disk error + 1159 + 03CB 1160 getdptra: ;compute the address of a directory element at + 1161 ;positon dptr in the buffer + 03CB 2ArC6s0A 1162 ld hl,(buffa) + 03CE 3ArC6s0A 1163 ld a,(dptr) + 03D1 1164 addh: ;HL = HL + A + 03D1 85 1165 add a,l + 03D2 6F 1166 ld l,a + 03D3 D0 1167 ret nc + 1168 ;overflow to H + 03D4 24 1169 inc h + 03D5 C9 1170 ret + 1171 + 1172 + 03D6 1173 getmodnum: ;compute the address of the module number + 1174 ;bring module number to accumulator + 1175 ;(high order bit is fwf (file write flag) + 03D6 2ArFCs01 1176 ld hl,(info) +ua 03D9 1177 ld de,modnum + 03D9 19 1178 add hl,de ;HL=.fcb(modnum) + 03DA 7E 1179 ld a,(hl) + 03DB C9 1180 ret ;A=fcb(modnum) + 1181 + 03DC 1182 clrmodnum: ;clear the module number field for user open/make + 03DC CDrD6s03 1183 call getmodnum +a 03DF 1184 ld (hl),0 ;fcb(modnum)=0 + 03DF C9 1185 ret + 1186 + 03E0 CDrD6s03 1187 setfwf: call getmodnum ;HL=.fcb(modnum), A=fcb(modnum) + 1188 ;set fwf (file write flag) to "1" +ua 03E3 1189 or fwfmsk + 03E3 77 1190 ld (hl),a ;fcb(modnum)=fcb(modnum) or 80h + 1191 ;also returns non zero in accumulator + 03E4 C9 1192 ret + 1193 + 1194 + 03E5 1195 compcdr: ;return cy if cdrmax > dcnt + 03E5 2ArC6s0A 1196 ld hl,(dcnt) + 03E8 EB 1197 ex de,hl ;DE = directory counter + 03E9 2ArC6s0A 1198 ld hl,(cdrmaxa) ;HL=.cdrmax + 03EC 7B 1199 ld a,e + 03ED 96 1200 sub (hl) ;low(dcnt) - low(cdrmax) + 03EE 23 1201 inc hl ;HL = .cdrmax+1 + 03EF 7A 1202 ld a,d + 03F0 9E 1203 sbc a,(hl) ;hig(dcnt) - hig(cdrmax) + 1204 ;condition dcnt - cdrmax produces cy if cdrmax>dcnt + 03F1 C9 1205 ret + 1206 + 03F2 1207 setcdr: ;if not (cdrmax > dcnt) then cdrmax = dcnt+1 + 03F2 CDrE5s03 1208 call compcdr + 03F5 D8 1209 ret c ;return if cdrmax > dcnt + 1210 ;otherwise, HL = .cdrmax+1, DE = dcnt + 03F6 13 1211 inc de + 03F7 72 1212 ld (hl),d + 03F8 2B 1213 dec hl + 03F9 73 1214 ld (hl),e + 03FA C9 1215 ret + 1216 + 03FB 1217 subdh: ;compute HL = DE - HL + 03FB 7B 1218 ld a,e + 03FC 95 1219 sub l + 03FD 6F 1220 ld l,a + 03FE 7A 1221 ld a,d + 03FF 9C 1222 sbc a,h + 0400 67 1223 ld h,a + 0401 C9 1224 ret + 1225 + 0402 1226 newchecksum: +ua 0402 1227 ld c,true ;drop through to compute new checksum + 0402 1228 checksum: ;compute current checksum record and update the + 1229 ;directory element if C=true, or check for = if not + 1230 ;drec < chksiz? + 0402 2ArC6s0A 1231 ld hl,(drec) + 0405 EB 1232 ex de,hl + 0406 2ArC6s0A 1233 ld hl,(chksiz) + 0409 CDrFBs03 1234 call subdh ;DE-HL + 040C D0 1235 ret nc ;skip checksum if past checksum vector size + 1236 ;drec < chksiz, so continue + 040D C5 1237 push bc ;save init flag + 040E CDr77s03 1238 call compute$cs ;check sum value to A + 0411 2ArC6s0A 1239 ld hl,(checka) ;address of check sum vector + 0414 EB 1240 ex de,hl + 0415 2ArC6s0A 1241 ld hl,(drec) ;value of drec + 0418 19 1242 add hl,de ;HL = .check(drec) + 0419 C1 1243 pop bc ;recall true=0ffh or false=00 to C + 041A 0C 1244 inc c ;0ffh produces zero flag + 041B CAr28s04 1245 jp z,initial$cs + 1246 ;not initializing, compare + 041E BE 1247 cp (hl) ;compute$cs=check(drec)? + 041F C8 1248 ret z ;no message if ok + 1249 ;checksum error, are we beyond + 1250 ;the end of the disk? + 0420 CDrE5s03 1251 call compcdr + 0423 D0 1252 ret nc ;no message if so + 0424 CDrA5s03 1253 call set$ro ;read/only disk set + 0427 C9 1254 ret + 1255 + 0428 1256 initial$cs: ;initializing the checksum + 0428 77 1257 ld (hl),a + 0429 C9 1258 ret + 1259 + 1260 + 042A 1261 wrdir: ;write the current directory entry, set checksum + 042A CDr02s04 1262 call newchecksum ;initialize entry + 042D CDr3Fs04 1263 call setdir ;directory dma +a 0430 1264 ld c,1 ;indicates a write directory operation + 0430 CDr57s02 1265 call wrbuff ;write the buffer + 0433 C3r3Cs04 1266 jp setdata ;to data dma address + 1267 ; ret + 0436 1268 rd$dir: ;read a directory entry into the directory buffer + 0436 CDr3Fs04 1269 call setdir ;directory dma + 0439 CDr51s02 1270 call rdbuff ;directory record loaded + 1271 ;jmp setdata to data dma address + 1272 ; ret + 043C 1273 setdata: ;set data dma address +a 043C 1274 ld hl,dmaad + 043C C3r3Fs04 1275 jp setdma ;to complete the call + 1276 + 043F 1277 setdir: ;set directory dma address +a 043F 1278 ld hl,buffa ;jmp setdma to complete call + 1279 + 043F 1280 setdma: ;HL=.dma address to set (i.e., buffa or dmaad) + 043F 4E 1281 ld c,(hl) + 0440 23 1282 inc hl + 0441 46 1283 ld b,(hl) ;parameter ready +u 0442 C3 00 00 1284 jp setdmaf + 1285 + 0445 1286 dir$to$user: ;copy the directory entry to the user buffer + 1287 ;after call to search or searchn by user code + 0445 2ArC6s0A 1288 ld hl,(buffa) + 0448 EB 1289 ex de,hl ;source is directory buffer + 0449 2ArC6s0A 1290 ld hl,(dmaad) ;destination is user dma address +ua 044C 1291 ld c,recsiz ;copy entire record + 044C C3r01s02 1292 jp move + 1293 ; ret + 1294 + 044F 1295 end$of$dir: ;return zero flag if at end of directory, non zero + 1296 ;if not at end (end of dir if dcnt = 0ffffh) +a 044F 1297 ld hl,dcnt + 044F 7E 1298 ld a,(hl) ;may be 0ffh + 0450 23 1299 inc hl + 0451 BE 1300 cp (hl) ;low(dcnt) = high(dcnt)? + 0452 C0 1301 ret nz ;non zero returned if different + 1302 ;high and low the same, = 0ffh? + 0453 3C 1303 inc a ;0ffh becomes 00 if so + 0454 C9 1304 ret + 1305 + 0455 1306 set$end$dir: ;set dcnt to the end of the directory +ua 0455 1307 ld hl,enddir + 0455 22rC6s0A 1308 ld (dcnt),hl + 0458 C9 1309 ret + 1310 + 0459 1311 read$dir: ;read next directory entry, with C=true if initializing + 0459 2ArC6s0A 1312 ld hl,(dirmax) + 045C EB 1313 ex de,hl ;in preparation for subtract + 045D 2ArC6s0A 1314 ld hl,(dcnt) + 0460 23 1315 inc hl + 0461 22rC6s0A 1316 ld (dcnt),hl ;dcnt=dcnt+1 + 1317 ;continue while dirmax >= dcnt (dirmax-dcnt no cy) + 0464 CDrFBs03 1318 call subdh ;DE-HL + 0467 D2r6Ds04 1319 jp nc,read$dir0 + 1320 ;yes, set dcnt to end of directory + 046A C3r55s04 1321 jp set$end$dir + 1322 ; ret + 1323 + 046D 1324 read$dir0: ;not at end of directory, seek next element + 1325 ;initialization flag is in C + 046D 3ArC6s0A 1326 ld a,(dcnt) +ua 0470 1327 and dskmsk ;low(dcnt) and dskmsk +ua 0470 1328 ld b,fcbshf ;to multiply by fcb size + 0470 1329 read$dir1: + 0470 87 1330 add a,a + 0471 05 1331 dec b + 0472 C2r70s04 1332 jp nz,read$dir1 + 1333 ;A = (low(dcnt) and dskmsk) shl fcbshf + 0475 32rC6s0A 1334 ld (dptr),a ;ready for next dir operation + 0478 B7 1335 or a + 0479 C0 1336 ret nz ;return if not a new record + 047A C5 1337 push bc ;save initialization flag C + 047B CDr5Fs02 1338 call seek$dir ;seek proper record + 047E CDr36s04 1339 call rd$dir ;read the directory record + 0481 C1 1340 pop bc ;recall initialization flag + 0482 C3r02s04 1341 jp checksum ;checksum the directory elt + 1342 ; ret + 1343 + 1344 + 0485 1345 getallocbit: ;given allocation vector position BC, return with byte + 1346 ;containing BC shifted so that the least significant + 1347 ;bit is in the low order accumulator position. HL is + 1348 ;the address of the byte for possible replacement in + 1349 ;memory upon return, and D contains the number of shifts + 1350 ;required to place the returned value back into position + 0485 79 1351 ld a,c +q 0486 1352 and 111b + 0486 3C 1353 inc a + 0487 5F 1354 ld e,a + 0488 57 1355 ld d,a + 1356 ;d and e both contain the number of bit positions to shift + 0489 79 1357 ld a,c + 048A 0F 1358 rrca + 048B 0F 1359 rrca + 048C 0F 1360 rrca +q 048D 1361 and 11111b + 048D 4F 1362 ld c,a ;C shr 3 to C + 048E 78 1363 ld a,b + 048F 87 1364 add a,a + 0490 87 1365 add a,a + 0491 87 1366 add a,a + 0492 87 1367 add a,a + 0493 87 1368 add a,a ;B shl 5 + 0494 B1 1369 or c + 0495 4F 1370 ld c,a ;bbbccccc to C + 0496 78 1371 ld a,b + 0497 0F 1372 rrca + 0498 0F 1373 rrca + 0499 0F 1374 rrca +q 049A 1375 and 11111b + 049A 47 1376 ld b,a ;BC shr 3 to BC + 049B 2ArC6s0A 1377 ld hl,(alloca) ;base address of allocation vector + 049E 09 1378 add hl,bc + 049F 7E 1379 ld a,(hl) ;byte to A, hl = .alloc(BC shr 3) + 1380 ;now move the bit to the low order position of A + 04A0 07 1381 rotl: rlca + 04A1 1D 1382 dec e + 04A2 C2rA0s04 1383 jp nz,rotl + 04A5 C9 1384 ret + 1385 + 1386 + 04A6 1387 set$alloc$bit: ;BC is the bit position of ALLOC to set or reset. The + 1388 ;value of the bit is in register E. + 04A6 D5 1389 push de + 04A7 CDr85s04 1390 call getallocbit ;shifted val A, count in D +q 04AA 1391 and 11111110b ;mask low bit to zero (may be set) + 04AA C1 1392 pop bc + 04AB B1 1393 or c ;low bit of C is masked into A + 1394 ; jp rotr ;to rotate back into proper position + 1395 ; ret + 04AC 1396 rotr: + 1397 ;byte value from ALLOC is in register A, with shift count + 1398 ;in register C (to place bit back into position), and + 1399 ;target ALLOC position in registers HL, rotate and replace + 04AC 0F 1400 rrca + 04AD 15 1401 dec d + 04AE C2rACs04 1402 jp nz,rotr ;back into position + 04B1 77 1403 ld (hl),a ;back to ALLOC + 04B2 C9 1404 ret + 1405 + 04B3 1406 scandm: ;scan the disk map addressed by dptr for non-zero + 1407 ;entries, the allocation vector entry corresponding + 1408 ;to a non-zero entry is set to the value of C (0,1) + 04B3 CDrCBs03 1409 call getdptra ;HL = buffa + dptr + 1410 ;HL addresses the beginning of the directory entry +ua 04B6 1411 ld de,dskmap + 04B6 19 1412 add hl,de ;hl now addresses the disk map + 04B7 C5 1413 push bc ;save the 0/1 bit to set +ua 04B8 1414 ld c,fcblen-dskmap+1;size of single byte disk map + 1 + 04B8 1415 scandm0: ;loop once for each disk map entry + 04B8 D1 1416 pop de ;recall bit parity + 04B9 0D 1417 dec c + 04BA C8 1418 ret z ;all done scanning? + 1419 ;no, get next entry for scan + 04BB D5 1420 push de ;replace bit parity + 04BC 3ArC6s0A 1421 ld a,(single) + 04BF B7 1422 or a + 04C0 CArC9s04 1423 jp z,scandm1 + 1424 ;single byte scan operation + 04C3 C5 1425 push bc ;save counter + 04C4 E5 1426 push hl ;save map address + 04C5 4E 1427 ld c,(hl) +a 04C6 1428 ld b,0 ;BC=block# + 04C6 C3rCFs04 1429 jp scandm2 + 1430 + 04C9 1431 scandm1: ;double byte scan operation + 04C9 0D 1432 dec c ;count for double byte + 04CA C5 1433 push bc ;save counter + 04CB 4E 1434 ld c,(hl) + 04CC 23 1435 inc hl + 04CD 46 1436 ld b,(hl) ;BC=block# + 04CE E5 1437 push hl ;save map address + 04CF 1438 scandm2: ;arrive here with BC=block#, E=0/1 + 04CF 79 1439 ld a,c + 04D0 B0 1440 or b ;skip if = 0000 + 04D1 CArDEs04 1441 jp z,scanm3 + 04D4 2ArC6s0A 1442 ld hl,(maxall) ;check invalid index + 04D7 7D 1443 ld a,l + 04D8 91 1444 sub c + 04D9 7C 1445 ld a,h + 04DA 98 1446 sbc a,b ;maxall - block# + 04DB D4rA6s04 1447 call nc,set$alloc$bit + 1448 ;bit set to 0/1 + 04DE E1 1449 scanm3: pop hl + 04DF 23 1450 inc hl ;to next bit position + 04E0 C1 1451 pop bc ;recall counter + 04E1 C3rB8s04 1452 jp scandm0 ;for another item + 1453 + 04E4 1454 initialize: ;initialize the current disk + 1455 ;lret = false ;set to true if $ file exists + 1456 ;compute the length of the allocation vector - 2 + 04E4 2ArC6s0A 1457 ld hl,(maxall) +a 04E7 1458 ld c,3 ;perform maxall/8 + 1459 ;number of bytes in alloc vector is (maxall/8)+1 + 04E7 CDr6As03 1460 call hlrotr + 04EA 23 1461 inc hl ;HL = maxall/8+1 + 04EB 44 1462 ld b,h + 04EC 4D 1463 ld c,l ;count down BC til zero + 04ED 2ArC6s0A 1464 ld hl,(alloca) ;base of allocation vector + 1465 ;fill the allocation vector with zeros + 04F0 1466 initial0: +a 04F0 1467 ld (hl),0 + 04F0 23 1468 inc hl ;alloc(i)=0 + 04F1 0B 1469 dec bc ;count length down + 04F2 78 1470 ld a,b + 04F3 B1 1471 or c + 04F4 C2rF0s04 1472 jp nz,initial0 + 1473 ;set the reserved space for the directory + 04F7 2ArC6s0A 1474 ld hl,(dirblk) + 04FA EB 1475 ex de,hl + 04FB 2ArC6s0A 1476 ld hl,(alloca) ;HL=.alloc() + 04FE 73 1477 ld (hl),e + 04FF 23 1478 inc hl + 0500 72 1479 ld (hl),d ;sets reserved directory blks + 1480 ;allocation vector initialized, home disk + 0501 CDr40s02 1481 call home + 1482 ;cdrmax = 3 (scans at least one directory record) + 0504 2ArC6s0A 1483 ld hl,(cdrmaxa) +a 0507 1484 ld (hl),3 + 0507 23 1485 inc hl +a 0508 1486 ld (hl),0 + 1487 ;cdrmax = 0000 + 0508 CDr55s04 1488 call set$end$dir ;dcnt = enddir + 1489 ;read directory entries and check for allocated storage + 050B 1490 initial2: +ua 050B 1491 ld c,true + 050B CDr59s04 1492 call read$dir + 050E CDr4Fs04 1493 call end$of$dir + 0511 C8 1494 ret z ;return if end of directory + 1495 ;not end of directory, valid entry? + 0512 CDrCBs03 1496 call getdptra ;HL = buffa + dptr +ua 0515 1497 ld a,empty + 0515 BE 1498 cp (hl) + 0516 CAr0Bs05 1499 jp z,initial2 ;go get another item + 1500 ;not empty, user code the same? + 0519 3ArFCs01 1501 ld a,(usrcode) + 051C BE 1502 cp (hl) + 051D C2r29s05 1503 jp nz,pdollar + 1504 ;same user code, check for '$' submit + 0520 23 1505 inc hl + 0521 7E 1506 ld a,(hl) ;first character +q 0522 1507 sub '$' ;dollar file? + 0522 C2r29s05 1508 jp nz,pdollar + 1509 ;dollar file found, mark in lret + 0525 3D 1510 dec a +u 0526 32 00 00 1511 ld (lret),a ;lret = 255 + 0529 1512 pdollar: ;now scan the disk map for allocated blocks +a 0529 1513 ld c,1 ;set to allocated + 0529 CDrB3s04 1514 call scandm + 052C CDrF2s03 1515 call setcdr ;set cdrmax to dcnt + 052F C3r0Bs05 1516 jp initial2 ;for another entry + 1517 + 0532 1518 copy$dirloc: ;copy directory location to lret following + 1519 ;delete, rename, ... ops + 0532 3ArC6s0A 1520 ld a,(dirloc) + 0535 C3rF5s01 1521 jp sta$ret + 1522 ; ret + 1523 + 0538 1524 compext: ;compare extent# in A with that in C, return nonzero + 1525 ;if they do not match + 0538 C5 1526 push bc ;save C's original value + 0539 F5 1527 push af + 053A 3ArC6s0A 1528 ld a,(extmsk) + 053D 2F 1529 cpl + 053E 47 1530 ld b,a + 1531 ;B has negated form of extent mask + 053F 79 1532 ld a,c + 0540 A0 1533 and b + 0541 4F 1534 ld c,a ;low bits removed from C + 0542 F1 1535 pop af + 0543 A0 1536 and b ;low bits removed from A + 0544 91 1537 sub c +ua 0545 1538 and maxext ;set flags + 0545 C1 1539 pop bc ;restore original values + 0546 C9 1540 ret + 1541 + 0547 1542 search: ;search for directory element of length C at info +ao 0547 1543 ld a,0ffh + 0547 32rC6s0A 1544 ld (dirloc),a ;changed if actually found +a 054A 1545 ld hl,searchl + 054A 71 1546 ld (hl),c ;searchl = C + 054B 2ArFCs01 1547 ld hl,(info) + 054E 22rC6s0A 1548 ld (searcha),hl ;searcha = info + 0551 CDr55s04 1549 call set$end$dir ;dcnt = enddir + 0554 CDr40s02 1550 call home ;to start at the beginning + 1551 ;(drop through to searchn) + 1552 + 0557 1553 searchn: ;search for the next directory element, assuming + 1554 ;a previous call on search which sets searcha and + 1555 ;searchl +ua 0557 1556 ld c,false + 0557 CDr59s04 1557 call read$dir ;read next dir element + 055A CDr4Fs04 1558 call end$of$dir + 055D CArABs05 1559 jp z,search$fin ;skip to end if so + 1560 ;not end of directory, scan for match + 0560 2ArC6s0A 1561 ld hl,(searcha) + 0563 EB 1562 ex de,hl ;DE=beginning of user fcb + 0564 1A 1563 ld a,(de) ;first character +ua 0565 1564 cp empty ;keep scanning if empty + 0565 CAr70s05 1565 jp z,searchnext + 1566 ;not empty, may be end of logical directory + 0568 D5 1567 push de ;save search address + 0569 CDrE5s03 1568 call compcdr ;past logical end? + 056C D1 1569 pop de ;recall address + 056D D2rABs05 1570 jp nc,search$fin ;artificial stop + 0570 1571 searchnext: + 0570 CDrCBs03 1572 call getdptra ;HL = buffa+dptr + 0573 3ArC6s0A 1573 ld a,(searchl) + 0576 4F 1574 ld c,a ;length of search to c +a 0577 1575 ld b,0 ;b counts up, c counts down + 0577 1576 searchloop: + 0577 79 1577 ld a,c + 0578 B7 1578 or a + 0579 CAr9Fs05 1579 jp z,endsearch + 057C 1A 1580 ld a,(de) +q 057D 1581 cp '?' + 057D CAr98s05 1582 jp z,searchok ;? matches all + 1583 ;scan next character if not ubytes + 0580 78 1584 ld a,b +ua 0581 1585 cp ubytes + 0581 CAr98s05 1586 jp z,searchok + 1587 ;not the ubytes field, extent field? +ua 0584 1588 cp extnum ;may be extent field + 0584 1A 1589 ld a,(de) ;fcb character + 0585 CAr8Fs05 1590 jp z,searchext ;skip to search extent + 0588 96 1591 sub (hl) +q 0589 1592 and 7fh ;mask-out flags/extent modulus + 0589 C2r57s05 1593 jp nz,searchn ;skip if not matched + 058C C3r98s05 1594 jp searchok ;matched character + 1595 + 058F 1596 searchext: ;A has fcb character + 1597 ;attempt an extent # match + 058F C5 1598 push bc ;save counters + 0590 4E 1599 ld c,(hl) ;directory character to c + 0591 CDr38s05 1600 call compext ;compare user/dir char + 0594 C1 1601 pop bc ;recall counters + 0595 C2r57s05 1602 jp nz,searchn ;skip if no match + 0598 1603 searchok: ;current character matches + 0598 13 1604 inc de + 0599 23 1605 inc hl + 059A 04 1606 inc b + 059B 0D 1607 dec c + 059C C3r77s05 1608 jp searchloop + 1609 + 059F 1610 endsearch: ;entire name matches, return dir position + 059F 3ArC6s0A 1611 ld a,(dcnt) +ua 05A2 1612 and dskmsk +u 05A2 32 00 00 1613 ld (lret),a + 1614 ;lret = low(dcnt) and 11b +a 05A5 1615 ld hl,dirloc + 05A5 7E 1616 ld a,(hl) + 05A6 17 1617 rla + 05A7 D0 1618 ret nc ;dirloc=0ffh? + 1619 ;yes, change it to 0 to mark as found + 05A8 AF 1620 xor a + 05A9 77 1621 ld (hl),a ;dirloc=0 + 05AA C9 1622 ret + 1623 + 05AB 1624 search$fin: ;end of directory, or empty name + 05AB CDr55s04 1625 call set$end$dir ;may be artifical end +a 05AE 1626 ld a,255 + 05AE C3rF5s01 1627 jp sta$ret + 1628 + 05B1 1629 delete: ;delete the currently addressed file + 05B1 CDrC4s03 1630 call check$write ;write protected? +ua 05B4 1631 ld c,extnum + 05B4 CDr47s05 1632 call search ;search through file type + 05B7 1633 delete0: + 1634 ;loop while directory matches + 05B7 CDr4Fs04 1635 call end$of$dir + 05BA C8 1636 ret z ;stop if end + 1637 ;set each non zero disk map entry to 0 + 1638 ;in the allocation vector + 1639 ;may be r/o file + 05BB CDrBAs03 1640 call check$rodir ;ro disk error if found + 05BE CDrCBs03 1641 call getdptra ;HL=.buff(dptr) +ua 05C1 1642 ld (hl),empty +a 05C1 1643 ld c,0 + 05C1 CDrB3s04 1644 call scandm ;alloc elts set to 0 + 05C4 CDr2As04 1645 call wrdir ;write the directory + 05C7 CDr57s05 1646 call searchn ;to next element + 05CA C3rB7s05 1647 jp delete0 ;for another record + 1648 + 05CD 1649 get$block: ;given allocation vector position BC, find the zero bit + 1650 ;closest to this position by searching left and right. + 1651 ;if found, set the bit to one and return the bit position + 1652 ;in hl. if not found (i.e., we pass 0 on the left, or + 1653 ;maxall on the right), return 0000 in hl + 05CD 50 1654 ld d,b + 05CE 59 1655 ld e,c ;copy of starting position to de + 05CF 1656 lefttst: + 05CF 79 1657 ld a,c + 05D0 B0 1658 or b + 05D1 CArE0s05 1659 jp z,righttst ;skip if left=0000 + 1660 ;left not at position zero, bit zero? + 05D4 0B 1661 dec bc + 05D5 D5 1662 push de + 05D6 C5 1663 push bc ;left,right pushed + 05D7 CDr85s04 1664 call getallocbit + 05DA 1F 1665 rra + 05DB D2rFBs05 1666 jp nc,retblock ;return block number if zero + 1667 ;bit is one, so try the right + 05DE C1 1668 pop bc + 05DF D1 1669 pop de ;left, right restored + 05E0 1670 righttst: + 05E0 2ArC6s0A 1671 ld hl,(maxall) ;value of maximum allocation# + 05E3 7B 1672 ld a,e + 05E4 95 1673 sub l + 05E5 7A 1674 ld a,d + 05E6 9C 1675 sbc a,h ;right=maxall? + 05E7 D2r03s06 1676 jp nc,retblock0 ;return block 0000 if so + 05EA 13 1677 inc de + 05EB C5 1678 push bc + 05EC D5 1679 push de ;left, right pushed + 05ED 42 1680 ld b,d + 05EE 4B 1681 ld c,e ;ready right for call + 05EF CDr85s04 1682 call getallocbit + 05F2 1F 1683 rra + 05F3 D2rFBs05 1684 jp nc,retblock ;return block number if zero + 05F6 D1 1685 pop de + 05F7 C1 1686 pop bc ;restore left and right pointers + 05F8 C3rCFs05 1687 jp lefttst ;for another attempt + 05FB 1688 retblock: + 05FB 17 1689 rla + 05FC 3C 1690 inc a ;bit back into position and set to 1 + 1691 ;d contains the number of shifts required to reposition + 05FD CDrACs04 1692 call rotr ;move bit back to position and store + 0600 E1 1693 pop hl + 0601 D1 1694 pop de ;HL returned value, DE discarded + 0602 C9 1695 ret + 1696 + 0603 1697 retblock0: ;cannot find an available bit, return 0000 + 0603 79 1698 ld a,c + 0604 B0 1699 or b + 0605 C2rCFs05 1700 jp nz,lefttst ;also at beginning +ao 0608 1701 ld hl,0000h + 0608 C9 1702 ret + 1703 + 0609 1704 copy$fcb: ;copy the entire file control block +a 0609 1705 ld c,0 +ua 0609 1706 ld e,fcblen ;start at 0, to fcblen-1 + 1707 ; jp copy$dir + 1708 + 0609 1709 copy$dir: ;copy fcb information starting at C for E bytes + 1710 ;into the currently addressed directory entry + 0609 D5 1711 push de ;save length for later +a 060A 1712 ld b,0 ;double index to BC + 060A 2ArFCs01 1713 ld hl,(info) ;HL = source for data + 060D 09 1714 add hl,bc + 060E EB 1715 ex de,hl ;DE=.fcb(C), source for copy + 060F CDrCBs03 1716 call getdptra ;HL=.buff(dptr), destination + 0612 C1 1717 pop bc ;DE=source, HL=dest, C=length + 0613 CDr01s02 1718 call move ;data moved + 0616 1719 seek$copy: ;enter from close to seek and copy current element + 0616 CDr5Fs02 1720 call seek$dir ;to the directory element + 0619 C3r2As04 1721 jp wrdir ;write the directory element + 1722 ; ret + 061C 1723 rename: ;rename the file described by the first half of + 1724 ;the currently addressed file control block. the + 1725 ;new name is contained in the last half of the + 1726 ;currently addressed file conrol block. the file + 1727 ;name and type are changed, but the reel number + 1728 ;is ignored. the user number is identical + 061C CDrC4s03 1729 call check$write ;may be write protected + 1730 ;search up to the extent field +ua 061F 1731 ld c,extnum + 061F CDr47s05 1732 call search + 1733 ;copy position 0 + 0622 2ArFCs01 1734 ld hl,(info) + 0625 7E 1735 ld a,(hl) ;HL=.fcb(0), A=fcb(0) +ua 0626 1736 ld de,dskmap + 0626 19 1737 add hl,de ;HL=.fcb(dskmap) + 0627 77 1738 ld (hl),a ;fcb(dskmap)=fcb(0) + 1739 ;assume the same disk drive for new named file + 0628 1740 rename0: + 0628 CDr4Fs04 1741 call end$of$dir + 062B C8 1742 ret z ;stop at end of dir + 1743 ;not end of directory, rename next element + 062C CDrBAs03 1744 call check$rodir ;may be read-only file +ua 062F 1745 ld c,dskmap +ua 062F 1746 ld e,extnum + 062F CDr09s06 1747 call copy$dir + 1748 ;element renamed, move to next + 0632 CDr57s05 1749 call searchn + 0635 C3r28s06 1750 jp rename0 + 1751 + 0638 1752 indicators: ;set file indicators for current fcb +ua 0638 1753 ld c,extnum + 0638 CDr47s05 1754 call search ;through file type + 063B CDr4Fs04 1755 indic0: call end$of$dir + 063E C8 1756 ret z ;stop at end of dir + 1757 ;not end of directory, continue to change +a 063F 1758 ld c,0 +ua 063F 1759 ld e,extnum ;copy name + 063F CDr09s06 1760 call copy$dir + 0642 CDr57s05 1761 call searchn + 0645 C3r3Bs06 1762 jp indic0 + 1763 + 0648 1764 open: ;search for the directory entry, copy to fcb +ua 0648 1765 ld c,namlen + 0648 CDr47s05 1766 call search + 064B CDr4Fs04 1767 call end$of$dir + 064E C8 1768 ret z ;return with lret=255 if end + 1769 ;not end of directory, copy fcb information + 064F 1770 open$copy: ;(referenced below to copy fcb info) + 064F CDr31s03 1771 call getexta + 0652 7E 1772 ld a,(hl) + 0653 F5 1773 push af + 0654 E5 1774 push hl ;save extent# + 0655 CDrCBs03 1775 call getdptra + 0658 EB 1776 ex de,hl ;DE = .buff(dptr) + 0659 2ArFCs01 1777 ld hl,(info) ;HL=.fcb(0) +ua 065C 1778 ld c,nxtrec ;length of move operation + 065C D5 1779 push de ;save .buff(dptr) + 065D CDr01s02 1780 call move ;from .buff(dptr) to .fcb(0) + 1781 ;note that entire fcb is copied, including indicators + 0660 CDrE0s03 1782 call setfwf ;sets file write flag + 0663 D1 1783 pop de +ua 0664 1784 ld hl,extnum + 0664 19 1785 add hl,de ;HL=.buff(dptr+extnum) + 0665 4E 1786 ld c,(hl) ;C = directory extent number +ua 0666 1787 ld hl,reccnt + 0666 19 1788 add hl,de ;HL=.buff(dptr+reccnt) + 0667 46 1789 ld b,(hl) ;B holds directory record count + 0668 E1 1790 pop hl + 0669 F1 1791 pop af + 066A 77 1792 ld (hl),a ;restore extent number + 1793 ;HL = .user extent#, B = dir rec cnt, C = dir extent# + 1794 ;if user ext < dir ext then user := 128 records + 1795 ;if user ext = dir ext then user := dir records + 1796 ;if user ext > dir ext then user := 0 records + 066B 79 1797 ld a,c + 066C BE 1798 cp (hl) + 066D 78 1799 ld a,b ;ready dir reccnt + 066E CAr74s06 1800 jp z,open$rcnt ;if same, user gets dir reccnt +a 0671 1801 ld a,0 + 0671 DAr74s06 1802 jp c,open$rcnt ;user is larger +a 0674 1803 ld a,128 ;directory is larger + 0674 1804 open$rcnt: ;A has record count to fill + 0674 2ArFCs01 1805 ld hl,(info) +ua 0677 1806 ld de,reccnt + 0677 19 1807 add hl,de + 0678 77 1808 ld (hl),a + 0679 C9 1809 ret + 1810 + 067A 1811 mergezero: ;HL = .fcb1(i), DE = .fcb2(i), + 1812 ;if fcb1(i) = 0 then fcb1(i) := fcb2(i) + 067A 7E 1813 ld a,(hl) + 067B 23 1814 inc hl + 067C B6 1815 or (hl) + 067D 2B 1816 dec hl + 067E C0 1817 ret nz ;return if = 0000 + 067F 1A 1818 ld a,(de) + 0680 77 1819 ld (hl),a + 0681 13 1820 inc de + 0682 23 1821 inc hl ;low byte copied + 0683 1A 1822 ld a,(de) + 0684 77 1823 ld (hl),a + 0685 1B 1824 dec de + 0686 2B 1825 dec hl ;back to input form + 0687 C9 1826 ret + 1827 + 0688 1828 close: ;locate the directory element and re-write it + 0688 AF 1829 xor a +u 0689 32 00 00 1830 ld (lret),a + 068C 32rC6s0A 1831 ld (dcnt),a + 068F 32rC7s0A 1832 ld (dcnt+1),a + 0692 CDr99s03 1833 call nowrite + 0695 C0 1834 ret nz ;skip close if r/o disk + 1835 ;check file write flag - 0 indicates written + 0696 CDrD6s03 1836 call getmodnum ;fcb(modnum) in A +ua 0699 1837 and fwfmsk + 0699 C0 1838 ret nz ;return if bit remains set +ua 069A 1839 ld c,namlen + 069A CDr47s05 1840 call search ;locate file + 069D CDr4Fs04 1841 call end$of$dir + 06A0 C8 1842 ret z ;return if not found + 1843 ;merge the disk map at info with that at buff(dptr) +ua 06A1 1844 ld bc,dskmap + 06A1 CDrCBs03 1845 call getdptra + 06A4 09 1846 add hl,bc + 06A5 EB 1847 ex de,hl ;DE is .buff(dptr+16) + 06A6 2ArFCs01 1848 ld hl,(info) + 06A9 09 1849 add hl,bc ;DE=.buff(dptr+16), HL=.fcb(16) +ua 06AA 1850 ld c,fcblen-dskmap;length of single byte dm + 06AA 3ArC6s0A 1851 merge0: ld a,(single) + 06AD B7 1852 or a + 06AE CArC5s06 1853 jp z,merged ;skip to double + 1854 ;this is a single byte map + 1855 ;if fcb(i) = 0 then fcb(i) = buff(i) + 1856 ;if buff(i) = 0 then buff(i) = fcb(i) + 1857 ;if fcb(i) <> buff(i) then error + 06B1 7E 1858 ld a,(hl) + 06B2 B7 1859 or a + 06B3 1A 1860 ld a,(de) + 06B4 C2rB8s06 1861 jp nz,fcbnzero + 1862 ;fcb(i) = 0 + 06B7 77 1863 ld (hl),a ;fcb(i) = buff(i) + 06B8 1864 fcbnzero: + 06B8 B7 1865 or a + 06B9 C2rBEs06 1866 jp nz,buffnzero + 1867 ;buff(i) = 0 + 06BC 7E 1868 ld a,(hl) + 06BD 12 1869 ld (de),a ;buff(i)=fcb(i) + 06BE 1870 buffnzero: + 06BE BE 1871 cp (hl) + 06BF C2rF4s06 1872 jp nz,mergerr ;fcb(i) = buff(i)? + 06C2 C3rDAs06 1873 jp dmset ;if merge ok + 1874 + 06C5 1875 merged: ;this is a double byte merge operation + 06C5 CDr7As06 1876 call mergezero ;buff = fcb if buff 0000 + 06C8 EB 1877 ex de,hl + 06C9 CDr7As06 1878 call mergezero + 06CC EB 1879 ex de,hl ;fcb = buff if fcb 0000 + 1880 ;they should be identical at this point + 06CD 1A 1881 ld a,(de) + 06CE BE 1882 cp (hl) + 06CF C2rF4s06 1883 jp nz,mergerr ;low same? + 06D2 13 1884 inc de + 06D3 23 1885 inc hl ;to high byte + 06D4 1A 1886 ld a,(de) + 06D5 BE 1887 cp (hl) + 06D6 C2rF4s06 1888 jp nz,mergerr ;high same? + 1889 ;merge operation ok for this pair + 06D9 0D 1890 dec c ;extra count for double byte + 06DA 13 1891 dmset: inc de + 06DB 23 1892 inc hl ;to next byte position + 06DC 0D 1893 dec c + 06DD C2rAAs06 1894 jp nz,merge0 ;for more + 1895 ;end of disk map merge, check record count + 1896 ;DE = .buff(dptr)+32, HL = .fcb(32) +ua 06E0 1897 ld bc,-(fcblen-extnum) + 06E0 09 1898 add hl,bc + 06E1 EB 1899 ex de,hl + 06E2 09 1900 add hl,bc + 1901 ;DE = .fcb(extnum), HL = .buff(dptr+extnum) + 06E3 1A 1902 ld a,(de) ;current user extent number + 1903 ;if fcb(ext) >= buff(fcb) then + 1904 ;buff(ext) := fcb(ext), buff(rec) := fcb(rec) + 06E4 BE 1905 cp (hl) + 06E5 DArEEs06 1906 jp c,endmerge + 1907 ;fcb extent number >= dir extent number + 06E8 77 1908 ld (hl),a ;buff(ext) = fcb(ext) + 1909 ;update directory record count field +ua 06E9 1910 ld bc,reccnt-extnum + 06E9 09 1911 add hl,bc + 06EA EB 1912 ex de,hl + 06EB 09 1913 add hl,bc + 1914 ;DE=.buff(reccnt), HL=.fcb(reccnt) + 06EC 7E 1915 ld a,(hl) + 06ED 12 1916 ld (de),a ;buff(reccnt)=fcb(reccnt) + 06EE 1917 endmerge: +ua 06EE 1918 ld a,true + 06EE 32rC6s0A 1919 ld (fcb$copied),a ;mark as copied + 06F1 C3r16s06 1920 jp seek$copy ;ok to "wrdir" here - 1.4 compat + 1921 ; ret + 1922 + 06F4 1923 mergerr: ;elements did not merge correctly +ua 06F4 1924 ld hl,lret + 06F4 35 1925 dec (hl) ;=255 non zero flag set + 06F5 C9 1926 ret + 1927 + 06F6 1928 make: ;create a new file by creating a directory entry + 1929 ;then opening the file + 06F6 CDrC4s03 1930 call check$write ;may be write protected + 06F9 2ArFCs01 1931 ld hl,(info) + 06FC E5 1932 push hl ;save fcb address, look for e5 +a 06FD 1933 ld hl,efcb + 06FD 22rFCs01 1934 ld (info),hl ;info = .empty +a 0700 1935 ld c,1 + 0700 CDr47s05 1936 call search ;length 1 match on empty entry + 0703 CDr4Fs04 1937 call end$of$dir ;zero flag set if no space + 0706 E1 1938 pop hl ;recall info address + 0707 22rFCs01 1939 ld (info),hl ;in case we return here + 070A C8 1940 ret z ;return with error condition 255 if not found + 070B EB 1941 ex de,hl ;DE = info address + 1942 ;clear the remainder of the fcb +ua 070C 1943 ld hl,namlen + 070C 19 1944 add hl,de ;HL=.fcb(namlen) +ua 070D 1945 ld c,fcblen-namlen ;number of bytes to fill + 070D AF 1946 xor a ;clear accumulator to 00 for fill + 070E 77 1947 make0: ld (hl),a + 070F 23 1948 inc hl + 0710 0D 1949 dec c + 0711 C2r0Es07 1950 jp nz,make0 +ua 0714 1951 ld hl,ubytes + 0714 19 1952 add hl,de ;HL = .fcb(ubytes) + 0715 77 1953 ld (hl),a ;fcb(ubytes) = 0 + 0716 CDrF2s03 1954 call setcdr ;may have extended the directory + 1955 ;now copy entry to the directory + 0719 CDr09s06 1956 call copy$fcb + 1957 ;and set the file write flag to "1" + 071C C3rE0s03 1958 jp setfwf + 1959 ; ret + 1960 + 071F 1961 open$reel: ;close the current extent, and open the next one + 1962 ;if possible. RMF is true if in read mode + 071F AF 1963 xor a + 0720 32rC6s0A 1964 ld (fcb$copied),a ;set true if actually copied + 0723 CDr88s06 1965 call close ;close current extent + 1966 ;lret remains at enddir if we cannot open the next ext + 0726 CDr4Fs04 1967 call end$of$dir + 0729 C8 1968 ret z ;return if end + 1969 ;increment extent number + 072A 2ArFCs01 1970 ld hl,(info) +ua 072D 1971 ld bc,extnum + 072D 09 1972 add hl,bc ;HL=.fcb(extnum) + 072E 7E 1973 ld a,(hl) + 072F 3C 1974 inc a +ua 0730 1975 and maxext + 0730 77 1976 ld (hl),a ;fcb(extnum)=++1 + 0731 CAr40s07 1977 jp z,open$mod ;move to next module if zero + 1978 ;may be in the same extent group + 0734 47 1979 ld b,a + 0735 3ArC6s0A 1980 ld a,(extmsk) + 0738 A0 1981 and b + 1982 ;if result is zero, then not in the same group +a 0739 1983 ld hl,fcb$copied ;true if the fcb was copied to directory + 0739 A6 1984 and (hl) ;produces a 00 in accumulator if not written + 073A CAr46s07 1985 jp z,open$reel0 ;go to next physical extent + 1986 ;result is non zero, so we must be in same logical ext + 073D C3r62s07 1987 jp open$reel1 ;to copy fcb information + 0740 1988 open$mod: ;extent number overflow, go to next module +ua 0740 1989 ld bc,modnum-extnum + 0740 09 1990 add hl,bc ;HL=.fcb(modnum) + 0741 34 1991 inc (hl) ;fcb(modnum)=++1 + 1992 ;module number incremented, check for overflow + 0742 7E 1993 ld a,(hl) +ua 0743 1994 and maxmod ;mask high order bits + 0743 CAr6Cs07 1995 jp z,open$r$err ;cannot overflow to zero + 1996 ;otherwise, ok to continue with new module + 0746 1997 open$reel0: +ua 0746 1998 ld c,namlen + 0746 CDr47s05 1999 call search ;next extent found? + 0749 CDr4Fs04 2000 call end$of$dir + 074C C2r62s07 2001 jp nz,open$reel1 + 2002 ;end of file encountered + 074F 3ArC6s0A 2003 ld a,(rmf) + 0752 3C 2004 inc a ;0ffh becomes 00 if read + 0753 CAr6Cs07 2005 jp z,open$r$err ;sets lret = 1 + 2006 ;try to extend the current file + 0756 CDrF6s06 2007 call make + 2008 ;cannot be end of directory + 0759 CDr4Fs04 2009 call end$of$dir + 075C CAr6Cs07 2010 jp z,open$r$err ;with lret = 1 + 075F C3r65s07 2011 jp open$reel2 + 2012 + 0762 2013 open$reel1: ;not end of file, open + 0762 CDr4Fs06 2014 call open$copy + 0765 2015 open$reel2: + 0765 CDr3Ds03 2016 call getfcb ;set parameters + 0768 AF 2017 xor a + 0769 C3rF5s01 2018 jp sta$ret ;lret = 0 + 2019 ; ret ;with lret = 0 + 2020 + 076C 2021 open$r$err: ;cannot move to next extent of this file + 076C CDrF9s01 2022 call setlret1 ;lret = 1 + 076F C3rE0s03 2023 jp setfwf ;ensure that it will not be closed + 2024 ; ret + 2025 + 0772 2026 seqdiskread: ;sequential disk read operation +a 0772 2027 ld a,1 + 0772 32rC6s0A 2028 ld (seqio),a + 2029 ;drop through to diskread + 2030 + 0775 2031 diskread: ;(may enter from seqdiskread) +ua 0775 2032 ld a,true + 0775 32rC6s0A 2033 ld (rmf),a ;read mode flag = true (open$reel) + 2034 ;read the next record from the current fcb + 0778 CDr3Ds03 2035 call getfcb ;sets parameters for the read + 077B 3ArC6s0A 2036 ld a,(vrecord) +a 077E 2037 ld hl,rcount + 077E BE 2038 cp (hl) ;vrecord-rcount + 2039 ;skip if rcount > vrecord + 077F DAr93s07 2040 jp c,recordok + 2041 ;not enough records in the extent + 2042 ;record count must be 128 to continue +a 0782 2043 cp 128 ;vrecord = 128? + 0782 C2rA8s07 2044 jp nz,diskeof ;skip if vrecord<>128 + 0785 CDr1Fs07 2045 call open$reel ;go to next extent if so + 0788 AF 2046 xor a + 0789 32rC6s0A 2047 ld (vrecord),a ;vrecord=00 + 2048 ;now check for open ok +u 078C 3A 00 00 2049 ld a,(lret) + 078F B7 2050 or a + 0790 C2rA8s07 2051 jp nz,diskeof ;stop at eof + 0793 2052 recordok: ;arrive with fcb addressing a record to read + 0793 CDr04s03 2053 call index + 2054 ;error 2 if reading unwritten data + 2055 ;(returns 1 to be compatible with 1.4) + 0796 CDr0Fs03 2056 call allocated ;arecord=0000? + 0799 CArA8s07 2057 jp z,diskeof + 2058 ;record has been allocated, read it + 079C CDr15s03 2059 call atran ;arecord now a disk address + 079F CDr6Bs02 2060 call seek ;to proper track,sector + 07A2 CDr51s02 2061 call rdbuff ;to dma address + 07A5 C3r54s03 2062 jp setfcb ;replace parameter + 2063 ; ret + 2064 + 07A8 2065 diskeof: + 07A8 C3rF9s01 2066 jp setlret1 ;lret = 1 + 2067 ; ret + 2068 + 07AB 2069 seqdiskwrite: ;sequential disk write +a 07AB 2070 ld a,1 + 07AB 32rC6s0A 2071 ld (seqio),a + 2072 ;drop through to diskwrite + 2073 + 07AE 2074 diskwrite: ;(may enter here from seqdiskwrite above) +ua 07AE 2075 ld a,false + 07AE 32rC6s0A 2076 ld (rmf),a ;read mode flag + 2077 ;write record to currently selected file + 07B1 CDrC4s03 2078 call check$write ;in case write protected + 07B4 2ArFCs01 2079 ld hl,(info) ;HL = .fcb(0) + 07B7 CDrBDs03 2080 call check$rofile ;may be a read-only file + 07BA CDr3Ds03 2081 call getfcb ;to set local parameters + 07BD 3ArC6s0A 2082 ld a,(vrecord) +ua 07C0 2083 cp lstrec+1 ;vrecord-128 + 2084 ;skip if vrecord > lstrec + 2085 ;vrecord = 128, cannot open next extent + 07C0 D2rF9s01 2086 jp nc,setlret1 ;lret=1 + 07C3 2087 diskwr0: ;can write the next record, so continue + 07C3 CDr04s03 2088 call index + 07C6 CDr0Fs03 2089 call allocated +a 07C9 2090 ld c,0 ;marked as normal write operation for wrbuff + 07C9 C2r07s08 2091 jp nz,diskwr1 + 2092 ;not allocated + 2093 ;the argument to getblock is the starting + 2094 ;position for the disk search, and should be + 2095 ;the last allocated block for this file, or + 2096 ;the value 0 if no space has been allocated + 07CC CDrD5s02 2097 call dm$position + 07CF 32rC6s0A 2098 ld (dminx),a ;save for later +ao 07D2 2099 ld bc,0000h ;may use block zero + 07D2 B7 2100 or a + 07D3 CArDDs07 2101 jp z,nopblock ;skip if no previous block + 2102 ;previous block exists at A + 07D6 4F 2103 ld c,a + 07D7 0B 2104 dec bc ;previous block # in BC + 07D8 CDrF0s02 2105 call getdm ;previous block # to HL + 07DB 44 2106 ld b,h + 07DC 4D 2107 ld c,l ;BC=prev block# + 07DD 2108 nopblock: ;BC = 0000, or previous block # + 07DD CDrCDs05 2109 call get$block ;block # to HL + 2110 ;arrive here with block# or zero + 07E0 7D 2111 ld a,l + 07E1 B4 2112 or h + 07E2 C2rE8s07 2113 jp nz,blockok + 2114 ;cannot find a block to allocate +a 07E5 2115 ld a,2 + 07E5 C3rF5s01 2116 jp sta$ret ;lret=2 + 2117 + 07E8 2118 blockok: ;allocated block number is in HL + 07E8 22rC6s0A 2119 ld (arecord),hl + 07EB EB 2120 ex de,hl ;block number to DE + 07EC 2ArFCs01 2121 ld hl,(info) +ua 07EF 2122 ld bc,dskmap + 07EF 09 2123 add hl,bc ;HL=.fcb(dskmap) + 07F0 3ArC6s0A 2124 ld a,(single) + 07F3 B7 2125 or a ;set flags for single byte dm + 07F4 3ArC6s0A 2126 ld a,(dminx) ;recall dm index + 07F7 CAr01s08 2127 jp z,allocwd ;skip if allocating word + 2128 ;allocating a byte value + 07FA CDrD1s03 2129 call addh + 07FD 73 2130 ld (hl),e ;single byte alloc + 07FE C3r07s08 2131 jp diskwru ;to continue + 2132 + 0801 2133 allocwd: ;allocate a word value + 0801 4F 2134 ld c,a +a 0802 2135 ld b,0 ;double(dminx) + 0802 09 2136 add hl,bc + 0803 09 2137 add hl,bc ;HL=.fcb(dminx*2) + 0804 73 2138 ld (hl),e + 0805 23 2139 inc hl + 0806 72 2140 ld (hl),d ;double wd + 0807 2141 diskwru: ;disk write to previously unallocated block +a 0807 2142 ld c,2 ;marked as unallocated write + 0807 2143 diskwr1: ;continue the write operation of no allocation error + 2144 ;C = 0 if normal write, 2 if to prev unalloc block +u 0807 3A 00 00 2145 ld a,(lret) + 080A B7 2146 or a + 080B C0 2147 ret nz ;stop if non zero returned value + 080C C5 2148 push bc ;save write flag + 080D CDr15s03 2149 call atran ;arecord set + 0810 3ArC6s0A 2150 ld a,(seqio) + 0813 3D 2151 dec a + 0814 3D 2152 dec a + 0815 C2r50s08 2153 jp nz,diskwr11 + 0818 C1 2154 pop bc + 0819 C5 2155 push bc + 081A 79 2156 ld a,c + 081B 3D 2157 dec a + 081C 3D 2158 dec a + 081D C2r50s08 2159 jp nz,diskwr11 ;old allocation + 0820 E5 2160 push hl ;arecord in hl ret from atran + 0821 2ArC6s0A 2161 ld hl,(buffa) + 0824 57 2162 ld d,a ;zero buffa & fill + 0825 77 2163 fill0: ld (hl),a + 0826 23 2164 inc hl + 0827 14 2165 inc d + 0828 F2r25s08 2166 jp p,fill0 + 082B CDr3Fs04 2167 call setdir + 082E 2ArC6s0A 2168 ld hl,(arecord1) +a 0831 2169 ld c,2 + 0831 22rC6s0A 2170 fill1: ld (arecord),hl + 0834 C5 2171 push bc + 0835 CDr6Bs02 2172 call seek + 0838 C1 2173 pop bc + 0839 CDr57s02 2174 call wrbuff ;write fill record + 083C 2ArC6s0A 2175 ld hl,(arecord) ;restore last record +a 083F 2176 ld c,0 ;change allocate flag + 083F 3ArC6s0A 2177 ld a,(blkmsk) + 0842 47 2178 ld b,a + 0843 A5 2179 and l + 0844 B8 2180 cp b + 0845 23 2181 inc hl + 0846 C2r31s08 2182 jp nz,fill1 ;cont until cluster is zeroed + 0849 E1 2183 pop hl + 084A 22rC6s0A 2184 ld (arecord),hl + 084D CDr3Cs04 2185 call setdata + 0850 2186 diskwr11: + 0850 CDr6Bs02 2187 call seek ;to proper file position + 0853 C1 2188 pop bc + 0854 C5 2189 push bc ;restore/save write flag (C=2 if new block) + 0855 CDr57s02 2190 call wrbuff ;written to disk + 0858 C1 2191 pop bc ;C = 2 if a new block was allocated, 0 if not + 2192 ;increment record count if rcount<=vrecord + 0859 3ArC6s0A 2193 ld a,(vrecord) +a 085C 2194 ld hl,rcount + 085C BE 2195 cp (hl) ;vrecord-rcount + 085D DAr62s08 2196 jp c,diskwr2 + 2197 ;rcount <= vrecord + 0860 77 2198 ld (hl),a + 0861 34 2199 inc (hl) ;rcount = vrecord+1 +a 0862 2200 ld c,2 ;mark as record count incremented + 0862 2201 diskwr2: ;A has vrecord, C=2 if new block or new record# + 0862 0D 2202 dec c + 0863 0D 2203 dec c + 0864 C2r6Ds08 2204 jp nz,noupdate + 0867 F5 2205 push af ;save vrecord value + 0868 CDrD6s03 2206 call getmodnum ;HL=.fcb(modnum), A=fcb(modnum) + 2207 ;reset the file write flag to mark as written fcb +uq 086B 2208 and (not fwfmsk) and 0ffh;bit reset + 086B 77 2209 ld (hl),a ;fcb(modnum) = fcb(modnum) and 7fh + 086C F1 2210 pop af ;restore vrecord + 086D 2211 noupdate: ;check for end of extent, if found attempt to open + 2212 ;next extent in preparation for next write +ua 086D 2213 cp lstrec ;vrecord=lstrec? + 086D C2r85s08 2214 jp nz,diskwr3 ;skip if not + 2215 ;may be random access write, if so we are done + 2216 ;change next + 0870 3ArC6s0A 2217 ld a,(seqio) +a 0873 2218 cp 1 + 0873 C2r85s08 2219 jp nz,diskwr3 ;skip next extent open op + 2220 ;update current fcb before going to next extent + 0876 CDr54s03 2221 call setfcb + 0879 CDr1Fs07 2222 call open$reel ;rmf=false + 2223 ;vrecord remains at lstrec causing eof if + 2224 ;no more directory space is available +ua 087C 2225 ld hl,lret + 087C 7E 2226 ld a,(hl) + 087D B7 2227 or a + 087E C2r85s08 2228 jp nz,nospace + 2229 ;space available, set vrecord=255 + 0881 3D 2230 dec a + 0882 32rC6s0A 2231 ld (vrecord),a ;goes to 00 next time + 0885 2232 nospace: +a 0885 2233 ld (hl),0 ;lret = 00 for returned value + 0885 2234 diskwr3: + 0885 C3r54s03 2235 jp setfcb ;replace parameters + 2236 ; ret + 2237 + 0888 2238 rseek: ;random access seek operation, C=0ffh if read mode + 2239 ;fcb is assumed to address an active file control block + 2240 ;(modnum has been set to 1100$0000b if previous bad seek) + 0888 AF 2241 xor a + 0889 32rC6s0A 2242 ld (seqio),a ;marked as random access operation + 088C C5 2243 rseek1: push bc ;save r/w flag + 088D 2ArFCs01 2244 ld hl,(info) + 0890 EB 2245 ex de,hl ;DE will hold base of fcb +ua 0891 2246 ld hl,ranrec + 0891 19 2247 add hl,de ;HL=.fcb(ranrec) + 0892 7E 2248 ld a,(hl) +q 0893 2249 and 7fh + 0893 F5 2250 push af ;record number + 0894 7E 2251 ld a,(hl) + 0895 17 2252 rla ;cy=lsb of extent# + 0896 23 2253 inc hl + 0897 7E 2254 ld a,(hl) + 0898 17 2255 rla +q 0899 2256 and 11111b ;A=ext# + 0899 4F 2257 ld c,a ;C holds extent number, record stacked + 089A 7E 2258 ld a,(hl) + 089B 1F 2259 rra + 089C 1F 2260 rra + 089D 1F 2261 rra + 089E 1F 2262 rra +q 089F 2263 and 1111b ;mod# + 089F 47 2264 ld b,a ;B holds module#, C holds ext# + 08A0 F1 2265 pop af ;recall sought record # + 2266 ;check to insure that high byte of ran rec = 00 + 08A1 23 2267 inc hl + 08A2 6E 2268 ld l,(hl) ;l=high byte (must be 00) + 08A3 2C 2269 inc l + 08A4 2D 2270 dec l +a 08A5 2271 ld l,6 ;zero flag, l=6 + 2272 ;produce error 6, seek past physical eod + 08A5 C2rECs08 2273 jp nz,seekerr + 2274 ;otherwise, high byte = 0, A = sought record +ua 08A8 2275 ld hl,nxtrec + 08A8 19 2276 add hl,de ;HL = .fcb(nxtrec) + 08A9 77 2277 ld (hl),a ;sought rec# stored away + 2278 ;arrive here with B=mod#, C=ext#, DE=.fcb, rec stored + 2279 ;the r/w flag is still stacked. compare fcb values +ua 08AA 2280 ld hl,extnum + 08AA 19 2281 add hl,de + 08AB 79 2282 ld a,c ;A=seek ext# + 08AC 96 2283 sub (hl) + 08AD C2rB6s08 2284 jp nz,ranclose ;tests for = extents + 2285 ;extents match, check mod# +ua 08B0 2286 ld hl,modnum + 08B0 19 2287 add hl,de + 08B1 78 2288 ld a,b ;B=seek mod# + 2289 ;could be overflow at eof, producing module# + 2290 ;of 90H or 10H, so compare all but fwf + 08B2 96 2291 sub (hl) +q 08B3 2292 and 7fh + 08B3 CArE2s08 2293 jp z,seekok ;same? + 08B6 2294 ranclose: + 08B6 C5 2295 push bc + 08B7 D5 2296 push de ;save seek mod#,ext#, .fcb + 08B8 CDr88s06 2297 call close ;current extent closed + 08BB D1 2298 pop de + 08BC C1 2299 pop bc ;recall parameters and fill +a 08BD 2300 ld l,3 ;cannot close error #3 +u 08BD 3A 00 00 2301 ld a,(lret) + 08C0 3C 2302 inc a + 08C1 CArE7s08 2303 jp z,badseek +ua 08C4 2304 ld hl,extnum + 08C4 19 2305 add hl,de + 08C5 71 2306 ld (hl),c ;fcb(extnum)=ext# +ua 08C6 2307 ld hl,modnum + 08C6 19 2308 add hl,de + 08C7 70 2309 ld (hl),b ;fcb(modnum)=mod# + 08C8 CDr48s06 2310 call open ;is the file present? +u 08CB 3A 00 00 2311 ld a,(lret) + 08CE 3C 2312 inc a + 08CF C2rE2s08 2313 jp nz,seekok ;open successful? + 2314 ;cannot open the file, read mode? + 08D2 C1 2315 pop bc ;r/w flag to c (=0ffh if read) + 08D3 C5 2316 push bc ;everyone expects this item stacked +a 08D4 2317 ld l,4 ;seek to unwritten extent #4 + 08D4 0C 2318 inc c ;becomes 00 if read operation + 08D5 CArE7s08 2319 jp z,badseek ;skip to error if read operation + 2320 ;write operation, make new extent + 08D8 CDrF6s06 2321 call make +a 08DB 2322 ld l,5 ;cannot create new extent #5 +u 08DB 3A 00 00 2323 ld a,(lret) + 08DE 3C 2324 inc a + 08DF CArE7s08 2325 jp z,badseek ;no dir space + 2326 ;file make operation successful + 08E2 2327 seekok: + 08E2 C1 2328 pop bc ;discard r/w flag + 08E3 AF 2329 xor a + 08E4 C3rF5s01 2330 jp sta$ret ;with zero set + 08E7 2331 badseek: ;fcb no longer contains a valid fcb, mark + 2332 ;with 1100$000b in modnum field so that it + 2333 ;appears as overflow with file write flag set + 08E7 E5 2334 push hl ;save error flag + 08E8 CDrD6s03 2335 call getmodnum ;HL = .modnum +ao 08EB 2336 ld (hl),11000000b + 08EB E1 2337 pop hl ;and drop through + 08EC 2338 seekerr: + 08EC C1 2339 pop bc ;discard r/w flag + 08ED 7D 2340 ld a,l +u 08EE 32 00 00 2341 ld (lret),a ;lret=#, nonzero + 2342 ;setfwf returns non-zero accumulator for err + 08F1 C3rE0s03 2343 jp setfwf ;flag set, so subsequent close ok + 2344 ; ret + 2345 + 08F4 2346 randiskread: ;random disk read operation +ua 08F4 2347 ld c,true ;marked as read operation + 08F4 CDr88s08 2348 call rseek + 08F7 CCr75s07 2349 call z,diskread ;if seek successful + 08FA C9 2350 ret + 2351 + 08FB 2352 randiskwrite: ;random disk write operation +ua 08FB 2353 ld c,false ;marked as write operation + 08FB CDr88s08 2354 call rseek + 08FE CCrAEs07 2355 call z,diskwrite ;if seek successful + 0901 C9 2356 ret + 2357 + 0902 2358 compute$rr: ;compute random record position for getfilesize/setrandom + 0902 EB 2359 ex de,hl + 0903 19 2360 add hl,de + 2361 ;DE=.buf(dptr) or .fcb(0), HL = .f(nxtrec/reccnt) + 0904 4E 2362 ld c,(hl) +a 0905 2363 ld b,0 ;BC = 0000 0000 ?rrr rrrr +ua 0905 2364 ld hl,extnum + 0905 19 2365 add hl,de + 0906 7E 2366 ld a,(hl) + 0907 0F 2367 rrca +q 0908 2368 and 80h ;A=e000 0000 + 0908 81 2369 add a,c + 0909 4F 2370 ld c,a +a 090A 2371 ld a,0 + 090A 88 2372 adc a,b + 090B 47 2373 ld b,a + 2374 ;BC = 0000 000? errrr rrrr + 090C 7E 2375 ld a,(hl) + 090D 0F 2376 rrca +q 090E 2377 and 0fh + 090E 80 2378 add a,b + 090F 47 2379 ld b,a + 2380 ;BC = 000? eeee errrr rrrr +ua 0910 2381 ld hl,modnum + 0910 19 2382 add hl,de + 0911 7E 2383 ld a,(hl) ;A=XXX? mmmm + 0912 87 2384 add a,a + 0913 87 2385 add a,a + 0914 87 2386 add a,a + 0915 87 2387 add a,a ;cy=? A=mmmm 0000 + 0916 F5 2388 push af + 0917 80 2389 add a,b + 0918 47 2390 ld b,a + 2391 ;cy=?, BC = mmmm eeee errr rrrr + 0919 F5 2392 push af ;possible second carry + 091A E1 2393 pop hl ;cy = lsb of L + 091B 7D 2394 ld a,l ;cy = lsb of A + 091C E1 2395 pop hl ;cy = lsb of L + 091D B5 2396 or l ;cy/cy = lsb of A +a 091E 2397 and 1 ;A = 0000 000? possible carry-out + 091E C9 2398 ret + 2399 + 091F 2400 getfilesize: ;compute logical file size for current fcb +ua 091F 2401 ld c,extnum + 091F CDr47s05 2402 call search + 2403 ;zero the receiving ranrec field + 0922 2ArFCs01 2404 ld hl,(info) +ua 0925 2405 ld de,ranrec + 0925 19 2406 add hl,de + 0926 E5 2407 push hl ;save position + 0927 72 2408 ld (hl),d + 0928 23 2409 inc hl + 0929 72 2410 ld (hl),d + 092A 23 2411 inc hl + 092B 72 2412 ld (hl),d ;=00 00 00 + 092C 2413 getsize: + 092C CDr4Fs04 2414 call end$of$dir + 092F CAr51s09 2415 jp z,setsize + 2416 ;current fcb addressed by dptr + 0932 CDrCBs03 2417 call getdptra +ua 0935 2418 ld de,reccnt ;ready for compute size + 0935 CDr02s09 2419 call compute$rr + 2420 ;A=0000 000? BC = mmmm eeee errr rrrr + 2421 ;compare with memory, larger? + 0938 E1 2422 pop hl + 0939 E5 2423 push hl ;recall, replace .fcb(ranrec) + 093A 5F 2424 ld e,a ;save cy + 093B 79 2425 ld a,c + 093C 96 2426 sub (hl) + 093D 23 2427 inc hl ;ls byte + 093E 78 2428 ld a,b + 093F 9E 2429 sbc a,(hl) + 0940 23 2430 inc hl ;middle byte + 0941 7B 2431 ld a,e + 0942 9E 2432 sbc a,(hl) ;carry if .fcb(ranrec) > directory + 0943 DAr4Bs09 2433 jp c,getnextsize ;for another try + 2434 ;fcb is less or equal, fill from directory + 0946 73 2435 ld (hl),e + 0947 2B 2436 dec hl + 0948 70 2437 ld (hl),b + 0949 2B 2438 dec hl + 094A 71 2439 ld (hl),c + 094B 2440 getnextsize: + 094B CDr57s05 2441 call searchn + 094E C3r2Cs09 2442 jp getsize + 2443 + 0951 2444 setsize: + 0951 E1 2445 pop hl ;discard .fcb(ranrec) + 0952 C9 2446 ret + 2447 + 0953 2448 setrandom: ;set random record from the current file control block + 0953 2ArFCs01 2449 ld hl,(info) +ua 0956 2450 ld de,nxtrec ;ready params for computesize + 0956 CDr02s09 2451 call compute$rr ;DE=info, A=cy, BC=mmmm eeee errr rrrr +ua 0959 2452 ld hl,ranrec + 0959 19 2453 add hl,de ;HL = .fcb(ranrec) + 095A 71 2454 ld (hl),c + 095B 23 2455 inc hl + 095C 70 2456 ld (hl),b + 095D 23 2457 inc hl + 095E 77 2458 ld (hl),a ;to ranrec + 095F C9 2459 ret + 2460 + 0960 2461 select: ;select disk info for subsequent input or output ops + 0960 2ArC6s0A 2462 ld hl,(dlog) + 0963 3ArFCs01 2463 ld a,(curdsk) + 0966 4F 2464 ld c,a + 0967 CDr6As03 2465 call hlrotr + 096A E5 2466 push hl + 096B EB 2467 ex de,hl ;save it for test below, send to seldsk + 096C CDr0Bs02 2468 call selectdisk + 096F E1 2469 pop hl ;recall dlog vector + 0970 CCrFCs01 2470 call z,sel$error ;returns true if select ok + 2471 ;is the disk logged in? + 0973 7D 2472 ld a,l + 0974 1F 2473 rra + 0975 D8 2474 ret c ;return if bit is set + 2475 ;disk not logged in, set bit and initialize + 0976 2ArC6s0A 2476 ld hl,(dlog) + 0979 4D 2477 ld c,l + 097A 44 2478 ld b,h ;call ready + 097B CDr89s03 2479 call set$cdisk + 097E 22rC6s0A 2480 ld (dlog),hl ;dlog=set$cdisk(dlog) + 0981 C3rE4s04 2481 jp initialize + 2482 ; ret + 2483 + 0984 2484 curselect: + 0984 3ArC6s0A 2485 ld a,(linfo) +a 0987 2486 ld hl,curdsk + 0987 BE 2487 cp (hl) + 0988 C8 2488 ret z ;skip if linfo=curdsk + 0989 77 2489 ld (hl),a ;curdsk=info + 098A C3r60s09 2490 jp select + 2491 ; ret + 2492 + 098D 2493 reselect: ;check current fcb to see if reselection necessary +ua 098D 2494 ld a,true + 098D 32rC6s0A 2495 ld (resel),a ;mark possible reselect + 0990 2ArFCs01 2496 ld hl,(info) + 0993 7E 2497 ld a,(hl) ;drive select code +q 0994 2498 and 11111b ;non zero is auto drive select + 0994 3D 2499 dec a ;drive code normalized to 0..30, or 255 + 0995 32rC6s0A 2500 ld (linfo),a ;save drive code +a 0998 2501 cp 30 + 0998 D2rA9s09 2502 jp nc,noselect + 2503 ;auto select function, save curdsk + 099B 3ArFCs01 2504 ld a,(curdsk) + 099E 32rC6s0A 2505 ld (olddsk),a ;olddsk=curdsk + 09A1 7E 2506 ld a,(hl) + 09A2 32rC6s0A 2507 ld (fcbdsk),a ;save drive code +q 09A5 2508 and 11100000b + 09A5 77 2509 ld (hl),a ;preserve hi bits + 09A6 CDr84s09 2510 call curselect + 09A9 2511 noselect: ;set user code + 09A9 3ArFCs01 2512 ld a,(usrcode) ;0...31 + 09AC 2ArFCs01 2513 ld hl,(info) + 09AF B6 2514 or (hl) + 09B0 77 2515 ld (hl),a + 09B1 C9 2516 ret + 2517 + 2518 ; individual function handlers + 09B2 2519 func12: ;return version number +ua 09B2 2520 ld a,dvers + 09B2 C3rF5s01 2521 jp sta$ret ;lret = dvers (high = 00) + 2522 ; ret + 2523 ; jp goback + 2524 + 09B5 2525 func13: ;reset disk system - initialize to disk 0 +a 09B5 2526 ld hl,0 + 09B5 22rC6s0A 2527 ld (rodsk),hl + 09B8 22rC6s0A 2528 ld (dlog),hl + 09BB AF 2529 xor a + 09BC 32rFCs01 2530 ld (curdsk),a ;note that usrcode remains unchanged +ua 09BF 2531 ld hl,tbuff + 09BF 22rC6s0A 2532 ld (dmaad),hl ;dmaad = tbuff + 09C2 CDr3Cs04 2533 call setdata ;to data dma address + 09C5 C3r60s09 2534 jp select + 2535 ; ret + 2536 ; jp goback + 2537 +o 09C8 2538 func14 equ curselect ;select disk info + 2539 ; ret + 2540 ; jp goback + 2541 + 09C8 2542 func15: ;open file + 09C8 CDrDCs03 2543 call clrmodnum ;clear the module number + 09CB CDr8Ds09 2544 call reselect + 09CE C3r48s06 2545 jp open + 2546 ; ret + 2547 ; jp goback + 2548 + 09D1 2549 func16: ;close file + 09D1 CDr8Ds09 2550 call reselect + 09D4 C3r88s06 2551 jp close + 2552 ; ret + 2553 ; jp goback + 2554 + 09D7 2555 func17: ;search for first occurrence of a file +a 09D7 2556 ld c,0 ;length assuming '?' true + 09D7 EB 2557 ex de,hl ;was lhld info + 09D8 7E 2558 ld a,(hl) +q 09D9 2559 cp '?' ;no reselect if ? + 09D9 CArE6s09 2560 jp z,qselect ;skip reselect if so + 2561 ;normal search + 09DC CDr31s03 2562 call getexta + 09DF 7E 2563 ld a,(hl) +q 09E0 2564 cp '?' ; + 09E0 C4rDCs03 2565 call nz,clrmodnum ;module number zeroed + 09E3 CDr8Ds09 2566 call reselect +ua 09E6 2567 ld c,namlen + 09E6 2568 qselect: + 09E6 CDr47s05 2569 call search + 09E9 C3r45s04 2570 jp dir$to$user ;copy directory entry to user + 2571 ; ret + 2572 ; jp goback + 2573 + 09EC 2574 func18: ;search for next occurrence of a file name + 09EC 2ArC6s0A 2575 ld hl,(searcha) + 09EF 22rFCs01 2576 ld (info),hl + 09F2 CDr8Ds09 2577 call reselect + 09F5 CDr57s05 2578 call searchn + 09F8 C3r45s04 2579 jp dir$to$user ;copy directory entry to user + 2580 ; ret + 2581 ; jp goback + 2582 + 09FB 2583 func19: ;delete a file + 09FB CDr8Ds09 2584 call reselect + 09FE CDrB1s05 2585 call delete + 0A01 C3r32s05 2586 jp copy$dirloc + 2587 ; ret + 2588 ; jp goback + 2589 + 0A04 2590 func20: ;read a file + 0A04 CDr8Ds09 2591 call reselect + 0A07 C3r72s07 2592 jp seqdiskread + 2593 ; jp goback + 2594 + 0A0A 2595 func21: ;write a file + 0A0A CDr8Ds09 2596 call reselect + 0A0D C3rABs07 2597 jp seqdiskwrite + 2598 ; jp goback + 2599 + 0A10 2600 func22: ;make a file + 0A10 CDrDCs03 2601 call clrmodnum + 0A13 CDr8Ds09 2602 call reselect + 0A16 C3rF6s06 2603 jp make + 2604 ; ret + 2605 ; jp goback + 2606 + 0A19 2607 func23: ;rename a file + 0A19 CDr8Ds09 2608 call reselect + 0A1C CDr1Cs06 2609 call rename + 0A1F C3r32s05 2610 jp copy$dirloc + 2611 ; ret + 2612 ; jp goback + 2613 + 0A22 2614 func24: ;return the login vector + 0A22 2ArC6s0A 2615 ld hl,(dlog) + 0A25 C3r4Ds0A 2616 jp sthl$ret + 2617 ; ret + 2618 ; jp goback + 2619 + 0A28 2620 func25: ;return selected disk number + 0A28 3ArFCs01 2621 ld a,(curdsk) + 0A2B C3rF5s01 2622 jp sta$ret + 2623 ; ret + 2624 ; jp goback + 2625 + 0A2E 2626 func26: ;set the subsequent dma address to info + 0A2E EB 2627 ex de,hl ;was lhld info + 0A2F 22rC6s0A 2628 ld (dmaad),hl ;dmaad = info + 0A32 C3r3Cs04 2629 jp setdata ;to data dma address + 2630 ; ret + 2631 ; jp goback + 2632 + 0A35 2633 func27: ;return the login vector address + 0A35 2ArC6s0A 2634 ld hl,(alloca) + 0A38 C3r4Ds0A 2635 jp sthl$ret + 2636 ; ret + 2637 ; jp goback + 2638 +o 0A3B 2639 func28 equ set$ro + 2640 ;write protect current disk + 2641 ; ret + 2642 ; jp goback + 2643 + 0A3B 2644 func29: ;return r/o bit vector + 0A3B 2ArC6s0A 2645 ld hl,(rodsk) + 0A3E C3r4Ds0A 2646 jp sthl$ret + 2647 ; ret + 2648 ; jp goback + 2649 + 0A41 2650 func30: ;set file indicators + 0A41 CDr8Ds09 2651 call reselect + 0A44 CDr38s06 2652 call indicators + 0A47 C3r32s05 2653 jp copy$dirloc ;lret=dirloc + 2654 ; ret + 2655 ; jp goback + 2656 + 0A4A 2657 func31: ;return address of disk parameter block + 0A4A 2ArC6s0A 2658 ld hl,(dpbaddr) + 0A4D 2659 sthl$ret: + 0A4D 22rFCs01 2660 ld (aret),hl + 0A50 C9 2661 ret + 2662 ; jp goback + 2663 + 0A51 2664 func32: ;set user code + 0A51 3ArC6s0A 2665 ld a,(linfo) +q 0A54 2666 cp 0ffh + 0A54 C2r5Ds0A 2667 jp nz,setusrcode + 2668 ;interrogate user code instead + 0A57 3ArFCs01 2669 ld a,(usrcode) + 0A5A C3rF5s01 2670 jp sta$ret ;lret=usrcode + 2671 ; ret + 2672 ; jp goback + 2673 + 0A5D 2674 setusrcode: +q 0A5D 2675 and 1fh + 0A5D 32rFCs01 2676 ld (usrcode),a + 0A60 C9 2677 ret + 2678 ; jp goback + 2679 + 0A61 2680 func33: ;random disk read operation + 0A61 CDr8Ds09 2681 call reselect + 0A64 C3rF4s08 2682 jp randiskread ;to perform the disk read + 2683 ; ret + 2684 ; jp goback + 2685 + 0A67 2686 func34: ;random disk write operation + 0A67 CDr8Ds09 2687 call reselect + 0A6A C3rFBs08 2688 jp randiskwrite ;to perform the disk write + 2689 ; ret + 2690 ; jp goback + 2691 + 0A6D 2692 func35: ;return file size (0-65536) + 0A6D CDr8Ds09 2693 call reselect + 0A70 C3r1Fs09 2694 jp getfilesize + 2695 ; ret + 2696 ; jp goback + 2697 +o 0A73 2698 func36 equ setrandom ;set random record + 2699 ; ret + 2700 ; jp goback + 2701 + 0A73 2ArFCs01 2702 func37: ld hl,(info) + 0A76 7D 2703 ld a,l + 0A77 2F 2704 cpl + 0A78 5F 2705 ld e,a + 0A79 7C 2706 ld a,h + 0A7A 2F 2707 cpl + 0A7B 2ArC6s0A 2708 ld hl,(dlog) + 0A7E A4 2709 and h + 0A7F 57 2710 ld d,a + 0A80 7D 2711 ld a,l + 0A81 A3 2712 and e + 0A82 5F 2713 ld e,a + 0A83 2ArC6s0A 2714 ld hl,(rodsk) + 0A86 EB 2715 ex de,hl + 0A87 22rC6s0A 2716 ld (dlog),hl + 0A8A 7D 2717 ld a,l + 0A8B A3 2718 and e + 0A8C 6F 2719 ld l,a + 0A8D 7C 2720 ld a,h + 0A8E A2 2721 and d + 0A8F 67 2722 ld h,a + 0A90 22rC6s0A 2723 ld (rodsk),hl + 0A93 C9 2724 ret + 2725 + 0A94 2726 goback: ;arrive here at end of processing to return to user + 0A94 3ArC6s0A 2727 ld a,(resel) + 0A97 B7 2728 or a + 0A98 CArAFs0A 2729 jp z,retmon + 2730 ;reselection may have taken place + 0A9B 2ArFCs01 2731 ld hl,(info) +a 0A9E 2732 ld (hl),0 ;fcb(0)=0 + 0A9E 3ArC6s0A 2733 ld a,(fcbdsk) + 0AA1 B7 2734 or a + 0AA2 CArAFs0A 2735 jp z,retmon + 2736 ;restore disk number + 0AA5 77 2737 ld (hl),a ;fcb(0)=fcbdsk + 0AA6 3ArC6s0A 2738 ld a,(olddsk) + 0AA9 32rC6s0A 2739 ld (linfo),a + 0AAC CDr84s09 2740 call curselect + 2741 + 2742 ; return from the disk monitor + 0AAF 2ArFCs01 2743 retmon: ld hl,(entsp) + 0AB2 F9 2744 ld sp,hl ;user stack restored + 0AB3 2ArFCs01 2745 ld hl,(aret) + 0AB6 7D 2746 ld a,l + 0AB7 44 2747 ld b,h ;BA = HL = aret + 0AB8 C9 2748 ret + 2749 +o 0AB9 2750 func38 equ func$ret +o 0AB9 2751 func39 equ func$ret + 0AB9 2752 func40: ;random disk write with zero fill of unallocated block + 0AB9 CDr8Ds09 2753 call reselect +a 0ABC 2754 ld a,2 + 0ABC 32rC6s0A 2755 ld (seqio),a +ua 0ABF 2756 ld c,false + 0ABF CDr8Cs08 2757 call rseek1 + 0AC2 CCrAEs07 2758 call z,diskwrite ;if seek successful + 0AC5 C9 2759 ret + 2760 + 2761 ; data areas + 2762 + 2763 ; initialized data +o 0AC6 2764 efcb: db empty ;0e5=available dir entry +o 0AC6 2765 rodsk: dw 0 ;read only disk vector +o 0AC6 2766 dlog: dw 0 ;logged-in disks +o 0AC6 2767 dmaad: dw tbuff ;initial dma address + 2768 + 2769 ; curtrka - alloca are set upon disk select + 2770 ; (data must be adjacent, do not insert variables) + 2771 ; (address of translate vector, not used) + 0AC6 2772 cdrmaxa: +o 0AC6 2773 ds word ;pointer to cur dir max value + 0AC6 2774 curtrka: +o 0AC6 2775 ds word ;current track address + 0AC6 2776 curreca: +o 0AC6 2777 ds word ;current record address +o 0AC6 2778 buffa: ds word ;pointer to directory dma address + 0AC6 2779 dpbaddr: +o 0AC6 2780 ds word ;current disk parameter block address +o 0AC6 2781 checka: ds word ;current checksum vector address +o 0AC6 2782 alloca: ds word ;current allocation vector address +o 0AC6 2783 addlist equ $-buffa ;address list size + 2784 + 2785 ; sectpt - offset obtained from disk parm block at dpbaddr + 2786 ; (data must be adjacent, do not insert variables) +o 0AC6 2787 sectpt: ds word ;sectors per track +o 0AC6 2788 blkshf: ds byte ;block shift factor +o 0AC6 2789 blkmsk: ds byte ;block mask +o 0AC6 2790 extmsk: ds byte ;extent mask +o 0AC6 2791 maxall: ds word ;maximum allocation number +o 0AC6 2792 dirmax: ds word ;largest directory number +o 0AC6 2793 dirblk: ds word ;reserved allocation bits for directory +o 0AC6 2794 chksiz: ds word ;size of checksum vector +o 0AC6 2795 offset: ds word ;offset tracks at beginning +o 0AC6 2796 dpblist equ $-sectpt ;size of area + 2797 + 2798 ; local variables +o 0AC6 2799 tranv: ds word ;address of translate vector + 0AC6 2800 fcb$copied: +o 0AC6 2801 ds byte ;set true if copy$fcb called +o 0AC6 2802 rmf: ds byte ;read mode flag for open$reel +o 0AC6 2803 dirloc: ds byte ;directory flag in rename, etc. +o 0AC6 2804 seqio: ds byte ;1 if sequential i/o +o 0AC6 2805 linfo: ds byte ;low(info) +o 0AC6 2806 dminx: ds byte ;local for diskwrite + 0AC6 2807 searchl: +o 0AC6 2808 ds byte ;search length + 0AC6 2809 searcha: +o 0AC6 2810 ds word ;search address +o 0AC6 2811 tinfo: ds word ;temp for info in "make" +o 0AC6 2812 single: ds byte ;set true if single byte allocation map +o 0AC6 2813 resel: ds byte ;reselection flag +o 0AC6 2814 olddsk: ds byte ;disk on entry to bdos +o 0AC6 2815 fcbdsk: ds byte ;disk named in fcb +o 0AC6 2816 rcount: ds byte ;record count in current fcb +o 0AC6 2817 extval: ds byte ;extent number and extmsk + 0AC6 2818 vrecord: +o 0AC6 2819 ds word ;current virtual record + 0AC6 2820 arecord: +o 0AC6 2821 ds word ;current actual record + 0AC6 2822 arecord1: +o 0AC6 2823 ds word ;current actual block# * blkmsk + 2824 + 2825 ; local variables for directory access +o 0AC6 2826 dptr: ds byte ;directory pointer 0,1,2,3 +o 0AC6 2827 dcnt: ds word ;directory counter 0,1,...,dirmax +o 0AC6 2828 drec: ds word ;directory record 0,1,...,dirmax/4 + 2829 + 2830 ;bios equ ($ and 0ff00h)+100h;next module + 2831 + 2832 ;;dwg;; end + 2833 + 2834 ;; dwg ; end dri source code here + 2835 + 0AC6 2836 _bdos_end:: + 2837 .area _CODE + 2838 .area _CABS diff --git a/doug/src/dribdos.mac b/doug/src/dribdos.mac new file mode 100755 index 00000000..b0a8f6d4 --- /dev/null +++ b/doug/src/dribdos.mac @@ -0,0 +1,2775 @@ + title 'Bdos Interface, Bdos, Version 2.2 Feb, 1980' + + .Z80 + aseg + org 100h + maclib MEMCFG.LIB ; define configuration parameters + .phase bdosph +bios equ biosph + +;***************************************************************** +;***************************************************************** +;** ** +;** B a s i c D i s k O p e r a t i n g S y s t e m ** +;** I n t e r f a c e M o d u l e ** +;** ** +;***************************************************************** +;***************************************************************** + +; Copyright (c) 1978, 1979, 1980 +; Digital Research +; Box 579, Pacific Grove +; California + + +; 20 january 1980 + +ssize equ 24 ;24 level stack + +; low memory locations +reboot equ 0000h ;reboot system +ioloc equ 0003h ;i/o byte location +bdosa equ 0006h ;address field of jp BDOS + +; bios access constants +bootf defl bios+3*0 ;cold boot function +wbootf defl bios+3*1 ;warm boot function +constf defl bios+3*2 ;console status function +coninf defl bios+3*3 ;console input function +conoutf defl bios+3*4 ;console output function +listf defl bios+3*5 ;list output function +punchf defl bios+3*6 ;punch output function +readerf defl bios+3*7 ;reader input function +homef defl bios+3*8 ;disk home function +seldskf defl bios+3*9 ;select disk function +settrkf defl bios+3*10 ;set track function +setsecf defl bios+3*11 ;set sector function +setdmaf defl bios+3*12 ;set dma function +readf defl bios+3*13 ;read disk function +writef defl bios+3*14 ;write disk function +liststf defl bios+3*15 ;list status function +sectran defl bios+3*16 ;sector translate + +; equates for non graphic characters +ctlc equ 03h ;control c +ctle equ 05h ;physical eol +ctlh equ 08h ;backspace +ctlp equ 10h ;prnt toggle +ctlr equ 12h ;repeat line +ctls equ 13h ;stop/start screen +ctlu equ 15h ;line delete +ctlx equ 18h ;=ctl-u +ctlz equ 1ah ;end of file +rubout equ 7fh ;char delete +tab equ 09h ;tab char +cr equ 0dh ;carriage return +lf equ 0ah ;line feed +ctl equ 5eh ;up arrow + + db 0,0,0,0,0,0 + +; enter here from the user's program with function number in c, +; and information address in d,e + jp bdose ;past parameter block + +; ************************************************ +; *** relative locations 0009 - 000e *** +; ************************************************ +pererr: dw persub ;permanent error subroutine +selerr: dw selsub ;select error subroutine +roderr: dw rodsub ;ro disk error subroutine +roferr: dw rofsub ;ro file error subroutine + + +bdose: ex de,hl ;arrive here from user programs + ld (info),hl + ex de,hl ;info=DE, DE=info + ld a,e + ld (linfo),a ;linfo = low(info) - don't equ + ld hl,0 + ld (aret),hl ;return value defaults to 0000 + ;save user's stack pointer, set to local stack + add hl,sp + ld (entsp),hl ;entsp = stackptr + ld sp,lstack ;local stack setup + xor a + ld (fcbdsk),a + ld (resel),a ;fcbdsk,resel=false + ld hl,goback ;return here after all functions + push hl ;jmp goback equivalent to ret + ld a,c + cp nfuncs + ret nc ;skip if invalid # + ld c,e ;possible output character to C + ld hl,functab + ld e,a + ld d,0 ;DE=func, HL=.ciotab + add hl,de + add hl,de + ld e,(hl) + inc hl + ld d,(hl) ;DE=functab(func) + ld hl,(info) ;info in DE for later xchg + ex de,hl + jp (hl) ;dispatched + +; dispatch table for functions +functab: + dw wbootf, func1, func2, func3 + dw punchf, listf, func6, func7 + dw func8, func9, func10,func11 +diskf equ ($-functab)/2 ;disk funcs + dw func12,func13,func14,func15 + dw func16,func17,func18,func19 + dw func20,func21,func22,func23 + dw func24,func25,func26,func27 + dw func28,func29,func30,func31 + dw func32,func33,func34,func35 + dw func36,func37,func38,func39 + dw func40 +nfuncs equ ($-functab)/2 + + +; error subroutines +persub: ld hl,permsg ;report permanent error + call errflg ;to report the error + cp ctlc + jp z,reboot ;reboot if response is ctlc + ret ;and ignore the error + +selsub: ld hl,selmsg ;report select error + jp wait$err ;wait console before boot + +rodsub: ld hl,rodmsg ;report write to read/only disk + jp wait$err ;wait console + +rofsub: ;report read/only file + ld hl,rofmsg ;drop through to wait for console + +wait$err: ;wait for response before boot + call errflg + jp reboot + +; error messages +dskmsg: db 'Bdos Err On ' +dskerr: db ' : $' ;filled in by errflg +permsg: db 'Bad Sector$' +selmsg: db 'Select$' +rofmsg: db 'File ' +rodmsg: db 'R/O$' + + +errflg: push hl ;report error to console, message address in HL + call crlf ;stack mssg address, new line + ld a,(curdsk) + add a,'A' + ld (dskerr),a ;current disk name + ld bc,dskmsg + call print ;the error message + pop bc + call print ;error mssage tail +; jp conin ;to get the input character + ;(drop through to conin) +; ret + + +; console handlers +conin: ld hl,kbchar ;read console character to A + ld a,(hl) + ld (hl),0 + or a + ret nz + ;no previous keyboard character ready + jp coninf ;get character externally +; ret +conech: call conin ;read character with echo + call echoc + ret c ;echo character? + ;character must be echoed before return + push af + ld c,a + call tabout + pop af + ret ;with character in A + +echoc: ;echo character if graphic + cp cr ;cr, lf, tab, or backspace + ret z ;carriage return? + cp lf + ret z ;line feed? + cp tab + ret z ;tab? + cp ctlh + ret z ;backspace? + cp ' ' + ret ;carry set if not graphic + +conbrk: ;check for character ready + ld a,(kbchar) + or a + jp nz,conb1 ;skip if active kbchar + ;no active kbchar, check external break + call constf + and 1 + ret z ;return if no char ready + ;character ready, read it + call coninf ;to A + cp ctls + jp nz,conb0 ;check stop screen function + ;found ctls, read next character + call coninf ;to A + cp ctlc + jp z,reboot ;ctlc implies re-boot + ;not a reboot, act as if nothing has happened + xor a + ret ;with zero in accumulator +conb0: + ;character in accum, save it + ld (kbchar),a +conb1: + ;return with true set in accumulator + ld a,1 + ret + +conout: ;compute character position/write console char from C + ;compcol = true if computing column position + ld a,(compcol) + or a + jp nz,compout + ;write the character, then compute the column + ;write console character from C + push bc + call conbrk ;check for screen stop function + pop bc + push bc ;recall/save character + call conoutf ;externally, to console + pop bc + push bc ;recall/save character + ;may be copying to the list device + ld a,(listcp) + or a + call nz,listf ;to printer, if so + pop bc ;recall the character +compout: + ld a,c ;recall the character + ;and compute column position + ld hl,column ;A = char, HL = .column + cp rubout + ret z ;no column change if nulls + inc (hl) ;column = column + 1 + cp ' ' + ret nc ;return if graphic + ;not graphic, reset column position + dec (hl) ;column = column - 1 + ld a,(hl) + or a + ret z ;return if at zero + ;not at zero, may be backspace or end line + ld a,c ;character back to A + cp ctlh + jp nz,notbacksp + ;backspace character + dec (hl) ;column = column - 1 + ret + +notbacksp: ;not a backspace character, eol? + cp lf + ret nz ;return if not + ;end of line, column = 0 + ld (hl),0 ;column = 0 + ret + +ctlout: ;send C character with possible preceding up-arrow + ld a,c + call echoc ;cy if not graphic (or special case) + jp nc,tabout ;skip if graphic, tab, cr, lf, or ctlh + ;send preceding up arrow + push af + ld c,ctl + call conout ;up arrow + pop af + or 40h ;becomes graphic letter + ld c,a ;ready to print + ;(drop through to tabout) + +tabout: ;expand tabs to console + ld a,c + cp tab + jp nz,conout ;direct to conout if not + ;tab encountered, move to next tab position +tab0: ld c,' ' + call conout ;another blank + ld a,(column) + and 111b ;column mod 8 = 0 ? + jp nz,tab0 ;back for another if not + ret + +backup: ;back-up one screen position + call pctlh + ld c,' ' + call conoutf +; (drop through to pctlh) +pctlh: ;send ctlh to console without affecting column count + ld c,ctlh + jp conoutf +; ret +crlfp: ;print #, cr, lf for ctlx, ctlu, ctlr functions + ;then move to strtcol (starting column) + ld c,'#' + call conout + call crlf ;column = 0, move to position strtcol +crlfp0: ld a,(column) + ld hl,strtcol + cp (hl) + ret nc ;stop when column reaches strtcol + ld c,' ' + call conout ;print blank + jp crlfp0 + +crlf: ld c,cr ;carriage return line feed sequence + call conout + ld c,lf + jp conout +; ret +print: ld a,(bc) ;print message until M(BC) = '$' + cp '$' + ret z ;stop on $ + ;more to print + inc bc + push bc + ld c,a ;char to C + call tabout ;another character printed + pop bc + jp print + +read: ;read to info address (max length, current length, buffer) + ld a,(column) + ld (strtcol),a ;save start for ctl-x, ctl-h + ld hl,(info) + ld c,(hl) + inc hl + push hl + ld b,0 + ;B = current buffer length, + ;C = maximum buffer length, + ;HL= next to fill - 1 +readnx: ;read next character, BC, HL active + push bc + push hl ;blen, cmax, HL saved +readn0: call conin ;next char in A + and 7fh ;mask parity bit + pop hl + pop bc ;reactivate counters + cp cr + jp z,readen ;end of line? + cp lf + jp z,readen ;also end of line + cp ctlh + jp nz,noth ;backspace? + ;do we have any characters to back over? + ld a,b + or a + jp z,readnx + ;characters remain in buffer, backup one + dec b ;remove one character + ld a,(column) + ld (compcol),a ;col > 0 + ;compcol > 0 marks repeat as length compute + jp linelen ;uses same code as repeat + +noth: ;not a backspace + cp rubout + jp nz,notrub ;rubout char? + ;rubout encountered, rubout if possible + ld a,b + or a + jp z,readnx ;skip if len=0 + ;buffer has characters, resend last char + ld a,(hl) + dec b + dec hl ;A = last char + ;blen=blen-1, next to fill - 1 decremented + jp rdech1 ;act like this is an echo + +notrub: ;not a rubout character, check end line + cp ctle + jp nz,note ;physical end line? + ;yes, save active counters and force eol + push bc + push hl + call crlf + xor a + ld (strtcol),a ;start position = 00 + jp readn0 ;for another character + +note: ;not end of line, list toggle? + cp ctlp + jp nz,notp ;skip if not ctlp + ;list toggle - change parity + push hl ;save next to fill - 1 + ld hl,listcp ;HL=.listcp flag + ld a,1 + sub (hl) ;True-listcp + ld (hl),a ;listcp = not listcp + pop hl + jp readnx ;for another char + +notp: ;not a ctlp, line delete? + cp ctlx + jp nz,notx + pop hl ;discard start position + ;loop while column > strtcol +backx: ld a,(strtcol) + ld hl,column + cp (hl) + jp nc,read ;start again + dec (hl) ;column = column - 1 + call backup ;one position + jp backx + +notx: ;not a control x, control u? + ;not control-X, control-U? + cp ctlu + jp nz,notu ;skip if not + ;delete line (ctlu) + call crlfp ;physical eol + pop hl ;discard starting position + jp read ;to start all over + +notu: ;not line delete, repeat line? + cp ctlr + jp nz,notr +linelen: ;repeat line, or compute line len (ctlh) + ;if compcol > 0 + push bc + call crlfp ;save line length + pop bc + pop hl + push hl + push bc + ;bcur, cmax active, beginning buff at HL +rep0: ld a,b + or a + jp z,rep1 ;count len to 00 + inc hl + ld c,(hl) ;next to print + dec b + push bc + push hl ;count length down + call ctlout ;character echoed + pop hl + pop bc ;recall remaining count + jp rep0 ;for the next character + +rep1: ;end of repeat, recall lengths + ;original BC still remains pushed + push hl ;save next to fill + ld a,(compcol) + or a ;>0 if computing length + jp z,readn0 ;for another char if so + ;column position computed for ctlh + ld hl,column + sub (hl) ;diff > 0 + ld (compcol),a ;count down below + ;move back compcol-column spaces +backsp: ;move back one more space + call backup ;one space + ld hl,compcol + dec (hl) + jp nz,backsp + jp readn0 ;for next character + +notr: ;not a ctlr, place into buffer +rdecho: inc hl + ld (hl),a ;character filled to mem + inc b ;blen = blen + 1 +rdech1: ;look for a random control character + push bc + push hl ;active values saved + ld c,a ;ready to print + call ctlout ;may be up-arrow C + pop hl + pop bc + ld a,(hl) ;recall char + cp ctlc ;set flags for reboot test + ld a,b ;move length to A + jp nz,notc ;skip if not a control c + cp 1 ;control C, must be length 1 + jp z,reboot ;reboot if blen = 1 + ;length not one, so skip reboot +notc: ;not reboot, are we at end of buffer? + cp c + jp c,readnx ;go for another if not +readen: ;end of read operation, store blen + pop hl + ld (hl),b ;M(current len) = B + ld c,cr + jp conout ;return carriage +; ret +func1: ;return console character with echo + call conech + jp sta$ret + +func2 equ tabout + ;write console character with tab expansion + +func3: ;return reader character + call readerf + jp sta$ret + +;func4: equated to punchf + ;write punch character + +;func5: equated to listf + ;write list character + ;write to list device + +func6: ;direct console i/o - read if 0ffh + ld a,c + inc a + jp z,dirinp ;0ffh => 00h, means input mode + inc a + jp z,constf ;0feH in C for status + ;direct output function + jp conoutf + +dirinp: call constf ;status check + or a + jp z,retmon ;skip, return 00 if not ready + ;character is ready, get it + call coninf ;to A + jp sta$ret + +func7: ;return io byte + ld a,(ioloc) + jp sta$ret + +func8: ;set i/o byte + ld hl,ioloc + ld (hl),c + ret ;jmp goback + +func9: ;write line until $ encountered + ex de,hl ;was lhld info + ld c,l + ld b,h ;BC=string address + jp print ;out to console + +func10 equ read + ;read a buffered console line + +func11: ;check console status + call conbrk + ;(drop through to sta$ret) +sta$ret: ;store the A register to aret + ld (aret),a +func$ret: + ret ;jmp goback (pop stack for non cp/m functions) + +setlret1: ;set lret = 1 + ld a,1 + jp sta$ret + + + +; data areas + +compcol: + db 0 ;true if computing column position +strtcol: + db 0 ;starting column position after read +column: db 0 ;column position +listcp: db 0 ;listing toggle +kbchar: db 0 ;initial key char = 00 +entsp: ds 2 ;entry stack pointer + ds ssize*2 ;stack size +lstack: +; end of Basic I/O System + +;***************************************************************** +;***************************************************************** + +; common values shared between bdosi and bdos +usrcode: + db 0 ;current user number +curdsk: db 0 ;current disk number +info: ds 2 ;information address +aret: ds 2 ;address value to return +lret equ aret ;low(aret) + +;***************************************************************** +;***************************************************************** +;** ** +;** B a s i c D i s k O p e r a t i n g S y s t e m ** +;** ** +;***************************************************************** +;***************************************************************** + +dvers equ 22h ;version 2.2 +; module addresses + +; literal constants +true equ 0ffh ;constant true +false equ 000h ;constant false +enddir equ 0ffffh ;end of directory +byte equ 1 ;number of bytes for "byte" type +word equ 2 ;number of bytes for "word" type + +; fixed addresses in low memory +tfcb equ 005ch ;default fcb location +tbuff equ 0080h ;default buffer location + +; fixed addresses referenced in bios module are +; pererr (0009), selerr (000c), roderr (000f) + +; error message handlers + +;per$error: ;report permanent error to user +; ld hl,pererr +; jp goerr + +;rod$error: ;report read/only disk error +; ld hl,roderr +; jp goerr + +;rof$error: ;report read/only file error +; ld hl,roferr +; jp goerr + +sel$error: ;report select error + ld hl,selerr + + +goerr: ;HL = .errorhandler, call subroutine + ld e,(hl) + inc hl + ld d,(hl) ;address of routine in DE + ex de,hl + jp (hl) ;to subroutine + + + +; local subroutines for bios interface + +move: ;move data length of length C from source DE to + ;destination given by HL + inc c ;in case it is zero +move0: dec c + ret z ;more to move + ld a,(de) + ld (hl),a ;one byte moved + inc de + inc hl ;to next byte + jp move0 + +selectdisk: ;select the disk drive given by curdsk, and fill + ;the base addresses curtrka - alloca, then fill + ;the values of the disk parameter block + ld a,(curdsk) + ld c,a ;current disk# to c + ;lsb of e = 0 if not yet logged - in + call seldskf ;HL filled by call + ;HL = 0000 if error, otherwise disk headers + ld a,h + or l + ret z ;return with 0000 in HL and z flag + ;disk header block address in hl + ld e,(hl) + inc hl + ld d,(hl) + inc hl ;DE=.tran + ld (cdrmaxa),hl + inc hl + inc hl ;.cdrmax + ld (curtrka),hl + inc hl + inc hl ;HL=.currec + ld (curreca),hl + inc hl + inc hl ;HL=.buffa + ;DE still contains .tran + ex de,hl + ld (tranv),hl ;.tran vector + ld hl,buffa ;DE= source for move, HL=dest + ld c,addlist + call move ;addlist filled + ;now fill the disk parameter block + ld hl,(dpbaddr) + ex de,hl ;DE is source + ld hl,sectpt ;HL is destination + ld c,dpblist + call move ;data filled + ;now set single/double map mode + ld hl,(maxall) ;largest allocation number + ld a,h ;00 indicates < 255 + ld hl,single + ld (hl),true ;assume a=00 + or a + jp z,retselect + ;high order of maxall not zero, use double dm + ld (hl),false +retselect: + ld a,true + or a + ret ;select disk function ok + +home: ;move to home position, then offset to start of dir + call homef ;move to track 00, sector 00 reference + ;lxi h,offset ;mov c,m ;inx h ;mov b,m ;call settrkf + ;first directory position selected + xor a ;constant zero to accumulator + ld hl,(curtrka) + ld (hl),a + inc hl + ld (hl),a ;curtrk=0000 + ld hl,(curreca) + ld (hl),a + inc hl + ld (hl),a ;currec=0000 + ;curtrk, currec both set to 0000 + ret + +rdbuff: ;read buffer and check condition + call readf ;current drive, track, sector, dma + jp diocomp ;check for i/o errors + +wrbuff: ;write buffer and check condition + ;write type (wrtype) is in register C + ;wrtype = 0 => normal write operation + ;wrtype = 1 => directory write operation + ;wrtype = 2 => start of new block + call writef ;current drive, track, sector, dma +diocomp: ;check for disk errors + or a + ret z + ld hl,pererr + jp goerr + +seek$dir: ;seek the record containing the current dir entry + ld hl,(dcnt) ;directory counter to HL + ld c,dskshf + call hlrotr ;value to HL + ld (arecord),hl + ld (drec),hl ;ready for seek +; jp seek +; ret + + +seek: ;seek the track given by arecord (actual record) + ;local equates for registers + ;load the registers from memory + ld hl,arecord + ld c,(hl) + inc hl + ld b,(hl) + ld hl,(curreca) + ld e,(hl) + inc hl + ld d,(hl) + ld hl,(curtrka) + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + ;loop while arecord < currec +seek0: ld a,c + sub e + ld a,b + sbc a,d + jp nc,seek1 ;skip if arecord >= currec + ;currec = currec - sectpt + push hl + ld hl,(sectpt) + ld a,e + sub l + ld e,a + ld a,d + sbc a,h + ld d,a + pop hl + ;curtrk = curtrk - 1 + dec hl + jp seek0 ;for another try + +seek1: ;look while arecord >= (t:=currec + sectpt) + push hl + ld hl,(sectpt) + add hl,de ;HL = currec+sectpt + jp c,seek2 ;can be > FFFFH + ld a,c + sub l + ld a,b + sbc a,h + jp c,seek2 ;skip if t > arecord + ;currec = t + ex de,hl + ;curtrk = curtrk + 1 + pop hl + inc hl + jp seek1 ;for another try + +seek2: pop hl + ;arrive here with updated values in each register + push bc + push de + push hl ;to stack for later + ;stack contains (lowest) BC=arecord, DE=currec, HL=curtrk + ex de,hl + ld hl,(offset) + add hl,de ;HL = curtrk+offset + ld b,h + ld c,l + call settrkf ;track set up + ;note that BC - curtrk is difference to move in bios + pop de ;recall curtrk + ld hl,(curtrka) + ld (hl),e + inc hl + ld (hl),d ;curtrk updated + ;now compute sector as arecord-currec + pop de ;recall currec + ld hl,(curreca) + ld (hl),e + inc hl + ld (hl),d + pop bc ;BC=arecord, DE=currec + ld a,c + sub e + ld c,a + ld a,b + sbc a,d + ld b,a + ld hl,(tranv) + ex de,hl ;BC=sector#, DE=.tran + call sectran ;HL = tran(sector) + ld c,l + ld b,h ;BC = tran(sector) + jp setsecf ;sector selected +; ret + +; file control block (fcb) constants +empty equ 0e5h ;empty directory entry +lstrec equ 127 ;last record# in extent +recsiz equ 128 ;record size +fcblen equ 32 ;file control block size +dirrec equ recsiz/fcblen ;directory elts / record +dskshf equ 2 ;log2(dirrec) +dskmsk equ dirrec-1 +fcbshf equ 5 ;log2(fcblen) + +extnum equ 12 ;extent number field +maxext equ 31 ;largest extent number +ubytes equ 13 ;unfilled bytes field +modnum equ 14 ;data module number +maxmod equ 15 ;largest module number +fwfmsk equ 80h ;file write flag is high order modnum +namlen equ 15 ;name length +reccnt equ 15 ;record count field +dskmap equ 16 ;disk map field +lstfcb equ fcblen-1 +nxtrec equ fcblen +ranrec equ nxtrec+1 ;random record field (2 bytes) + +; reserved file indicators +rofile equ 9 ;high order of first type char +invis equ 10 ;invisible file in dir command +; equ 11 ;reserved + +; utility functions for file access + +dm$position: ;compute disk map position for vrecord to HL + ld hl,blkshf + ld c,(hl) ;shift count to C + ld a,(vrecord) ;current virtual record to A +dmpos0: or a + rra + dec c + jp nz,dmpos0 + ;A = shr(vrecord,blkshf) = vrecord/2**(sect/block) + ld b,a ;save it for later addition + ld a,8 + sub (hl) ;8-blkshf to accumulator + ld c,a ;extent shift count in register c + ld a,(extval) ;extent value ani extmsk +dmpos1: + ;blkshf = 3,4,5,6,7, C=5,4,3,2,1 + ;shift is 4,3,2,1,0 + dec c + jp z,dmpos2 + or a + rla + jp dmpos1 + +dmpos2: ;arrive here with A = shl(ext and extmsk,7-blkshf) + add a,b ;add the previous shr(vrecord,blkshf) value + ;A is one of the following values, depending upon alloc + ;bks blkshf + ;1k 3 v/8 + extval * 16 + ;2k 4 v/16+ extval * 8 + ;4k 5 v/32+ extval * 4 + ;8k 6 v/64+ extval * 2 + ;16k 7 v/128+extval * 1 + ret ;with dm$position in A + +getdm: ;return disk map value from position given by BC + ld hl,(info) ;base address of file control block + ld de,dskmap + add hl,de ;HL =.diskmap + add hl,bc ;index by a single byte value + ld a,(single) ;single byte/map entry? + or a + jp z,getdmd ;get disk map single byte + ld l,(hl) + ld h,0 + ret ;with HL=00bb +getdmd: + add hl,bc ;HL=.fcb(dm+i*2) + ;double precision value returned + ld e,(hl) + inc hl + ld d,(hl) + ex de,hl + ret + +index: ;compute disk block number from current fcb + call dm$position ;0...15 in register A + ld c,a + ld b,0 + call getdm ;value to HL + ld (arecord),hl + ret + +allocated: ;called following index to see if block allocated + ld hl,(arecord) + ld a,l + or h + ret + +atran: ;compute actual record address, assuming index called + ld a,(blkshf) ;shift count to reg A + ld hl,(arecord) +atran0: add hl,hl + dec a + jp nz,atran0 ;shl(arecord,blkshf) + ld (arecord1),hl ;save shifted block # + ld a,(blkmsk) + ld c,a ;mask value to C + ld a,(vrecord) + and c ;masked value in A + or l + ld l,a ;to HL + ld (arecord),hl ;arecord=HL or (vrecord and blkmsk) + ret + +getexta: ;get current extent field address to A + ld hl,(info) + ld de,extnum + add hl,de ;HL=.fcb(extnum) + ret + +getfcba: ;compute reccnt and nxtrec addresses for get/setfcb + ld hl,(info) + ld de,reccnt + add hl,de + ex de,hl ;DE=.fcb(reccnt) + ld hl,nxtrec-reccnt + add hl,de ;HL=.fcb(nxtrec) + ret + +getfcb: ;set variables from currently addressed fcb + call getfcba ;addresses in DE, HL + ld a,(hl) + ld (vrecord),a ;vrecord=fcb(nxtrec) + ex de,hl + ld a,(hl) + ld (rcount),a ;rcount=fcb(reccnt) + call getexta ;HL=.fcb(extnum) + ld a,(extmsk) ;extent mask to a + and (hl) ;fcb(extnum) and extmsk + ld (extval),a + ret + +setfcb: ;place values back into current fcb + call getfcba ;addresses to DE, HL + ld a,(seqio) + cp 02 + jp nz,setfcb1 + xor a ;check ranfill +setfcb1: + ld c,a ;=1 if sequential i/o + ld a,(vrecord) + add a,c + ld (hl),a ;fcb(nxtrec)=vrecord+seqio + ex de,hl + ld a,(rcount) + ld (hl),a ;fcb(reccnt)=rcount + ret + +hlrotr: ;hl rotate right by amount C + inc c ;in case zero +hlrotr0: + dec c + ret z ;return when zero + ld a,h + or a + rra + ld h,a ;high byte + ld a,l + rra + ld l,a ;low byte + jp hlrotr0 + +compute$cs: ;compute checksum for current directory buffer + ld c,recsiz ;size of directory buffer + ld hl,(buffa) ;current directory buffer + xor a ;clear checksum value +computecs0: + add a,(hl) + inc hl + dec c ;cs=cs+buff(recsiz-C) + jp nz,computecs0 + ret ;with checksum in A + +hlrotl: ;rotate the mask in HL by amount in C + inc c ;may be zero +hlrotl0: + dec c + ret z ;return if zero + add hl,hl + jp hlrotl0 + +set$cdisk: ;set a "1" value in curdsk position of BC + push bc ;save input parameter + ld a,(curdsk) + ld c,a ;ready parameter for shift + ld hl,1 ;number to shift + call hlrotl ;HL = mask to integrate + pop bc ;original mask + ld a,c + or l + ld l,a + ld a,b + or h + ld h,a ;HL = mask or rol(1,curdsk) + ret + +nowrite: ;return true if dir checksum difference occurred + ld hl,(rodsk) + ld a,(curdsk) + ld c,a + call hlrotr + ld a,l + and 1b + ret ;non zero if nowrite + +set$ro: ;set current disk to read only + ld hl,rodsk + ld c,(hl) + inc hl + ld b,(hl) + call set$cdisk ;sets bit to 1 + ld (rodsk),hl + ;high water mark in directory goes to max + ld hl,(dirmax) + inc hl + ex de,hl ;DE = directory max + ld hl,(cdrmaxa) ;HL = .cdrmax + ld (hl),e + inc hl + ld (hl),d ;cdrmax = dirmax + ret + +check$rodir: ;check current directory element for read/only status + call getdptra ;address of element + +check$rofile: ;check current buff(dptr) or fcb(0) for r/o status + ld de,rofile + add hl,de ;offset to ro bit + ld a,(hl) + rla + ret nc ;return if not set + ld hl,roferr + jp goerr +; jp rof$error ;exit to read only disk message + + +check$write: ;check for write protected disk + call nowrite + ret z ;ok to write if not rodsk + ld hl,roderr + jp goerr +; jp rod$error ;read only disk error + +getdptra: ;compute the address of a directory element at + ;positon dptr in the buffer + ld hl,(buffa) + ld a,(dptr) +addh: ;HL = HL + A + add a,l + ld l,a + ret nc + ;overflow to H + inc h + ret + + +getmodnum: ;compute the address of the module number + ;bring module number to accumulator + ;(high order bit is fwf (file write flag) + ld hl,(info) + ld de,modnum + add hl,de ;HL=.fcb(modnum) + ld a,(hl) + ret ;A=fcb(modnum) + +clrmodnum: ;clear the module number field for user open/make + call getmodnum + ld (hl),0 ;fcb(modnum)=0 + ret + +setfwf: call getmodnum ;HL=.fcb(modnum), A=fcb(modnum) + ;set fwf (file write flag) to "1" + or fwfmsk + ld (hl),a ;fcb(modnum)=fcb(modnum) or 80h + ;also returns non zero in accumulator + ret + + +compcdr: ;return cy if cdrmax > dcnt + ld hl,(dcnt) + ex de,hl ;DE = directory counter + ld hl,(cdrmaxa) ;HL=.cdrmax + ld a,e + sub (hl) ;low(dcnt) - low(cdrmax) + inc hl ;HL = .cdrmax+1 + ld a,d + sbc a,(hl) ;hig(dcnt) - hig(cdrmax) + ;condition dcnt - cdrmax produces cy if cdrmax>dcnt + ret + +setcdr: ;if not (cdrmax > dcnt) then cdrmax = dcnt+1 + call compcdr + ret c ;return if cdrmax > dcnt + ;otherwise, HL = .cdrmax+1, DE = dcnt + inc de + ld (hl),d + dec hl + ld (hl),e + ret + +subdh: ;compute HL = DE - HL + ld a,e + sub l + ld l,a + ld a,d + sbc a,h + ld h,a + ret + +newchecksum: + ld c,true ;drop through to compute new checksum +checksum: ;compute current checksum record and update the + ;directory element if C=true, or check for = if not + ;drec < chksiz? + ld hl,(drec) + ex de,hl + ld hl,(chksiz) + call subdh ;DE-HL + ret nc ;skip checksum if past checksum vector size + ;drec < chksiz, so continue + push bc ;save init flag + call compute$cs ;check sum value to A + ld hl,(checka) ;address of check sum vector + ex de,hl + ld hl,(drec) ;value of drec + add hl,de ;HL = .check(drec) + pop bc ;recall true=0ffh or false=00 to C + inc c ;0ffh produces zero flag + jp z,initial$cs + ;not initializing, compare + cp (hl) ;compute$cs=check(drec)? + ret z ;no message if ok + ;checksum error, are we beyond + ;the end of the disk? + call compcdr + ret nc ;no message if so + call set$ro ;read/only disk set + ret + +initial$cs: ;initializing the checksum + ld (hl),a + ret + + +wrdir: ;write the current directory entry, set checksum + call newchecksum ;initialize entry + call setdir ;directory dma + ld c,1 ;indicates a write directory operation + call wrbuff ;write the buffer + jp setdata ;to data dma address +; ret +rd$dir: ;read a directory entry into the directory buffer + call setdir ;directory dma + call rdbuff ;directory record loaded + ;jmp setdata to data dma address +; ret +setdata: ;set data dma address + ld hl,dmaad + jp setdma ;to complete the call + +setdir: ;set directory dma address + ld hl,buffa ;jmp setdma to complete call + +setdma: ;HL=.dma address to set (i.e., buffa or dmaad) + ld c,(hl) + inc hl + ld b,(hl) ;parameter ready + jp setdmaf + +dir$to$user: ;copy the directory entry to the user buffer + ;after call to search or searchn by user code + ld hl,(buffa) + ex de,hl ;source is directory buffer + ld hl,(dmaad) ;destination is user dma address + ld c,recsiz ;copy entire record + jp move +; ret + +end$of$dir: ;return zero flag if at end of directory, non zero + ;if not at end (end of dir if dcnt = 0ffffh) + ld hl,dcnt + ld a,(hl) ;may be 0ffh + inc hl + cp (hl) ;low(dcnt) = high(dcnt)? + ret nz ;non zero returned if different + ;high and low the same, = 0ffh? + inc a ;0ffh becomes 00 if so + ret + +set$end$dir: ;set dcnt to the end of the directory + ld hl,enddir + ld (dcnt),hl + ret + +read$dir: ;read next directory entry, with C=true if initializing + ld hl,(dirmax) + ex de,hl ;in preparation for subtract + ld hl,(dcnt) + inc hl + ld (dcnt),hl ;dcnt=dcnt+1 + ;continue while dirmax >= dcnt (dirmax-dcnt no cy) + call subdh ;DE-HL + jp nc,read$dir0 + ;yes, set dcnt to end of directory + jp set$end$dir +; ret + +read$dir0: ;not at end of directory, seek next element + ;initialization flag is in C + ld a,(dcnt) + and dskmsk ;low(dcnt) and dskmsk + ld b,fcbshf ;to multiply by fcb size +read$dir1: + add a,a + dec b + jp nz,read$dir1 + ;A = (low(dcnt) and dskmsk) shl fcbshf + ld (dptr),a ;ready for next dir operation + or a + ret nz ;return if not a new record + push bc ;save initialization flag C + call seek$dir ;seek proper record + call rd$dir ;read the directory record + pop bc ;recall initialization flag + jp checksum ;checksum the directory elt +; ret + + +getallocbit: ;given allocation vector position BC, return with byte + ;containing BC shifted so that the least significant + ;bit is in the low order accumulator position. HL is + ;the address of the byte for possible replacement in + ;memory upon return, and D contains the number of shifts + ;required to place the returned value back into position + ld a,c + and 111b + inc a + ld e,a + ld d,a + ;d and e both contain the number of bit positions to shift + ld a,c + rrca + rrca + rrca + and 11111b + ld c,a ;C shr 3 to C + ld a,b + add a,a + add a,a + add a,a + add a,a + add a,a ;B shl 5 + or c + ld c,a ;bbbccccc to C + ld a,b + rrca + rrca + rrca + and 11111b + ld b,a ;BC shr 3 to BC + ld hl,(alloca) ;base address of allocation vector + add hl,bc + ld a,(hl) ;byte to A, hl = .alloc(BC shr 3) + ;now move the bit to the low order position of A +rotl: rlca + dec e + jp nz,rotl + ret + + +set$alloc$bit: ;BC is the bit position of ALLOC to set or reset. The + ;value of the bit is in register E. + push de + call getallocbit ;shifted val A, count in D + and 11111110b ;mask low bit to zero (may be set) + pop bc + or c ;low bit of C is masked into A +; jp rotr ;to rotate back into proper position +; ret +rotr: + ;byte value from ALLOC is in register A, with shift count + ;in register C (to place bit back into position), and + ;target ALLOC position in registers HL, rotate and replace + rrca + dec d + jp nz,rotr ;back into position + ld (hl),a ;back to ALLOC + ret + +scandm: ;scan the disk map addressed by dptr for non-zero + ;entries, the allocation vector entry corresponding + ;to a non-zero entry is set to the value of C (0,1) + call getdptra ;HL = buffa + dptr + ;HL addresses the beginning of the directory entry + ld de,dskmap + add hl,de ;hl now addresses the disk map + push bc ;save the 0/1 bit to set + ld c,fcblen-dskmap+1;size of single byte disk map + 1 +scandm0: ;loop once for each disk map entry + pop de ;recall bit parity + dec c + ret z ;all done scanning? + ;no, get next entry for scan + push de ;replace bit parity + ld a,(single) + or a + jp z,scandm1 + ;single byte scan operation + push bc ;save counter + push hl ;save map address + ld c,(hl) + ld b,0 ;BC=block# + jp scandm2 + +scandm1: ;double byte scan operation + dec c ;count for double byte + push bc ;save counter + ld c,(hl) + inc hl + ld b,(hl) ;BC=block# + push hl ;save map address +scandm2: ;arrive here with BC=block#, E=0/1 + ld a,c + or b ;skip if = 0000 + jp z,scanm3 + ld hl,(maxall) ;check invalid index + ld a,l + sub c + ld a,h + sbc a,b ;maxall - block# + call nc,set$alloc$bit + ;bit set to 0/1 +scanm3: pop hl + inc hl ;to next bit position + pop bc ;recall counter + jp scandm0 ;for another item + +initialize: ;initialize the current disk + ;lret = false ;set to true if $ file exists + ;compute the length of the allocation vector - 2 + ld hl,(maxall) + ld c,3 ;perform maxall/8 + ;number of bytes in alloc vector is (maxall/8)+1 + call hlrotr + inc hl ;HL = maxall/8+1 + ld b,h + ld c,l ;count down BC til zero + ld hl,(alloca) ;base of allocation vector + ;fill the allocation vector with zeros +initial0: + ld (hl),0 + inc hl ;alloc(i)=0 + dec bc ;count length down + ld a,b + or c + jp nz,initial0 + ;set the reserved space for the directory + ld hl,(dirblk) + ex de,hl + ld hl,(alloca) ;HL=.alloc() + ld (hl),e + inc hl + ld (hl),d ;sets reserved directory blks + ;allocation vector initialized, home disk + call home + ;cdrmax = 3 (scans at least one directory record) + ld hl,(cdrmaxa) + ld (hl),3 + inc hl + ld (hl),0 + ;cdrmax = 0000 + call set$end$dir ;dcnt = enddir + ;read directory entries and check for allocated storage +initial2: + ld c,true + call read$dir + call end$of$dir + ret z ;return if end of directory + ;not end of directory, valid entry? + call getdptra ;HL = buffa + dptr + ld a,empty + cp (hl) + jp z,initial2 ;go get another item + ;not empty, user code the same? + ld a,(usrcode) + cp (hl) + jp nz,pdollar + ;same user code, check for '$' submit + inc hl + ld a,(hl) ;first character + sub '$' ;dollar file? + jp nz,pdollar + ;dollar file found, mark in lret + dec a + ld (lret),a ;lret = 255 +pdollar: ;now scan the disk map for allocated blocks + ld c,1 ;set to allocated + call scandm + call setcdr ;set cdrmax to dcnt + jp initial2 ;for another entry + +copy$dirloc: ;copy directory location to lret following + ;delete, rename, ... ops + ld a,(dirloc) + jp sta$ret +; ret + +compext: ;compare extent# in A with that in C, return nonzero + ;if they do not match + push bc ;save C's original value + push af + ld a,(extmsk) + cpl + ld b,a + ;B has negated form of extent mask + ld a,c + and b + ld c,a ;low bits removed from C + pop af + and b ;low bits removed from A + sub c + and maxext ;set flags + pop bc ;restore original values + ret + +search: ;search for directory element of length C at info + ld a,0ffh + ld (dirloc),a ;changed if actually found + ld hl,searchl + ld (hl),c ;searchl = C + ld hl,(info) + ld (searcha),hl ;searcha = info + call set$end$dir ;dcnt = enddir + call home ;to start at the beginning + ;(drop through to searchn) + +searchn: ;search for the next directory element, assuming + ;a previous call on search which sets searcha and + ;searchl + ld c,false + call read$dir ;read next dir element + call end$of$dir + jp z,search$fin ;skip to end if so + ;not end of directory, scan for match + ld hl,(searcha) + ex de,hl ;DE=beginning of user fcb + ld a,(de) ;first character + cp empty ;keep scanning if empty + jp z,searchnext + ;not empty, may be end of logical directory + push de ;save search address + call compcdr ;past logical end? + pop de ;recall address + jp nc,search$fin ;artificial stop +searchnext: + call getdptra ;HL = buffa+dptr + ld a,(searchl) + ld c,a ;length of search to c + ld b,0 ;b counts up, c counts down +searchloop: + ld a,c + or a + jp z,endsearch + ld a,(de) + cp '?' + jp z,searchok ;? matches all + ;scan next character if not ubytes + ld a,b + cp ubytes + jp z,searchok + ;not the ubytes field, extent field? + cp extnum ;may be extent field + ld a,(de) ;fcb character + jp z,searchext ;skip to search extent + sub (hl) + and 7fh ;mask-out flags/extent modulus + jp nz,searchn ;skip if not matched + jp searchok ;matched character + +searchext: ;A has fcb character + ;attempt an extent # match + push bc ;save counters + ld c,(hl) ;directory character to c + call compext ;compare user/dir char + pop bc ;recall counters + jp nz,searchn ;skip if no match +searchok: ;current character matches + inc de + inc hl + inc b + dec c + jp searchloop + +endsearch: ;entire name matches, return dir position + ld a,(dcnt) + and dskmsk + ld (lret),a + ;lret = low(dcnt) and 11b + ld hl,dirloc + ld a,(hl) + rla + ret nc ;dirloc=0ffh? + ;yes, change it to 0 to mark as found + xor a + ld (hl),a ;dirloc=0 + ret + +search$fin: ;end of directory, or empty name + call set$end$dir ;may be artifical end + ld a,255 + jp sta$ret + +delete: ;delete the currently addressed file + call check$write ;write protected? + ld c,extnum + call search ;search through file type +delete0: + ;loop while directory matches + call end$of$dir + ret z ;stop if end + ;set each non zero disk map entry to 0 + ;in the allocation vector + ;may be r/o file + call check$rodir ;ro disk error if found + call getdptra ;HL=.buff(dptr) + ld (hl),empty + ld c,0 + call scandm ;alloc elts set to 0 + call wrdir ;write the directory + call searchn ;to next element + jp delete0 ;for another record + +get$block: ;given allocation vector position BC, find the zero bit + ;closest to this position by searching left and right. + ;if found, set the bit to one and return the bit position + ;in hl. if not found (i.e., we pass 0 on the left, or + ;maxall on the right), return 0000 in hl + ld d,b + ld e,c ;copy of starting position to de +lefttst: + ld a,c + or b + jp z,righttst ;skip if left=0000 + ;left not at position zero, bit zero? + dec bc + push de + push bc ;left,right pushed + call getallocbit + rra + jp nc,retblock ;return block number if zero + ;bit is one, so try the right + pop bc + pop de ;left, right restored +righttst: + ld hl,(maxall) ;value of maximum allocation# + ld a,e + sub l + ld a,d + sbc a,h ;right=maxall? + jp nc,retblock0 ;return block 0000 if so + inc de + push bc + push de ;left, right pushed + ld b,d + ld c,e ;ready right for call + call getallocbit + rra + jp nc,retblock ;return block number if zero + pop de + pop bc ;restore left and right pointers + jp lefttst ;for another attempt +retblock: + rla + inc a ;bit back into position and set to 1 + ;d contains the number of shifts required to reposition + call rotr ;move bit back to position and store + pop hl + pop de ;HL returned value, DE discarded + ret + +retblock0: ;cannot find an available bit, return 0000 + ld a,c + or b + jp nz,lefttst ;also at beginning + ld hl,0000h + ret + +copy$fcb: ;copy the entire file control block + ld c,0 + ld e,fcblen ;start at 0, to fcblen-1 +; jp copy$dir + +copy$dir: ;copy fcb information starting at C for E bytes + ;into the currently addressed directory entry + push de ;save length for later + ld b,0 ;double index to BC + ld hl,(info) ;HL = source for data + add hl,bc + ex de,hl ;DE=.fcb(C), source for copy + call getdptra ;HL=.buff(dptr), destination + pop bc ;DE=source, HL=dest, C=length + call move ;data moved +seek$copy: ;enter from close to seek and copy current element + call seek$dir ;to the directory element + jp wrdir ;write the directory element +; ret +rename: ;rename the file described by the first half of + ;the currently addressed file control block. the + ;new name is contained in the last half of the + ;currently addressed file conrol block. the file + ;name and type are changed, but the reel number + ;is ignored. the user number is identical + call check$write ;may be write protected + ;search up to the extent field + ld c,extnum + call search + ;copy position 0 + ld hl,(info) + ld a,(hl) ;HL=.fcb(0), A=fcb(0) + ld de,dskmap + add hl,de ;HL=.fcb(dskmap) + ld (hl),a ;fcb(dskmap)=fcb(0) + ;assume the same disk drive for new named file +rename0: + call end$of$dir + ret z ;stop at end of dir + ;not end of directory, rename next element + call check$rodir ;may be read-only file + ld c,dskmap + ld e,extnum + call copy$dir + ;element renamed, move to next + call searchn + jp rename0 + +indicators: ;set file indicators for current fcb + ld c,extnum + call search ;through file type +indic0: call end$of$dir + ret z ;stop at end of dir + ;not end of directory, continue to change + ld c,0 + ld e,extnum ;copy name + call copy$dir + call searchn + jp indic0 + +open: ;search for the directory entry, copy to fcb + ld c,namlen + call search + call end$of$dir + ret z ;return with lret=255 if end + ;not end of directory, copy fcb information +open$copy: ;(referenced below to copy fcb info) + call getexta + ld a,(hl) + push af + push hl ;save extent# + call getdptra + ex de,hl ;DE = .buff(dptr) + ld hl,(info) ;HL=.fcb(0) + ld c,nxtrec ;length of move operation + push de ;save .buff(dptr) + call move ;from .buff(dptr) to .fcb(0) + ;note that entire fcb is copied, including indicators + call setfwf ;sets file write flag + pop de + ld hl,extnum + add hl,de ;HL=.buff(dptr+extnum) + ld c,(hl) ;C = directory extent number + ld hl,reccnt + add hl,de ;HL=.buff(dptr+reccnt) + ld b,(hl) ;B holds directory record count + pop hl + pop af + ld (hl),a ;restore extent number + ;HL = .user extent#, B = dir rec cnt, C = dir extent# + ;if user ext < dir ext then user := 128 records + ;if user ext = dir ext then user := dir records + ;if user ext > dir ext then user := 0 records + ld a,c + cp (hl) + ld a,b ;ready dir reccnt + jp z,open$rcnt ;if same, user gets dir reccnt + ld a,0 + jp c,open$rcnt ;user is larger + ld a,128 ;directory is larger +open$rcnt: ;A has record count to fill + ld hl,(info) + ld de,reccnt + add hl,de + ld (hl),a + ret + +mergezero: ;HL = .fcb1(i), DE = .fcb2(i), + ;if fcb1(i) = 0 then fcb1(i) := fcb2(i) + ld a,(hl) + inc hl + or (hl) + dec hl + ret nz ;return if = 0000 + ld a,(de) + ld (hl),a + inc de + inc hl ;low byte copied + ld a,(de) + ld (hl),a + dec de + dec hl ;back to input form + ret + +close: ;locate the directory element and re-write it + xor a + ld (lret),a + ld (dcnt),a + ld (dcnt+1),a + call nowrite + ret nz ;skip close if r/o disk + ;check file write flag - 0 indicates written + call getmodnum ;fcb(modnum) in A + and fwfmsk + ret nz ;return if bit remains set + ld c,namlen + call search ;locate file + call end$of$dir + ret z ;return if not found + ;merge the disk map at info with that at buff(dptr) + ld bc,dskmap + call getdptra + add hl,bc + ex de,hl ;DE is .buff(dptr+16) + ld hl,(info) + add hl,bc ;DE=.buff(dptr+16), HL=.fcb(16) + ld c,fcblen-dskmap;length of single byte dm +merge0: ld a,(single) + or a + jp z,merged ;skip to double + ;this is a single byte map + ;if fcb(i) = 0 then fcb(i) = buff(i) + ;if buff(i) = 0 then buff(i) = fcb(i) + ;if fcb(i) <> buff(i) then error + ld a,(hl) + or a + ld a,(de) + jp nz,fcbnzero + ;fcb(i) = 0 + ld (hl),a ;fcb(i) = buff(i) +fcbnzero: + or a + jp nz,buffnzero + ;buff(i) = 0 + ld a,(hl) + ld (de),a ;buff(i)=fcb(i) +buffnzero: + cp (hl) + jp nz,mergerr ;fcb(i) = buff(i)? + jp dmset ;if merge ok + +merged: ;this is a double byte merge operation + call mergezero ;buff = fcb if buff 0000 + ex de,hl + call mergezero + ex de,hl ;fcb = buff if fcb 0000 + ;they should be identical at this point + ld a,(de) + cp (hl) + jp nz,mergerr ;low same? + inc de + inc hl ;to high byte + ld a,(de) + cp (hl) + jp nz,mergerr ;high same? + ;merge operation ok for this pair + dec c ;extra count for double byte +dmset: inc de + inc hl ;to next byte position + dec c + jp nz,merge0 ;for more + ;end of disk map merge, check record count + ;DE = .buff(dptr)+32, HL = .fcb(32) + ld bc,-(fcblen-extnum) + add hl,bc + ex de,hl + add hl,bc + ;DE = .fcb(extnum), HL = .buff(dptr+extnum) + ld a,(de) ;current user extent number + ;if fcb(ext) >= buff(fcb) then + ;buff(ext) := fcb(ext), buff(rec) := fcb(rec) + cp (hl) + jp c,endmerge + ;fcb extent number >= dir extent number + ld (hl),a ;buff(ext) = fcb(ext) + ;update directory record count field + ld bc,reccnt-extnum + add hl,bc + ex de,hl + add hl,bc + ;DE=.buff(reccnt), HL=.fcb(reccnt) + ld a,(hl) + ld (de),a ;buff(reccnt)=fcb(reccnt) +endmerge: + ld a,true + ld (fcb$copied),a ;mark as copied + jp seek$copy ;ok to "wrdir" here - 1.4 compat + ; ret + +mergerr: ;elements did not merge correctly + ld hl,lret + dec (hl) ;=255 non zero flag set + ret + +make: ;create a new file by creating a directory entry + ;then opening the file + call check$write ;may be write protected + ld hl,(info) + push hl ;save fcb address, look for e5 + ld hl,efcb + ld (info),hl ;info = .empty + ld c,1 + call search ;length 1 match on empty entry + call end$of$dir ;zero flag set if no space + pop hl ;recall info address + ld (info),hl ;in case we return here + ret z ;return with error condition 255 if not found + ex de,hl ;DE = info address + ;clear the remainder of the fcb + ld hl,namlen + add hl,de ;HL=.fcb(namlen) + ld c,fcblen-namlen ;number of bytes to fill + xor a ;clear accumulator to 00 for fill +make0: ld (hl),a + inc hl + dec c + jp nz,make0 + ld hl,ubytes + add hl,de ;HL = .fcb(ubytes) + ld (hl),a ;fcb(ubytes) = 0 + call setcdr ;may have extended the directory + ;now copy entry to the directory + call copy$fcb + ;and set the file write flag to "1" + jp setfwf +; ret + +open$reel: ;close the current extent, and open the next one + ;if possible. RMF is true if in read mode + xor a + ld (fcb$copied),a ;set true if actually copied + call close ;close current extent + ;lret remains at enddir if we cannot open the next ext + call end$of$dir + ret z ;return if end + ;increment extent number + ld hl,(info) + ld bc,extnum + add hl,bc ;HL=.fcb(extnum) + ld a,(hl) + inc a + and maxext + ld (hl),a ;fcb(extnum)=++1 + jp z,open$mod ;move to next module if zero + ;may be in the same extent group + ld b,a + ld a,(extmsk) + and b + ;if result is zero, then not in the same group + ld hl,fcb$copied ;true if the fcb was copied to directory + and (hl) ;produces a 00 in accumulator if not written + jp z,open$reel0 ;go to next physical extent + ;result is non zero, so we must be in same logical ext + jp open$reel1 ;to copy fcb information +open$mod: ;extent number overflow, go to next module + ld bc,modnum-extnum + add hl,bc ;HL=.fcb(modnum) + inc (hl) ;fcb(modnum)=++1 + ;module number incremented, check for overflow + ld a,(hl) + and maxmod ;mask high order bits + jp z,open$r$err ;cannot overflow to zero + ;otherwise, ok to continue with new module +open$reel0: + ld c,namlen + call search ;next extent found? + call end$of$dir + jp nz,open$reel1 + ;end of file encountered + ld a,(rmf) + inc a ;0ffh becomes 00 if read + jp z,open$r$err ;sets lret = 1 + ;try to extend the current file + call make + ;cannot be end of directory + call end$of$dir + jp z,open$r$err ;with lret = 1 + jp open$reel2 + +open$reel1: ;not end of file, open + call open$copy +open$reel2: + call getfcb ;set parameters + xor a + jp sta$ret ;lret = 0 +; ret ;with lret = 0 + +open$r$err: ;cannot move to next extent of this file + call setlret1 ;lret = 1 + jp setfwf ;ensure that it will not be closed +; ret + +seqdiskread: ;sequential disk read operation + ld a,1 + ld (seqio),a + ;drop through to diskread + +diskread: ;(may enter from seqdiskread) + ld a,true + ld (rmf),a ;read mode flag = true (open$reel) + ;read the next record from the current fcb + call getfcb ;sets parameters for the read + ld a,(vrecord) + ld hl,rcount + cp (hl) ;vrecord-rcount + ;skip if rcount > vrecord + jp c,recordok + ;not enough records in the extent + ;record count must be 128 to continue + cp 128 ;vrecord = 128? + jp nz,diskeof ;skip if vrecord<>128 + call open$reel ;go to next extent if so + xor a + ld (vrecord),a ;vrecord=00 + ;now check for open ok + ld a,(lret) + or a + jp nz,diskeof ;stop at eof +recordok: ;arrive with fcb addressing a record to read + call index + ;error 2 if reading unwritten data + ;(returns 1 to be compatible with 1.4) + call allocated ;arecord=0000? + jp z,diskeof + ;record has been allocated, read it + call atran ;arecord now a disk address + call seek ;to proper track,sector + call rdbuff ;to dma address + jp setfcb ;replace parameter +; ret + +diskeof: + jp setlret1 ;lret = 1 +; ret + +seqdiskwrite: ;sequential disk write + ld a,1 + ld (seqio),a + ;drop through to diskwrite + +diskwrite: ;(may enter here from seqdiskwrite above) + ld a,false + ld (rmf),a ;read mode flag + ;write record to currently selected file + call check$write ;in case write protected + ld hl,(info) ;HL = .fcb(0) + call check$rofile ;may be a read-only file + call getfcb ;to set local parameters + ld a,(vrecord) + cp lstrec+1 ;vrecord-128 + ;skip if vrecord > lstrec + ;vrecord = 128, cannot open next extent + jp nc,setlret1 ;lret=1 +diskwr0: ;can write the next record, so continue + call index + call allocated + ld c,0 ;marked as normal write operation for wrbuff + jp nz,diskwr1 + ;not allocated + ;the argument to getblock is the starting + ;position for the disk search, and should be + ;the last allocated block for this file, or + ;the value 0 if no space has been allocated + call dm$position + ld (dminx),a ;save for later + ld bc,0000h ;may use block zero + or a + jp z,nopblock ;skip if no previous block + ;previous block exists at A + ld c,a + dec bc ;previous block # in BC + call getdm ;previous block # to HL + ld b,h + ld c,l ;BC=prev block# +nopblock: ;BC = 0000, or previous block # + call get$block ;block # to HL + ;arrive here with block# or zero + ld a,l + or h + jp nz,blockok + ;cannot find a block to allocate + ld a,2 + jp sta$ret ;lret=2 + +blockok: ;allocated block number is in HL + ld (arecord),hl + ex de,hl ;block number to DE + ld hl,(info) + ld bc,dskmap + add hl,bc ;HL=.fcb(dskmap) + ld a,(single) + or a ;set flags for single byte dm + ld a,(dminx) ;recall dm index + jp z,allocwd ;skip if allocating word + ;allocating a byte value + call addh + ld (hl),e ;single byte alloc + jp diskwru ;to continue + +allocwd: ;allocate a word value + ld c,a + ld b,0 ;double(dminx) + add hl,bc + add hl,bc ;HL=.fcb(dminx*2) + ld (hl),e + inc hl + ld (hl),d ;double wd +diskwru: ;disk write to previously unallocated block + ld c,2 ;marked as unallocated write +diskwr1: ;continue the write operation of no allocation error + ;C = 0 if normal write, 2 if to prev unalloc block + ld a,(lret) + or a + ret nz ;stop if non zero returned value + push bc ;save write flag + call atran ;arecord set + ld a,(seqio) + dec a + dec a + jp nz,diskwr11 + pop bc + push bc + ld a,c + dec a + dec a + jp nz,diskwr11 ;old allocation + push hl ;arecord in hl ret from atran + ld hl,(buffa) + ld d,a ;zero buffa & fill +fill0: ld (hl),a + inc hl + inc d + jp p,fill0 + call setdir + ld hl,(arecord1) + ld c,2 +fill1: ld (arecord),hl + push bc + call seek + pop bc + call wrbuff ;write fill record + ld hl,(arecord) ;restore last record + ld c,0 ;change allocate flag + ld a,(blkmsk) + ld b,a + and l + cp b + inc hl + jp nz,fill1 ;cont until cluster is zeroed + pop hl + ld (arecord),hl + call setdata +diskwr11: + call seek ;to proper file position + pop bc + push bc ;restore/save write flag (C=2 if new block) + call wrbuff ;written to disk + pop bc ;C = 2 if a new block was allocated, 0 if not + ;increment record count if rcount<=vrecord + ld a,(vrecord) + ld hl,rcount + cp (hl) ;vrecord-rcount + jp c,diskwr2 + ;rcount <= vrecord + ld (hl),a + inc (hl) ;rcount = vrecord+1 + ld c,2 ;mark as record count incremented +diskwr2: ;A has vrecord, C=2 if new block or new record# + dec c + dec c + jp nz,noupdate + push af ;save vrecord value + call getmodnum ;HL=.fcb(modnum), A=fcb(modnum) + ;reset the file write flag to mark as written fcb + and (not fwfmsk) and 0ffh;bit reset + ld (hl),a ;fcb(modnum) = fcb(modnum) and 7fh + pop af ;restore vrecord +noupdate: ;check for end of extent, if found attempt to open + ;next extent in preparation for next write + cp lstrec ;vrecord=lstrec? + jp nz,diskwr3 ;skip if not + ;may be random access write, if so we are done + ;change next + ld a,(seqio) + cp 1 + jp nz,diskwr3 ;skip next extent open op + ;update current fcb before going to next extent + call setfcb + call open$reel ;rmf=false + ;vrecord remains at lstrec causing eof if + ;no more directory space is available + ld hl,lret + ld a,(hl) + or a + jp nz,nospace + ;space available, set vrecord=255 + dec a + ld (vrecord),a ;goes to 00 next time +nospace: + ld (hl),0 ;lret = 00 for returned value +diskwr3: + jp setfcb ;replace parameters +; ret + +rseek: ;random access seek operation, C=0ffh if read mode + ;fcb is assumed to address an active file control block + ;(modnum has been set to 1100$0000b if previous bad seek) + xor a + ld (seqio),a ;marked as random access operation +rseek1: push bc ;save r/w flag + ld hl,(info) + ex de,hl ;DE will hold base of fcb + ld hl,ranrec + add hl,de ;HL=.fcb(ranrec) + ld a,(hl) + and 7fh + push af ;record number + ld a,(hl) + rla ;cy=lsb of extent# + inc hl + ld a,(hl) + rla + and 11111b ;A=ext# + ld c,a ;C holds extent number, record stacked + ld a,(hl) + rra + rra + rra + rra + and 1111b ;mod# + ld b,a ;B holds module#, C holds ext# + pop af ;recall sought record # + ;check to insure that high byte of ran rec = 00 + inc hl + ld l,(hl) ;l=high byte (must be 00) + inc l + dec l + ld l,6 ;zero flag, l=6 + ;produce error 6, seek past physical eod + jp nz,seekerr + ;otherwise, high byte = 0, A = sought record + ld hl,nxtrec + add hl,de ;HL = .fcb(nxtrec) + ld (hl),a ;sought rec# stored away + ;arrive here with B=mod#, C=ext#, DE=.fcb, rec stored + ;the r/w flag is still stacked. compare fcb values + ld hl,extnum + add hl,de + ld a,c ;A=seek ext# + sub (hl) + jp nz,ranclose ;tests for = extents + ;extents match, check mod# + ld hl,modnum + add hl,de + ld a,b ;B=seek mod# + ;could be overflow at eof, producing module# + ;of 90H or 10H, so compare all but fwf + sub (hl) + and 7fh + jp z,seekok ;same? +ranclose: + push bc + push de ;save seek mod#,ext#, .fcb + call close ;current extent closed + pop de + pop bc ;recall parameters and fill + ld l,3 ;cannot close error #3 + ld a,(lret) + inc a + jp z,badseek + ld hl,extnum + add hl,de + ld (hl),c ;fcb(extnum)=ext# + ld hl,modnum + add hl,de + ld (hl),b ;fcb(modnum)=mod# + call open ;is the file present? + ld a,(lret) + inc a + jp nz,seekok ;open successful? + ;cannot open the file, read mode? + pop bc ;r/w flag to c (=0ffh if read) + push bc ;everyone expects this item stacked + ld l,4 ;seek to unwritten extent #4 + inc c ;becomes 00 if read operation + jp z,badseek ;skip to error if read operation + ;write operation, make new extent + call make + ld l,5 ;cannot create new extent #5 + ld a,(lret) + inc a + jp z,badseek ;no dir space + ;file make operation successful +seekok: + pop bc ;discard r/w flag + xor a + jp sta$ret ;with zero set +badseek: ;fcb no longer contains a valid fcb, mark + ;with 1100$000b in modnum field so that it + ;appears as overflow with file write flag set + push hl ;save error flag + call getmodnum ;HL = .modnum + ld (hl),11000000b + pop hl ;and drop through +seekerr: + pop bc ;discard r/w flag + ld a,l + ld (lret),a ;lret=#, nonzero + ;setfwf returns non-zero accumulator for err + jp setfwf ;flag set, so subsequent close ok +; ret + +randiskread: ;random disk read operation + ld c,true ;marked as read operation + call rseek + call z,diskread ;if seek successful + ret + +randiskwrite: ;random disk write operation + ld c,false ;marked as write operation + call rseek + call z,diskwrite ;if seek successful + ret + +compute$rr: ;compute random record position for getfilesize/setrandom + ex de,hl + add hl,de + ;DE=.buf(dptr) or .fcb(0), HL = .f(nxtrec/reccnt) + ld c,(hl) + ld b,0 ;BC = 0000 0000 ?rrr rrrr + ld hl,extnum + add hl,de + ld a,(hl) + rrca + and 80h ;A=e000 0000 + add a,c + ld c,a + ld a,0 + adc a,b + ld b,a + ;BC = 0000 000? errrr rrrr + ld a,(hl) + rrca + and 0fh + add a,b + ld b,a + ;BC = 000? eeee errrr rrrr + ld hl,modnum + add hl,de + ld a,(hl) ;A=XXX? mmmm + add a,a + add a,a + add a,a + add a,a ;cy=? A=mmmm 0000 + push af + add a,b + ld b,a + ;cy=?, BC = mmmm eeee errr rrrr + push af ;possible second carry + pop hl ;cy = lsb of L + ld a,l ;cy = lsb of A + pop hl ;cy = lsb of L + or l ;cy/cy = lsb of A + and 1 ;A = 0000 000? possible carry-out + ret + +getfilesize: ;compute logical file size for current fcb + ld c,extnum + call search + ;zero the receiving ranrec field + ld hl,(info) + ld de,ranrec + add hl,de + push hl ;save position + ld (hl),d + inc hl + ld (hl),d + inc hl + ld (hl),d ;=00 00 00 +getsize: + call end$of$dir + jp z,setsize + ;current fcb addressed by dptr + call getdptra + ld de,reccnt ;ready for compute size + call compute$rr + ;A=0000 000? BC = mmmm eeee errr rrrr + ;compare with memory, larger? + pop hl + push hl ;recall, replace .fcb(ranrec) + ld e,a ;save cy + ld a,c + sub (hl) + inc hl ;ls byte + ld a,b + sbc a,(hl) + inc hl ;middle byte + ld a,e + sbc a,(hl) ;carry if .fcb(ranrec) > directory + jp c,getnextsize ;for another try + ;fcb is less or equal, fill from directory + ld (hl),e + dec hl + ld (hl),b + dec hl + ld (hl),c +getnextsize: + call searchn + jp getsize + +setsize: + pop hl ;discard .fcb(ranrec) + ret + +setrandom: ;set random record from the current file control block + ld hl,(info) + ld de,nxtrec ;ready params for computesize + call compute$rr ;DE=info, A=cy, BC=mmmm eeee errr rrrr + ld hl,ranrec + add hl,de ;HL = .fcb(ranrec) + ld (hl),c + inc hl + ld (hl),b + inc hl + ld (hl),a ;to ranrec + ret + +select: ;select disk info for subsequent input or output ops + ld hl,(dlog) + ld a,(curdsk) + ld c,a + call hlrotr + push hl + ex de,hl ;save it for test below, send to seldsk + call selectdisk + pop hl ;recall dlog vector + call z,sel$error ;returns true if select ok + ;is the disk logged in? + ld a,l + rra + ret c ;return if bit is set + ;disk not logged in, set bit and initialize + ld hl,(dlog) + ld c,l + ld b,h ;call ready + call set$cdisk + ld (dlog),hl ;dlog=set$cdisk(dlog) + jp initialize +; ret + +curselect: + ld a,(linfo) + ld hl,curdsk + cp (hl) + ret z ;skip if linfo=curdsk + ld (hl),a ;curdsk=info + jp select +; ret + +reselect: ;check current fcb to see if reselection necessary + ld a,true + ld (resel),a ;mark possible reselect + ld hl,(info) + ld a,(hl) ;drive select code + and 11111b ;non zero is auto drive select + dec a ;drive code normalized to 0..30, or 255 + ld (linfo),a ;save drive code + cp 30 + jp nc,noselect + ;auto select function, save curdsk + ld a,(curdsk) + ld (olddsk),a ;olddsk=curdsk + ld a,(hl) + ld (fcbdsk),a ;save drive code + and 11100000b + ld (hl),a ;preserve hi bits + call curselect +noselect: ;set user code + ld a,(usrcode) ;0...31 + ld hl,(info) + or (hl) + ld (hl),a + ret + +; individual function handlers +func12: ;return version number + ld a,dvers + jp sta$ret ;lret = dvers (high = 00) +; ret +; jp goback + +func13: ;reset disk system - initialize to disk 0 + ld hl,0 + ld (rodsk),hl + ld (dlog),hl + xor a + ld (curdsk),a ;note that usrcode remains unchanged + ld hl,tbuff + ld (dmaad),hl ;dmaad = tbuff + call setdata ;to data dma address + jp select +; ret +; jp goback + +func14 equ curselect ;select disk info +; ret +; jp goback + +func15: ;open file + call clrmodnum ;clear the module number + call reselect + jp open +; ret +; jp goback + +func16: ;close file + call reselect + jp close +; ret +; jp goback + +func17: ;search for first occurrence of a file + ld c,0 ;length assuming '?' true + ex de,hl ;was lhld info + ld a,(hl) + cp '?' ;no reselect if ? + jp z,qselect ;skip reselect if so + ;normal search + call getexta + ld a,(hl) + cp '?' ; + call nz,clrmodnum ;module number zeroed + call reselect + ld c,namlen +qselect: + call search + jp dir$to$user ;copy directory entry to user +; ret +; jp goback + +func18: ;search for next occurrence of a file name + ld hl,(searcha) + ld (info),hl + call reselect + call searchn + jp dir$to$user ;copy directory entry to user +; ret +; jp goback + +func19: ;delete a file + call reselect + call delete + jp copy$dirloc +; ret +; jp goback + +func20: ;read a file + call reselect + jp seqdiskread +; jp goback + +func21: ;write a file + call reselect + jp seqdiskwrite +; jp goback + +func22: ;make a file + call clrmodnum + call reselect + jp make +; ret +; jp goback + +func23: ;rename a file + call reselect + call rename + jp copy$dirloc +; ret +; jp goback + +func24: ;return the login vector + ld hl,(dlog) + jp sthl$ret +; ret +; jp goback + +func25: ;return selected disk number + ld a,(curdsk) + jp sta$ret +; ret +; jp goback + +func26: ;set the subsequent dma address to info + ex de,hl ;was lhld info + ld (dmaad),hl ;dmaad = info + jp setdata ;to data dma address +; ret +; jp goback + +func27: ;return the login vector address + ld hl,(alloca) + jp sthl$ret +; ret +; jp goback + +func28 equ set$ro + ;write protect current disk +; ret +; jp goback + +func29: ;return r/o bit vector + ld hl,(rodsk) + jp sthl$ret +; ret +; jp goback + +func30: ;set file indicators + call reselect + call indicators + jp copy$dirloc ;lret=dirloc +; ret +; jp goback + +func31: ;return address of disk parameter block + ld hl,(dpbaddr) +sthl$ret: + ld (aret),hl + ret +; jp goback + +func32: ;set user code + ld a,(linfo) + cp 0ffh + jp nz,setusrcode + ;interrogate user code instead + ld a,(usrcode) + jp sta$ret ;lret=usrcode +; ret +; jp goback + +setusrcode: + and 1fh + ld (usrcode),a + ret +; jp goback + +func33: ;random disk read operation + call reselect + jp randiskread ;to perform the disk read +; ret +; jp goback + +func34: ;random disk write operation + call reselect + jp randiskwrite ;to perform the disk write +; ret +; jp goback + +func35: ;return file size (0-65536) + call reselect + jp getfilesize +; ret +; jp goback + +func36 equ setrandom ;set random record +; ret +; jp goback + +func37: ld hl,(info) + ld a,l + cpl + ld e,a + ld a,h + cpl + ld hl,(dlog) + and h + ld d,a + ld a,l + and e + ld e,a + ld hl,(rodsk) + ex de,hl + ld (dlog),hl + ld a,l + and e + ld l,a + ld a,h + and d + ld h,a + ld (rodsk),hl + ret + +goback: ;arrive here at end of processing to return to user + ld a,(resel) + or a + jp z,retmon + ;reselection may have taken place + ld hl,(info) + ld (hl),0 ;fcb(0)=0 + ld a,(fcbdsk) + or a + jp z,retmon + ;restore disk number + ld (hl),a ;fcb(0)=fcbdsk + ld a,(olddsk) + ld (linfo),a + call curselect + +; return from the disk monitor +retmon: ld hl,(entsp) + ld sp,hl ;user stack restored + ld hl,(aret) + ld a,l + ld b,h ;BA = HL = aret + ret + +func38 equ func$ret +func39 equ func$ret +func40: ;random disk write with zero fill of unallocated block + call reselect + ld a,2 + ld (seqio),a + ld c,false + call rseek1 + call z,diskwrite ;if seek successful + ret + +; data areas + +; initialized data +efcb: db empty ;0e5=available dir entry +rodsk: dw 0 ;read only disk vector +dlog: dw 0 ;logged-in disks +dmaad: dw tbuff ;initial dma address + +; curtrka - alloca are set upon disk select +; (data must be adjacent, do not insert variables) +; (address of translate vector, not used) +cdrmaxa: + ds word ;pointer to cur dir max value +curtrka: + ds word ;current track address +curreca: + ds word ;current record address +buffa: ds word ;pointer to directory dma address +dpbaddr: + ds word ;current disk parameter block address +checka: ds word ;current checksum vector address +alloca: ds word ;current allocation vector address +addlist equ $-buffa ;address list size + +; sectpt - offset obtained from disk parm block at dpbaddr +; (data must be adjacent, do not insert variables) +sectpt: ds word ;sectors per track +blkshf: ds byte ;block shift factor +blkmsk: ds byte ;block mask +extmsk: ds byte ;extent mask +maxall: ds word ;maximum allocation number +dirmax: ds word ;largest directory number +dirblk: ds word ;reserved allocation bits for directory +chksiz: ds word ;size of checksum vector +offset: ds word ;offset tracks at beginning +dpblist equ $-sectpt ;size of area + +; local variables +tranv: ds word ;address of translate vector +fcb$copied: + ds byte ;set true if copy$fcb called +rmf: ds byte ;read mode flag for open$reel +dirloc: ds byte ;directory flag in rename, etc. +seqio: ds byte ;1 if sequential i/o +linfo: ds byte ;low(info) +dminx: ds byte ;local for diskwrite +searchl: + ds byte ;search length +searcha: + ds word ;search address +tinfo: ds word ;temp for info in "make" +single: ds byte ;set true if single byte allocation map +resel: ds byte ;reselection flag +olddsk: ds byte ;disk on entry to bdos +fcbdsk: ds byte ;disk named in fcb +rcount: ds byte ;record count in current fcb +extval: ds byte ;extent number and extmsk +vrecord: + ds word ;current virtual record +arecord: + ds word ;current actual record +arecord1: + ds word ;current actual block# * blkmsk + +; local variables for directory access +dptr: ds byte ;directory pointer 0,1,2,3 +dcnt: ds word ;directory counter 0,1,...,dirmax +drec: ds word ;directory record 0,1,...,dirmax/4 + +;bios equ ($ and 0ff00h)+100h;next module + + end diff --git a/doug/src/dribdos.s b/doug/src/dribdos.s new file mode 100755 index 00000000..1cb3a8f2 --- /dev/null +++ b/doug/src/dribdos.s @@ -0,0 +1,2838 @@ +;-------------------------------------------------------- +; File Created by SDCC : free open source ANSI-C Compiler +; Version 3.0.2 #6489 (May 10 2011) (Mac OS X x86_64) +; This file was generated Sun May 29 01:02:12 2011 +;-------------------------------------------------------- + .module dribdos + .optsdcc -mz80 + +;-------------------------------------------------------- +; Public variables in this module +;-------------------------------------------------------- + .globl _bdos +;-------------------------------------------------------- +; special function registers +;-------------------------------------------------------- +;-------------------------------------------------------- +; ram data +;-------------------------------------------------------- + .area _DATA +;-------------------------------------------------------- +; overlayable items in ram +;-------------------------------------------------------- + .area _OVERLAY +;-------------------------------------------------------- +; external initialized ram data +;-------------------------------------------------------- +;-------------------------------------------------------- +; global & static initialisations +;-------------------------------------------------------- + .area _HOME + .area _GSINIT + .area _GSFINAL + .area _GSINIT +;-------------------------------------------------------- +; Home +;-------------------------------------------------------- + .area _HOME + .area _HOME +;-------------------------------------------------------- +; code +;-------------------------------------------------------- + .area _BDOS +;dribdos.c:4: void bdos(int argc,char **argv) +; --------------------------------- +; Function bdos +; --------------------------------- +_bdos_start:: +_bdos: +;; push ix +;; ld ix,#0 +;; add ix,sp +;; ;dribdos.c:7: } +;; pop ix +;; ret + +;; dwg ; begin DRI source code here + + .title 'Bdos Interface, Bdos, Version 2.2 Feb, 1980' + +;;dwg;;: .Z80 +;; aseg + org 100h + maclib MEMCFG.LIB ; define configuration parameters + .phase bdosph +bios equ biosph + +;***************************************************************** +;***************************************************************** +;** ** +;** B a s i c D i s k O p e r a t i n g S y s t e m ** +;** I n t e r f a c e M o d u l e ** +;** ** +;***************************************************************** +;***************************************************************** + +; Copyright (c) 1978, 1979, 1980 +; Digital Research +; Box 579, Pacific Grove +; California + + +; 20 january 1980 + +ssize equ 24 ;24 level stack + +; low memory locations +reboot equ 0000h ;reboot system +ioloc equ 0003h ;i/o byte location +bdosa equ 0006h ;address field of jp BDOS + +; bios access constants +bootf defl bios+3*0 ;cold boot function +wbootf defl bios+3*1 ;warm boot function +constf defl bios+3*2 ;console status function +coninf defl bios+3*3 ;console input function +conoutf defl bios+3*4 ;console output function +listf defl bios+3*5 ;list output function +punchf defl bios+3*6 ;punch output function +readerf defl bios+3*7 ;reader input function +homef defl bios+3*8 ;disk home function +seldskf defl bios+3*9 ;select disk function +settrkf defl bios+3*10 ;set track function +setsecf defl bios+3*11 ;set sector function +setdmaf defl bios+3*12 ;set dma function +readf defl bios+3*13 ;read disk function +writef defl bios+3*14 ;write disk function +liststf defl bios+3*15 ;list status function +sectran defl bios+3*16 ;sector translate + +; equates for non graphic characters +ctlc equ 03h ;control c +ctle equ 05h ;physical eol +ctlh equ 08h ;backspace +ctlp equ 10h ;prnt toggle +ctlr equ 12h ;repeat line +ctls equ 13h ;stop/start screen +ctlu equ 15h ;line delete +ctlx equ 18h ;=ctl-u +ctlz equ 1ah ;end of file +rubout equ 7fh ;char delete +tab equ 09h ;tab char +cr equ 0dh ;carriage return +lf equ 0ah ;line feed +ctl equ 5eh ;up arrow + + .db 0,0,0,0,0,0 + +; enter here from the user's program with function number in c, +; and information address in d,e + jp bdose ;past parameter block + +; ************************************************ +; *** relative locations 0009 - 000e *** +; ************************************************ +pererr: .dw persub ;permanent error subroutine +selerr: .dw selsub ;select error subroutine +roderr: .dw rodsub ;ro disk error subroutine +roferr: .dw rofsub ;ro file error subroutine + + +bdose: ex de,hl ;arrive here from user programs + ld (info),hl + ex de,hl ;info=DE, DE=info + ld a,e + ld (linfo),a ;linfo = low(info) - don't equ + ld hl,0 + ld (aret),hl ;return value defaults to 0000 + ;save user's stack pointer, set to local stack + add hl,sp + ld (entsp),hl ;entsp = stackptr + ld sp,lstack ;local stack setup + xor a + ld (fcbdsk),a + ld (resel),a ;fcbdsk,resel=false + ld hl,goback ;return here after all functions + push hl ;jmp goback equivalent to ret + ld a,c + cp nfuncs + ret nc ;skip if invalid # + ld c,e ;possible output character to C + ld hl,functab + ld e,a + ld d,0 ;DE=func, HL=.ciotab + add hl,de + add hl,de + ld e,(hl) + inc hl + ld d,(hl) ;DE=functab(func) + ld hl,(info) ;info in DE for later xchg + ex de,hl + jp (hl) ;dispatched + +; dispatch table for functions +functab: + dw wbootf, func1, func2, func3 + dw punchf, listf, func6, func7 + dw func8, func9, func10,func11 +diskf equ ($-functab)/2 ;disk funcs + dw func12,func13,func14,func15 + dw func16,func17,func18,func19 + dw func20,func21,func22,func23 + dw func24,func25,func26,func27 + dw func28,func29,func30,func31 + dw func32,func33,func34,func35 + dw func36,func37,func38,func39 + dw func40 +nfuncs equ ($-functab)/2 + + +; error subroutines +persub: ld hl,permsg ;report permanent error + call errflg ;to report the error + cp ctlc + jp z,reboot ;reboot if response is ctlc + ret ;and ignore the error + +selsub: ld hl,selmsg ;report select error + jp wait$err ;wait console before boot + +rodsub: ld hl,rodmsg ;report write to read/only disk + jp wait$err ;wait console + +rofsub: ;report read/only file + ld hl,rofmsg ;drop through to wait for console + +wait$err: ;wait for response before boot + call errflg + jp reboot + +; error messages +dskmsg: db 'Bdos Err On ' +dskerr: db ' : $' ;filled in by errflg +permsg: db 'Bad Sector$' +selmsg: db 'Select$' +rofmsg: db 'File ' +rodmsg: db 'R/O$' + + +errflg: push hl ;report error to console, message address in HL + call crlf ;stack mssg address, new line + ld a,(curdsk) + add a,'A' + ld (dskerr),a ;current disk name + ld bc,dskmsg + call print ;the error message + pop bc + call print ;error mssage tail +; jp conin ;to get the input character + ;(drop through to conin) +; ret + + +; console handlers +conin: ld hl,kbchar ;read console character to A + ld a,(hl) + ld (hl),0 + or a + ret nz + ;no previous keyboard character ready + jp coninf ;get character externally +; ret +conech: call conin ;read character with echo + call echoc + ret c ;echo character? + ;character must be echoed before return + push af + ld c,a + call tabout + pop af + ret ;with character in A + +echoc: ;echo character if graphic + cp cr ;cr, lf, tab, or backspace + ret z ;carriage return? + cp lf + ret z ;line feed? + cp tab + ret z ;tab? + cp ctlh + ret z ;backspace? + cp ' ' + ret ;carry set if not graphic + +conbrk: ;check for character ready + ld a,(kbchar) + or a + jp nz,conb1 ;skip if active kbchar + ;no active kbchar, check external break + call constf + and 1 + ret z ;return if no char ready + ;character ready, read it + call coninf ;to A + cp ctls + jp nz,conb0 ;check stop screen function + ;found ctls, read next character + call coninf ;to A + cp ctlc + jp z,reboot ;ctlc implies re-boot + ;not a reboot, act as if nothing has happened + xor a + ret ;with zero in accumulator +conb0: + ;character in accum, save it + ld (kbchar),a +conb1: + ;return with true set in accumulator + ld a,1 + ret + +conout: ;compute character position/write console char from C + ;compcol = true if computing column position + ld a,(compcol) + or a + jp nz,compout + ;write the character, then compute the column + ;write console character from C + push bc + call conbrk ;check for screen stop function + pop bc + push bc ;recall/save character + call conoutf ;externally, to console + pop bc + push bc ;recall/save character + ;may be copying to the list device + ld a,(listcp) + or a + call nz,listf ;to printer, if so + pop bc ;recall the character +compout: + ld a,c ;recall the character + ;and compute column position + ld hl,column ;A = char, HL = .column + cp rubout + ret z ;no column change if nulls + inc (hl) ;column = column + 1 + cp ' ' + ret nc ;return if graphic + ;not graphic, reset column position + dec (hl) ;column = column - 1 + ld a,(hl) + or a + ret z ;return if at zero + ;not at zero, may be backspace or end line + ld a,c ;character back to A + cp ctlh + jp nz,notbacksp + ;backspace character + dec (hl) ;column = column - 1 + ret + +notbacksp: ;not a backspace character, eol? + cp lf + ret nz ;return if not + ;end of line, column = 0 + ld (hl),0 ;column = 0 + ret + +ctlout: ;send C character with possible preceding up-arrow + ld a,c + call echoc ;cy if not graphic (or special case) + jp nc,tabout ;skip if graphic, tab, cr, lf, or ctlh + ;send preceding up arrow + push af + ld c,ctl + call conout ;up arrow + pop af + or 40h ;becomes graphic letter + ld c,a ;ready to print + ;(drop through to tabout) + +tabout: ;expand tabs to console + ld a,c + cp tab + jp nz,conout ;direct to conout if not + ;tab encountered, move to next tab position +tab0: ld c,' ' + call conout ;another blank + ld a,(column) + and 111b ;column mod 8 = 0 ? + jp nz,tab0 ;back for another if not + ret + +backup: ;back-up one screen position + call pctlh + ld c,' ' + call conoutf +; (drop through to pctlh) +pctlh: ;send ctlh to console without affecting column count + ld c,ctlh + jp conoutf +; ret +crlfp: ;print #, cr, lf for ctlx, ctlu, ctlr functions + ;then move to strtcol (starting column) + ld c,'#' + call conout + call crlf ;column = 0, move to position strtcol +crlfp0: ld a,(column) + ld hl,strtcol + cp (hl) + ret nc ;stop when column reaches strtcol + ld c,' ' + call conout ;print blank + jp crlfp0 + +crlf: ld c,cr ;carriage return line feed sequence + call conout + ld c,lf + jp conout +; ret +print: ld a,(bc) ;print message until M(BC) = '$' + cp '$' + ret z ;stop on $ + ;more to print + inc bc + push bc + ld c,a ;char to C + call tabout ;another character printed + pop bc + jp print + +read: ;read to info address (max length, current length, buffer) + ld a,(column) + ld (strtcol),a ;save start for ctl-x, ctl-h + ld hl,(info) + ld c,(hl) + inc hl + push hl + ld b,0 + ;B = current buffer length, + ;C = maximum buffer length, + ;HL= next to fill - 1 +readnx: ;read next character, BC, HL active + push bc + push hl ;blen, cmax, HL saved +readn0: call conin ;next char in A + and 7fh ;mask parity bit + pop hl + pop bc ;reactivate counters + cp cr + jp z,readen ;end of line? + cp lf + jp z,readen ;also end of line + cp ctlh + jp nz,noth ;backspace? + ;do we have any characters to back over? + ld a,b + or a + jp z,readnx + ;characters remain in buffer, backup one + dec b ;remove one character + ld a,(column) + ld (compcol),a ;col > 0 + ;compcol > 0 marks repeat as length compute + jp linelen ;uses same code as repeat + +noth: ;not a backspace + cp rubout + jp nz,notrub ;rubout char? + ;rubout encountered, rubout if possible + ld a,b + or a + jp z,readnx ;skip if len=0 + ;buffer has characters, resend last char + ld a,(hl) + dec b + dec hl ;A = last char + ;blen=blen-1, next to fill - 1 decremented + jp rdech1 ;act like this is an echo + +notrub: ;not a rubout character, check end line + cp ctle + jp nz,note ;physical end line? + ;yes, save active counters and force eol + push bc + push hl + call crlf + xor a + ld (strtcol),a ;start position = 00 + jp readn0 ;for another character + +note: ;not end of line, list toggle? + cp ctlp + jp nz,notp ;skip if not ctlp + ;list toggle - change parity + push hl ;save next to fill - 1 + ld hl,listcp ;HL=.listcp flag + ld a,1 + sub (hl) ;True-listcp + ld (hl),a ;listcp = not listcp + pop hl + jp readnx ;for another char + +notp: ;not a ctlp, line delete? + cp ctlx + jp nz,notx + pop hl ;discard start position + ;loop while column > strtcol +backx: ld a,(strtcol) + ld hl,column + cp (hl) + jp nc,read ;start again + dec (hl) ;column = column - 1 + call backup ;one position + jp backx + +notx: ;not a control x, control u? + ;not control-X, control-U? + cp ctlu + jp nz,notu ;skip if not + ;delete line (ctlu) + call crlfp ;physical eol + pop hl ;discard starting position + jp read ;to start all over + +notu: ;not line delete, repeat line? + cp ctlr + jp nz,notr +linelen: ;repeat line, or compute line len (ctlh) + ;if compcol > 0 + push bc + call crlfp ;save line length + pop bc + pop hl + push hl + push bc + ;bcur, cmax active, beginning buff at HL +rep0: ld a,b + or a + jp z,rep1 ;count len to 00 + inc hl + ld c,(hl) ;next to print + dec b + push bc + push hl ;count length down + call ctlout ;character echoed + pop hl + pop bc ;recall remaining count + jp rep0 ;for the next character + +rep1: ;end of repeat, recall lengths + ;original BC still remains pushed + push hl ;save next to fill + ld a,(compcol) + or a ;>0 if computing length + jp z,readn0 ;for another char if so + ;column position computed for ctlh + ld hl,column + sub (hl) ;diff > 0 + ld (compcol),a ;count down below + ;move back compcol-column spaces +backsp: ;move back one more space + call backup ;one space + ld hl,compcol + dec (hl) + jp nz,backsp + jp readn0 ;for next character + +notr: ;not a ctlr, place into buffer +rdecho: inc hl + ld (hl),a ;character filled to mem + inc b ;blen = blen + 1 +rdech1: ;look for a random control character + push bc + push hl ;active values saved + ld c,a ;ready to print + call ctlout ;may be up-arrow C + pop hl + pop bc + ld a,(hl) ;recall char + cp ctlc ;set flags for reboot test + ld a,b ;move length to A + jp nz,notc ;skip if not a control c + cp 1 ;control C, must be length 1 + jp z,reboot ;reboot if blen = 1 + ;length not one, so skip reboot +notc: ;not reboot, are we at end of buffer? + cp c + jp c,readnx ;go for another if not +readen: ;end of read operation, store blen + pop hl + ld (hl),b ;M(current len) = B + ld c,cr + jp conout ;return carriage +; ret +func1: ;return console character with echo + call conech + jp sta$ret + +func2 equ tabout + ;write console character with tab expansion + +func3: ;return reader character + call readerf + jp sta$ret + +;func4: equated to punchf + ;write punch character + +;func5: equated to listf + ;write list character + ;write to list device + +func6: ;direct console i/o - read if 0ffh + ld a,c + inc a + jp z,dirinp ;0ffh => 00h, means input mode + inc a + jp z,constf ;0feH in C for status + ;direct output function + jp conoutf + +dirinp: call constf ;status check + or a + jp z,retmon ;skip, return 00 if not ready + ;character is ready, get it + call coninf ;to A + jp sta$ret + +func7: ;return io byte + ld a,(ioloc) + jp sta$ret + +func8: ;set i/o byte + ld hl,ioloc + ld (hl),c + ret ;jmp goback + +func9: ;write line until $ encountered + ex de,hl ;was lhld info + ld c,l + ld b,h ;BC=string address + jp print ;out to console + +func10 equ read + ;read a buffered console line + +func11: ;check console status + call conbrk + ;(drop through to sta$ret) +sta$ret: ;store the A register to aret + ld (aret),a +func$ret: + ret ;jmp goback (pop stack for non cp/m functions) + +setlret1: ;set lret = 1 + ld a,1 + jp sta$ret + + + +; data areas + +compcol: + db 0 ;true if computing column position +strtcol: + db 0 ;starting column position after read +column: db 0 ;column position +listcp: db 0 ;listing toggle +kbchar: db 0 ;initial key char = 00 +entsp: ds 2 ;entry stack pointer + ds ssize*2 ;stack size +lstack: +; end of Basic I/O System + +;***************************************************************** +;***************************************************************** + +; common values shared between bdosi and bdos +usrcode: + db 0 ;current user number +curdsk: db 0 ;current disk number +info: ds 2 ;information address +aret: ds 2 ;address value to return +lret equ aret ;low(aret) + +;***************************************************************** +;***************************************************************** +;** ** +;** B a s i c D i s k O p e r a t i n g S y s t e m ** +;** ** +;***************************************************************** +;***************************************************************** + +dvers equ 22h ;version 2.2 +; module addresses + +; literal constants +true equ 0ffh ;constant true +false equ 000h ;constant false +enddir equ 0ffffh ;end of directory +byte equ 1 ;number of bytes for "byte" type +word equ 2 ;number of bytes for "word" type + +; fixed addresses in low memory +tfcb equ 005ch ;default fcb location +tbuff equ 0080h ;default buffer location + +; fixed addresses referenced in bios module are +; pererr (0009), selerr (000c), roderr (000f) + +; error message handlers + +;per$error: ;report permanent error to user +; ld hl,pererr +; jp goerr + +;rod$error: ;report read/only disk error +; ld hl,roderr +; jp goerr + +;rof$error: ;report read/only file error +; ld hl,roferr +; jp goerr + +sel$error: ;report select error + ld hl,selerr + + +goerr: ;HL = .errorhandler, call subroutine + ld e,(hl) + inc hl + ld d,(hl) ;address of routine in DE + ex de,hl + jp (hl) ;to subroutine + + + +; local subroutines for bios interface + +move: ;move data length of length C from source DE to + ;destination given by HL + inc c ;in case it is zero +move0: dec c + ret z ;more to move + ld a,(de) + ld (hl),a ;one byte moved + inc de + inc hl ;to next byte + jp move0 + +selectdisk: ;select the disk drive given by curdsk, and fill + ;the base addresses curtrka - alloca, then fill + ;the values of the disk parameter block + ld a,(curdsk) + ld c,a ;current disk# to c + ;lsb of e = 0 if not yet logged - in + call seldskf ;HL filled by call + ;HL = 0000 if error, otherwise disk headers + ld a,h + or l + ret z ;return with 0000 in HL and z flag + ;disk header block address in hl + ld e,(hl) + inc hl + ld d,(hl) + inc hl ;DE=.tran + ld (cdrmaxa),hl + inc hl + inc hl ;.cdrmax + ld (curtrka),hl + inc hl + inc hl ;HL=.currec + ld (curreca),hl + inc hl + inc hl ;HL=.buffa + ;DE still contains .tran + ex de,hl + ld (tranv),hl ;.tran vector + ld hl,buffa ;DE= source for move, HL=dest + ld c,addlist + call move ;addlist filled + ;now fill the disk parameter block + ld hl,(dpbaddr) + ex de,hl ;DE is source + ld hl,sectpt ;HL is destination + ld c,dpblist + call move ;data filled + ;now set single/double map mode + ld hl,(maxall) ;largest allocation number + ld a,h ;00 indicates < 255 + ld hl,single + ld (hl),true ;assume a=00 + or a + jp z,retselect + ;high order of maxall not zero, use double dm + ld (hl),false +retselect: + ld a,true + or a + ret ;select disk function ok + +home: ;move to home position, then offset to start of dir + call homef ;move to track 00, sector 00 reference + ;lxi h,offset ;mov c,m ;inx h ;mov b,m ;call settrkf + ;first directory position selected + xor a ;constant zero to accumulator + ld hl,(curtrka) + ld (hl),a + inc hl + ld (hl),a ;curtrk=0000 + ld hl,(curreca) + ld (hl),a + inc hl + ld (hl),a ;currec=0000 + ;curtrk, currec both set to 0000 + ret + +rdbuff: ;read buffer and check condition + call readf ;current drive, track, sector, dma + jp diocomp ;check for i/o errors + +wrbuff: ;write buffer and check condition + ;write type (wrtype) is in register C + ;wrtype = 0 => normal write operation + ;wrtype = 1 => directory write operation + ;wrtype = 2 => start of new block + call writef ;current drive, track, sector, dma +diocomp: ;check for disk errors + or a + ret z + ld hl,pererr + jp goerr + +seek$dir: ;seek the record containing the current dir entry + ld hl,(dcnt) ;directory counter to HL + ld c,dskshf + call hlrotr ;value to HL + ld (arecord),hl + ld (drec),hl ;ready for seek +; jp seek +; ret + + +seek: ;seek the track given by arecord (actual record) + ;local equates for registers + ;load the registers from memory + ld hl,arecord + ld c,(hl) + inc hl + ld b,(hl) + ld hl,(curreca) + ld e,(hl) + inc hl + ld d,(hl) + ld hl,(curtrka) + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + ;loop while arecord < currec +seek0: ld a,c + sub e + ld a,b + sbc a,d + jp nc,seek1 ;skip if arecord >= currec + ;currec = currec - sectpt + push hl + ld hl,(sectpt) + ld a,e + sub l + ld e,a + ld a,d + sbc a,h + ld d,a + pop hl + ;curtrk = curtrk - 1 + dec hl + jp seek0 ;for another try + +seek1: ;look while arecord >= (t:=currec + sectpt) + push hl + ld hl,(sectpt) + add hl,de ;HL = currec+sectpt + jp c,seek2 ;can be > FFFFH + ld a,c + sub l + ld a,b + sbc a,h + jp c,seek2 ;skip if t > arecord + ;currec = t + ex de,hl + ;curtrk = curtrk + 1 + pop hl + inc hl + jp seek1 ;for another try + +seek2: pop hl + ;arrive here with updated values in each register + push bc + push de + push hl ;to stack for later + ;stack contains (lowest) BC=arecord, DE=currec, HL=curtrk + ex de,hl + ld hl,(offset) + add hl,de ;HL = curtrk+offset + ld b,h + ld c,l + call settrkf ;track set up + ;note that BC - curtrk is difference to move in bios + pop de ;recall curtrk + ld hl,(curtrka) + ld (hl),e + inc hl + ld (hl),d ;curtrk updated + ;now compute sector as arecord-currec + pop de ;recall currec + ld hl,(curreca) + ld (hl),e + inc hl + ld (hl),d + pop bc ;BC=arecord, DE=currec + ld a,c + sub e + ld c,a + ld a,b + sbc a,d + ld b,a + ld hl,(tranv) + ex de,hl ;BC=sector#, DE=.tran + call sectran ;HL = tran(sector) + ld c,l + ld b,h ;BC = tran(sector) + jp setsecf ;sector selected +; ret + +; file control block (fcb) constants +empty equ 0e5h ;empty directory entry +lstrec equ 127 ;last record# in extent +recsiz equ 128 ;record size +fcblen equ 32 ;file control block size +dirrec equ recsiz/fcblen ;directory elts / record +dskshf equ 2 ;log2(dirrec) +dskmsk equ dirrec-1 +fcbshf equ 5 ;log2(fcblen) + +extnum equ 12 ;extent number field +maxext equ 31 ;largest extent number +ubytes equ 13 ;unfilled bytes field +modnum equ 14 ;data module number +maxmod equ 15 ;largest module number +fwfmsk equ 80h ;file write flag is high order modnum +namlen equ 15 ;name length +reccnt equ 15 ;record count field +dskmap equ 16 ;disk map field +lstfcb equ fcblen-1 +nxtrec equ fcblen +ranrec equ nxtrec+1 ;random record field (2 bytes) + +; reserved file indicators +rofile equ 9 ;high order of first type char +invis equ 10 ;invisible file in dir command +; equ 11 ;reserved + +; utility functions for file access + +dm$position: ;compute disk map position for vrecord to HL + ld hl,blkshf + ld c,(hl) ;shift count to C + ld a,(vrecord) ;current virtual record to A +dmpos0: or a + rra + dec c + jp nz,dmpos0 + ;A = shr(vrecord,blkshf) = vrecord/2**(sect/block) + ld b,a ;save it for later addition + ld a,8 + sub (hl) ;8-blkshf to accumulator + ld c,a ;extent shift count in register c + ld a,(extval) ;extent value ani extmsk +dmpos1: + ;blkshf = 3,4,5,6,7, C=5,4,3,2,1 + ;shift is 4,3,2,1,0 + dec c + jp z,dmpos2 + or a + rla + jp dmpos1 + +dmpos2: ;arrive here with A = shl(ext and extmsk,7-blkshf) + add a,b ;add the previous shr(vrecord,blkshf) value + ;A is one of the following values, depending upon alloc + ;bks blkshf + ;1k 3 v/8 + extval * 16 + ;2k 4 v/16+ extval * 8 + ;4k 5 v/32+ extval * 4 + ;8k 6 v/64+ extval * 2 + ;16k 7 v/128+extval * 1 + ret ;with dm$position in A + +getdm: ;return disk map value from position given by BC + ld hl,(info) ;base address of file control block + ld de,dskmap + add hl,de ;HL =.diskmap + add hl,bc ;index by a single byte value + ld a,(single) ;single byte/map entry? + or a + jp z,getdmd ;get disk map single byte + ld l,(hl) + ld h,0 + ret ;with HL=00bb +getdmd: + add hl,bc ;HL=.fcb(dm+i*2) + ;double precision value returned + ld e,(hl) + inc hl + ld d,(hl) + ex de,hl + ret + +index: ;compute disk block number from current fcb + call dm$position ;0...15 in register A + ld c,a + ld b,0 + call getdm ;value to HL + ld (arecord),hl + ret + +allocated: ;called following index to see if block allocated + ld hl,(arecord) + ld a,l + or h + ret + +atran: ;compute actual record address, assuming index called + ld a,(blkshf) ;shift count to reg A + ld hl,(arecord) +atran0: add hl,hl + dec a + jp nz,atran0 ;shl(arecord,blkshf) + ld (arecord1),hl ;save shifted block # + ld a,(blkmsk) + ld c,a ;mask value to C + ld a,(vrecord) + and c ;masked value in A + or l + ld l,a ;to HL + ld (arecord),hl ;arecord=HL or (vrecord and blkmsk) + ret + +getexta: ;get current extent field address to A + ld hl,(info) + ld de,extnum + add hl,de ;HL=.fcb(extnum) + ret + +getfcba: ;compute reccnt and nxtrec addresses for get/setfcb + ld hl,(info) + ld de,reccnt + add hl,de + ex de,hl ;DE=.fcb(reccnt) + ld hl,nxtrec-reccnt + add hl,de ;HL=.fcb(nxtrec) + ret + +getfcb: ;set variables from currently addressed fcb + call getfcba ;addresses in DE, HL + ld a,(hl) + ld (vrecord),a ;vrecord=fcb(nxtrec) + ex de,hl + ld a,(hl) + ld (rcount),a ;rcount=fcb(reccnt) + call getexta ;HL=.fcb(extnum) + ld a,(extmsk) ;extent mask to a + and (hl) ;fcb(extnum) and extmsk + ld (extval),a + ret + +setfcb: ;place values back into current fcb + call getfcba ;addresses to DE, HL + ld a,(seqio) + cp 02 + jp nz,setfcb1 + xor a ;check ranfill +setfcb1: + ld c,a ;=1 if sequential i/o + ld a,(vrecord) + add a,c + ld (hl),a ;fcb(nxtrec)=vrecord+seqio + ex de,hl + ld a,(rcount) + ld (hl),a ;fcb(reccnt)=rcount + ret + +hlrotr: ;hl rotate right by amount C + inc c ;in case zero +hlrotr0: + dec c + ret z ;return when zero + ld a,h + or a + rra + ld h,a ;high byte + ld a,l + rra + ld l,a ;low byte + jp hlrotr0 + +compute$cs: ;compute checksum for current directory buffer + ld c,recsiz ;size of directory buffer + ld hl,(buffa) ;current directory buffer + xor a ;clear checksum value +computecs0: + add a,(hl) + inc hl + dec c ;cs=cs+buff(recsiz-C) + jp nz,computecs0 + ret ;with checksum in A + +hlrotl: ;rotate the mask in HL by amount in C + inc c ;may be zero +hlrotl0: + dec c + ret z ;return if zero + add hl,hl + jp hlrotl0 + +set$cdisk: ;set a "1" value in curdsk position of BC + push bc ;save input parameter + ld a,(curdsk) + ld c,a ;ready parameter for shift + ld hl,1 ;number to shift + call hlrotl ;HL = mask to integrate + pop bc ;original mask + ld a,c + or l + ld l,a + ld a,b + or h + ld h,a ;HL = mask or rol(1,curdsk) + ret + +nowrite: ;return true if dir checksum difference occurred + ld hl,(rodsk) + ld a,(curdsk) + ld c,a + call hlrotr + ld a,l + and 1b + ret ;non zero if nowrite + +set$ro: ;set current disk to read only + ld hl,rodsk + ld c,(hl) + inc hl + ld b,(hl) + call set$cdisk ;sets bit to 1 + ld (rodsk),hl + ;high water mark in directory goes to max + ld hl,(dirmax) + inc hl + ex de,hl ;DE = directory max + ld hl,(cdrmaxa) ;HL = .cdrmax + ld (hl),e + inc hl + ld (hl),d ;cdrmax = dirmax + ret + +check$rodir: ;check current directory element for read/only status + call getdptra ;address of element + +check$rofile: ;check current buff(dptr) or fcb(0) for r/o status + ld de,rofile + add hl,de ;offset to ro bit + ld a,(hl) + rla + ret nc ;return if not set + ld hl,roferr + jp goerr +; jp rof$error ;exit to read only disk message + + +check$write: ;check for write protected disk + call nowrite + ret z ;ok to write if not rodsk + ld hl,roderr + jp goerr +; jp rod$error ;read only disk error + +getdptra: ;compute the address of a directory element at + ;positon dptr in the buffer + ld hl,(buffa) + ld a,(dptr) +addh: ;HL = HL + A + add a,l + ld l,a + ret nc + ;overflow to H + inc h + ret + + +getmodnum: ;compute the address of the module number + ;bring module number to accumulator + ;(high order bit is fwf (file write flag) + ld hl,(info) + ld de,modnum + add hl,de ;HL=.fcb(modnum) + ld a,(hl) + ret ;A=fcb(modnum) + +clrmodnum: ;clear the module number field for user open/make + call getmodnum + ld (hl),0 ;fcb(modnum)=0 + ret + +setfwf: call getmodnum ;HL=.fcb(modnum), A=fcb(modnum) + ;set fwf (file write flag) to "1" + or fwfmsk + ld (hl),a ;fcb(modnum)=fcb(modnum) or 80h + ;also returns non zero in accumulator + ret + + +compcdr: ;return cy if cdrmax > dcnt + ld hl,(dcnt) + ex de,hl ;DE = directory counter + ld hl,(cdrmaxa) ;HL=.cdrmax + ld a,e + sub (hl) ;low(dcnt) - low(cdrmax) + inc hl ;HL = .cdrmax+1 + ld a,d + sbc a,(hl) ;hig(dcnt) - hig(cdrmax) + ;condition dcnt - cdrmax produces cy if cdrmax>dcnt + ret + +setcdr: ;if not (cdrmax > dcnt) then cdrmax = dcnt+1 + call compcdr + ret c ;return if cdrmax > dcnt + ;otherwise, HL = .cdrmax+1, DE = dcnt + inc de + ld (hl),d + dec hl + ld (hl),e + ret + +subdh: ;compute HL = DE - HL + ld a,e + sub l + ld l,a + ld a,d + sbc a,h + ld h,a + ret + +newchecksum: + ld c,true ;drop through to compute new checksum +checksum: ;compute current checksum record and update the + ;directory element if C=true, or check for = if not + ;drec < chksiz? + ld hl,(drec) + ex de,hl + ld hl,(chksiz) + call subdh ;DE-HL + ret nc ;skip checksum if past checksum vector size + ;drec < chksiz, so continue + push bc ;save init flag + call compute$cs ;check sum value to A + ld hl,(checka) ;address of check sum vector + ex de,hl + ld hl,(drec) ;value of drec + add hl,de ;HL = .check(drec) + pop bc ;recall true=0ffh or false=00 to C + inc c ;0ffh produces zero flag + jp z,initial$cs + ;not initializing, compare + cp (hl) ;compute$cs=check(drec)? + ret z ;no message if ok + ;checksum error, are we beyond + ;the end of the disk? + call compcdr + ret nc ;no message if so + call set$ro ;read/only disk set + ret + +initial$cs: ;initializing the checksum + ld (hl),a + ret + + +wrdir: ;write the current directory entry, set checksum + call newchecksum ;initialize entry + call setdir ;directory dma + ld c,1 ;indicates a write directory operation + call wrbuff ;write the buffer + jp setdata ;to data dma address +; ret +rd$dir: ;read a directory entry into the directory buffer + call setdir ;directory dma + call rdbuff ;directory record loaded + ;jmp setdata to data dma address +; ret +setdata: ;set data dma address + ld hl,dmaad + jp setdma ;to complete the call + +setdir: ;set directory dma address + ld hl,buffa ;jmp setdma to complete call + +setdma: ;HL=.dma address to set (i.e., buffa or dmaad) + ld c,(hl) + inc hl + ld b,(hl) ;parameter ready + jp setdmaf + +dir$to$user: ;copy the directory entry to the user buffer + ;after call to search or searchn by user code + ld hl,(buffa) + ex de,hl ;source is directory buffer + ld hl,(dmaad) ;destination is user dma address + ld c,recsiz ;copy entire record + jp move +; ret + +end$of$dir: ;return zero flag if at end of directory, non zero + ;if not at end (end of dir if dcnt = 0ffffh) + ld hl,dcnt + ld a,(hl) ;may be 0ffh + inc hl + cp (hl) ;low(dcnt) = high(dcnt)? + ret nz ;non zero returned if different + ;high and low the same, = 0ffh? + inc a ;0ffh becomes 00 if so + ret + +set$end$dir: ;set dcnt to the end of the directory + ld hl,enddir + ld (dcnt),hl + ret + +read$dir: ;read next directory entry, with C=true if initializing + ld hl,(dirmax) + ex de,hl ;in preparation for subtract + ld hl,(dcnt) + inc hl + ld (dcnt),hl ;dcnt=dcnt+1 + ;continue while dirmax >= dcnt (dirmax-dcnt no cy) + call subdh ;DE-HL + jp nc,read$dir0 + ;yes, set dcnt to end of directory + jp set$end$dir +; ret + +read$dir0: ;not at end of directory, seek next element + ;initialization flag is in C + ld a,(dcnt) + and dskmsk ;low(dcnt) and dskmsk + ld b,fcbshf ;to multiply by fcb size +read$dir1: + add a,a + dec b + jp nz,read$dir1 + ;A = (low(dcnt) and dskmsk) shl fcbshf + ld (dptr),a ;ready for next dir operation + or a + ret nz ;return if not a new record + push bc ;save initialization flag C + call seek$dir ;seek proper record + call rd$dir ;read the directory record + pop bc ;recall initialization flag + jp checksum ;checksum the directory elt +; ret + + +getallocbit: ;given allocation vector position BC, return with byte + ;containing BC shifted so that the least significant + ;bit is in the low order accumulator position. HL is + ;the address of the byte for possible replacement in + ;memory upon return, and D contains the number of shifts + ;required to place the returned value back into position + ld a,c + and 111b + inc a + ld e,a + ld d,a + ;d and e both contain the number of bit positions to shift + ld a,c + rrca + rrca + rrca + and 11111b + ld c,a ;C shr 3 to C + ld a,b + add a,a + add a,a + add a,a + add a,a + add a,a ;B shl 5 + or c + ld c,a ;bbbccccc to C + ld a,b + rrca + rrca + rrca + and 11111b + ld b,a ;BC shr 3 to BC + ld hl,(alloca) ;base address of allocation vector + add hl,bc + ld a,(hl) ;byte to A, hl = .alloc(BC shr 3) + ;now move the bit to the low order position of A +rotl: rlca + dec e + jp nz,rotl + ret + + +set$alloc$bit: ;BC is the bit position of ALLOC to set or reset. The + ;value of the bit is in register E. + push de + call getallocbit ;shifted val A, count in D + and 11111110b ;mask low bit to zero (may be set) + pop bc + or c ;low bit of C is masked into A +; jp rotr ;to rotate back into proper position +; ret +rotr: + ;byte value from ALLOC is in register A, with shift count + ;in register C (to place bit back into position), and + ;target ALLOC position in registers HL, rotate and replace + rrca + dec d + jp nz,rotr ;back into position + ld (hl),a ;back to ALLOC + ret + +scandm: ;scan the disk map addressed by dptr for non-zero + ;entries, the allocation vector entry corresponding + ;to a non-zero entry is set to the value of C (0,1) + call getdptra ;HL = buffa + dptr + ;HL addresses the beginning of the directory entry + ld de,dskmap + add hl,de ;hl now addresses the disk map + push bc ;save the 0/1 bit to set + ld c,fcblen-dskmap+1;size of single byte disk map + 1 +scandm0: ;loop once for each disk map entry + pop de ;recall bit parity + dec c + ret z ;all done scanning? + ;no, get next entry for scan + push de ;replace bit parity + ld a,(single) + or a + jp z,scandm1 + ;single byte scan operation + push bc ;save counter + push hl ;save map address + ld c,(hl) + ld b,0 ;BC=block# + jp scandm2 + +scandm1: ;double byte scan operation + dec c ;count for double byte + push bc ;save counter + ld c,(hl) + inc hl + ld b,(hl) ;BC=block# + push hl ;save map address +scandm2: ;arrive here with BC=block#, E=0/1 + ld a,c + or b ;skip if = 0000 + jp z,scanm3 + ld hl,(maxall) ;check invalid index + ld a,l + sub c + ld a,h + sbc a,b ;maxall - block# + call nc,set$alloc$bit + ;bit set to 0/1 +scanm3: pop hl + inc hl ;to next bit position + pop bc ;recall counter + jp scandm0 ;for another item + +initialize: ;initialize the current disk + ;lret = false ;set to true if $ file exists + ;compute the length of the allocation vector - 2 + ld hl,(maxall) + ld c,3 ;perform maxall/8 + ;number of bytes in alloc vector is (maxall/8)+1 + call hlrotr + inc hl ;HL = maxall/8+1 + ld b,h + ld c,l ;count down BC til zero + ld hl,(alloca) ;base of allocation vector + ;fill the allocation vector with zeros +initial0: + ld (hl),0 + inc hl ;alloc(i)=0 + dec bc ;count length down + ld a,b + or c + jp nz,initial0 + ;set the reserved space for the directory + ld hl,(dirblk) + ex de,hl + ld hl,(alloca) ;HL=.alloc() + ld (hl),e + inc hl + ld (hl),d ;sets reserved directory blks + ;allocation vector initialized, home disk + call home + ;cdrmax = 3 (scans at least one directory record) + ld hl,(cdrmaxa) + ld (hl),3 + inc hl + ld (hl),0 + ;cdrmax = 0000 + call set$end$dir ;dcnt = enddir + ;read directory entries and check for allocated storage +initial2: + ld c,true + call read$dir + call end$of$dir + ret z ;return if end of directory + ;not end of directory, valid entry? + call getdptra ;HL = buffa + dptr + ld a,empty + cp (hl) + jp z,initial2 ;go get another item + ;not empty, user code the same? + ld a,(usrcode) + cp (hl) + jp nz,pdollar + ;same user code, check for '$' submit + inc hl + ld a,(hl) ;first character + sub '$' ;dollar file? + jp nz,pdollar + ;dollar file found, mark in lret + dec a + ld (lret),a ;lret = 255 +pdollar: ;now scan the disk map for allocated blocks + ld c,1 ;set to allocated + call scandm + call setcdr ;set cdrmax to dcnt + jp initial2 ;for another entry + +copy$dirloc: ;copy directory location to lret following + ;delete, rename, ... ops + ld a,(dirloc) + jp sta$ret +; ret + +compext: ;compare extent# in A with that in C, return nonzero + ;if they do not match + push bc ;save C's original value + push af + ld a,(extmsk) + cpl + ld b,a + ;B has negated form of extent mask + ld a,c + and b + ld c,a ;low bits removed from C + pop af + and b ;low bits removed from A + sub c + and maxext ;set flags + pop bc ;restore original values + ret + +search: ;search for directory element of length C at info + ld a,0ffh + ld (dirloc),a ;changed if actually found + ld hl,searchl + ld (hl),c ;searchl = C + ld hl,(info) + ld (searcha),hl ;searcha = info + call set$end$dir ;dcnt = enddir + call home ;to start at the beginning + ;(drop through to searchn) + +searchn: ;search for the next directory element, assuming + ;a previous call on search which sets searcha and + ;searchl + ld c,false + call read$dir ;read next dir element + call end$of$dir + jp z,search$fin ;skip to end if so + ;not end of directory, scan for match + ld hl,(searcha) + ex de,hl ;DE=beginning of user fcb + ld a,(de) ;first character + cp empty ;keep scanning if empty + jp z,searchnext + ;not empty, may be end of logical directory + push de ;save search address + call compcdr ;past logical end? + pop de ;recall address + jp nc,search$fin ;artificial stop +searchnext: + call getdptra ;HL = buffa+dptr + ld a,(searchl) + ld c,a ;length of search to c + ld b,0 ;b counts up, c counts down +searchloop: + ld a,c + or a + jp z,endsearch + ld a,(de) + cp '?' + jp z,searchok ;? matches all + ;scan next character if not ubytes + ld a,b + cp ubytes + jp z,searchok + ;not the ubytes field, extent field? + cp extnum ;may be extent field + ld a,(de) ;fcb character + jp z,searchext ;skip to search extent + sub (hl) + and 7fh ;mask-out flags/extent modulus + jp nz,searchn ;skip if not matched + jp searchok ;matched character + +searchext: ;A has fcb character + ;attempt an extent # match + push bc ;save counters + ld c,(hl) ;directory character to c + call compext ;compare user/dir char + pop bc ;recall counters + jp nz,searchn ;skip if no match +searchok: ;current character matches + inc de + inc hl + inc b + dec c + jp searchloop + +endsearch: ;entire name matches, return dir position + ld a,(dcnt) + and dskmsk + ld (lret),a + ;lret = low(dcnt) and 11b + ld hl,dirloc + ld a,(hl) + rla + ret nc ;dirloc=0ffh? + ;yes, change it to 0 to mark as found + xor a + ld (hl),a ;dirloc=0 + ret + +search$fin: ;end of directory, or empty name + call set$end$dir ;may be artifical end + ld a,255 + jp sta$ret + +delete: ;delete the currently addressed file + call check$write ;write protected? + ld c,extnum + call search ;search through file type +delete0: + ;loop while directory matches + call end$of$dir + ret z ;stop if end + ;set each non zero disk map entry to 0 + ;in the allocation vector + ;may be r/o file + call check$rodir ;ro disk error if found + call getdptra ;HL=.buff(dptr) + ld (hl),empty + ld c,0 + call scandm ;alloc elts set to 0 + call wrdir ;write the directory + call searchn ;to next element + jp delete0 ;for another record + +get$block: ;given allocation vector position BC, find the zero bit + ;closest to this position by searching left and right. + ;if found, set the bit to one and return the bit position + ;in hl. if not found (i.e., we pass 0 on the left, or + ;maxall on the right), return 0000 in hl + ld d,b + ld e,c ;copy of starting position to de +lefttst: + ld a,c + or b + jp z,righttst ;skip if left=0000 + ;left not at position zero, bit zero? + dec bc + push de + push bc ;left,right pushed + call getallocbit + rra + jp nc,retblock ;return block number if zero + ;bit is one, so try the right + pop bc + pop de ;left, right restored +righttst: + ld hl,(maxall) ;value of maximum allocation# + ld a,e + sub l + ld a,d + sbc a,h ;right=maxall? + jp nc,retblock0 ;return block 0000 if so + inc de + push bc + push de ;left, right pushed + ld b,d + ld c,e ;ready right for call + call getallocbit + rra + jp nc,retblock ;return block number if zero + pop de + pop bc ;restore left and right pointers + jp lefttst ;for another attempt +retblock: + rla + inc a ;bit back into position and set to 1 + ;d contains the number of shifts required to reposition + call rotr ;move bit back to position and store + pop hl + pop de ;HL returned value, DE discarded + ret + +retblock0: ;cannot find an available bit, return 0000 + ld a,c + or b + jp nz,lefttst ;also at beginning + ld hl,0000h + ret + +copy$fcb: ;copy the entire file control block + ld c,0 + ld e,fcblen ;start at 0, to fcblen-1 +; jp copy$dir + +copy$dir: ;copy fcb information starting at C for E bytes + ;into the currently addressed directory entry + push de ;save length for later + ld b,0 ;double index to BC + ld hl,(info) ;HL = source for data + add hl,bc + ex de,hl ;DE=.fcb(C), source for copy + call getdptra ;HL=.buff(dptr), destination + pop bc ;DE=source, HL=dest, C=length + call move ;data moved +seek$copy: ;enter from close to seek and copy current element + call seek$dir ;to the directory element + jp wrdir ;write the directory element +; ret +rename: ;rename the file described by the first half of + ;the currently addressed file control block. the + ;new name is contained in the last half of the + ;currently addressed file conrol block. the file + ;name and type are changed, but the reel number + ;is ignored. the user number is identical + call check$write ;may be write protected + ;search up to the extent field + ld c,extnum + call search + ;copy position 0 + ld hl,(info) + ld a,(hl) ;HL=.fcb(0), A=fcb(0) + ld de,dskmap + add hl,de ;HL=.fcb(dskmap) + ld (hl),a ;fcb(dskmap)=fcb(0) + ;assume the same disk drive for new named file +rename0: + call end$of$dir + ret z ;stop at end of dir + ;not end of directory, rename next element + call check$rodir ;may be read-only file + ld c,dskmap + ld e,extnum + call copy$dir + ;element renamed, move to next + call searchn + jp rename0 + +indicators: ;set file indicators for current fcb + ld c,extnum + call search ;through file type +indic0: call end$of$dir + ret z ;stop at end of dir + ;not end of directory, continue to change + ld c,0 + ld e,extnum ;copy name + call copy$dir + call searchn + jp indic0 + +open: ;search for the directory entry, copy to fcb + ld c,namlen + call search + call end$of$dir + ret z ;return with lret=255 if end + ;not end of directory, copy fcb information +open$copy: ;(referenced below to copy fcb info) + call getexta + ld a,(hl) + push af + push hl ;save extent# + call getdptra + ex de,hl ;DE = .buff(dptr) + ld hl,(info) ;HL=.fcb(0) + ld c,nxtrec ;length of move operation + push de ;save .buff(dptr) + call move ;from .buff(dptr) to .fcb(0) + ;note that entire fcb is copied, including indicators + call setfwf ;sets file write flag + pop de + ld hl,extnum + add hl,de ;HL=.buff(dptr+extnum) + ld c,(hl) ;C = directory extent number + ld hl,reccnt + add hl,de ;HL=.buff(dptr+reccnt) + ld b,(hl) ;B holds directory record count + pop hl + pop af + ld (hl),a ;restore extent number + ;HL = .user extent#, B = dir rec cnt, C = dir extent# + ;if user ext < dir ext then user := 128 records + ;if user ext = dir ext then user := dir records + ;if user ext > dir ext then user := 0 records + ld a,c + cp (hl) + ld a,b ;ready dir reccnt + jp z,open$rcnt ;if same, user gets dir reccnt + ld a,0 + jp c,open$rcnt ;user is larger + ld a,128 ;directory is larger +open$rcnt: ;A has record count to fill + ld hl,(info) + ld de,reccnt + add hl,de + ld (hl),a + ret + +mergezero: ;HL = .fcb1(i), DE = .fcb2(i), + ;if fcb1(i) = 0 then fcb1(i) := fcb2(i) + ld a,(hl) + inc hl + or (hl) + dec hl + ret nz ;return if = 0000 + ld a,(de) + ld (hl),a + inc de + inc hl ;low byte copied + ld a,(de) + ld (hl),a + dec de + dec hl ;back to input form + ret + +close: ;locate the directory element and re-write it + xor a + ld (lret),a + ld (dcnt),a + ld (dcnt+1),a + call nowrite + ret nz ;skip close if r/o disk + ;check file write flag - 0 indicates written + call getmodnum ;fcb(modnum) in A + and fwfmsk + ret nz ;return if bit remains set + ld c,namlen + call search ;locate file + call end$of$dir + ret z ;return if not found + ;merge the disk map at info with that at buff(dptr) + ld bc,dskmap + call getdptra + add hl,bc + ex de,hl ;DE is .buff(dptr+16) + ld hl,(info) + add hl,bc ;DE=.buff(dptr+16), HL=.fcb(16) + ld c,fcblen-dskmap;length of single byte dm +merge0: ld a,(single) + or a + jp z,merged ;skip to double + ;this is a single byte map + ;if fcb(i) = 0 then fcb(i) = buff(i) + ;if buff(i) = 0 then buff(i) = fcb(i) + ;if fcb(i) <> buff(i) then error + ld a,(hl) + or a + ld a,(de) + jp nz,fcbnzero + ;fcb(i) = 0 + ld (hl),a ;fcb(i) = buff(i) +fcbnzero: + or a + jp nz,buffnzero + ;buff(i) = 0 + ld a,(hl) + ld (de),a ;buff(i)=fcb(i) +buffnzero: + cp (hl) + jp nz,mergerr ;fcb(i) = buff(i)? + jp dmset ;if merge ok + +merged: ;this is a double byte merge operation + call mergezero ;buff = fcb if buff 0000 + ex de,hl + call mergezero + ex de,hl ;fcb = buff if fcb 0000 + ;they should be identical at this point + ld a,(de) + cp (hl) + jp nz,mergerr ;low same? + inc de + inc hl ;to high byte + ld a,(de) + cp (hl) + jp nz,mergerr ;high same? + ;merge operation ok for this pair + dec c ;extra count for double byte +dmset: inc de + inc hl ;to next byte position + dec c + jp nz,merge0 ;for more + ;end of disk map merge, check record count + ;DE = .buff(dptr)+32, HL = .fcb(32) + ld bc,-(fcblen-extnum) + add hl,bc + ex de,hl + add hl,bc + ;DE = .fcb(extnum), HL = .buff(dptr+extnum) + ld a,(de) ;current user extent number + ;if fcb(ext) >= buff(fcb) then + ;buff(ext) := fcb(ext), buff(rec) := fcb(rec) + cp (hl) + jp c,endmerge + ;fcb extent number >= dir extent number + ld (hl),a ;buff(ext) = fcb(ext) + ;update directory record count field + ld bc,reccnt-extnum + add hl,bc + ex de,hl + add hl,bc + ;DE=.buff(reccnt), HL=.fcb(reccnt) + ld a,(hl) + ld (de),a ;buff(reccnt)=fcb(reccnt) +endmerge: + ld a,true + ld (fcb$copied),a ;mark as copied + jp seek$copy ;ok to "wrdir" here - 1.4 compat + ; ret + +mergerr: ;elements did not merge correctly + ld hl,lret + dec (hl) ;=255 non zero flag set + ret + +make: ;create a new file by creating a directory entry + ;then opening the file + call check$write ;may be write protected + ld hl,(info) + push hl ;save fcb address, look for e5 + ld hl,efcb + ld (info),hl ;info = .empty + ld c,1 + call search ;length 1 match on empty entry + call end$of$dir ;zero flag set if no space + pop hl ;recall info address + ld (info),hl ;in case we return here + ret z ;return with error condition 255 if not found + ex de,hl ;DE = info address + ;clear the remainder of the fcb + ld hl,namlen + add hl,de ;HL=.fcb(namlen) + ld c,fcblen-namlen ;number of bytes to fill + xor a ;clear accumulator to 00 for fill +make0: ld (hl),a + inc hl + dec c + jp nz,make0 + ld hl,ubytes + add hl,de ;HL = .fcb(ubytes) + ld (hl),a ;fcb(ubytes) = 0 + call setcdr ;may have extended the directory + ;now copy entry to the directory + call copy$fcb + ;and set the file write flag to "1" + jp setfwf +; ret + +open$reel: ;close the current extent, and open the next one + ;if possible. RMF is true if in read mode + xor a + ld (fcb$copied),a ;set true if actually copied + call close ;close current extent + ;lret remains at enddir if we cannot open the next ext + call end$of$dir + ret z ;return if end + ;increment extent number + ld hl,(info) + ld bc,extnum + add hl,bc ;HL=.fcb(extnum) + ld a,(hl) + inc a + and maxext + ld (hl),a ;fcb(extnum)=++1 + jp z,open$mod ;move to next module if zero + ;may be in the same extent group + ld b,a + ld a,(extmsk) + and b + ;if result is zero, then not in the same group + ld hl,fcb$copied ;true if the fcb was copied to directory + and (hl) ;produces a 00 in accumulator if not written + jp z,open$reel0 ;go to next physical extent + ;result is non zero, so we must be in same logical ext + jp open$reel1 ;to copy fcb information +open$mod: ;extent number overflow, go to next module + ld bc,modnum-extnum + add hl,bc ;HL=.fcb(modnum) + inc (hl) ;fcb(modnum)=++1 + ;module number incremented, check for overflow + ld a,(hl) + and maxmod ;mask high order bits + jp z,open$r$err ;cannot overflow to zero + ;otherwise, ok to continue with new module +open$reel0: + ld c,namlen + call search ;next extent found? + call end$of$dir + jp nz,open$reel1 + ;end of file encountered + ld a,(rmf) + inc a ;0ffh becomes 00 if read + jp z,open$r$err ;sets lret = 1 + ;try to extend the current file + call make + ;cannot be end of directory + call end$of$dir + jp z,open$r$err ;with lret = 1 + jp open$reel2 + +open$reel1: ;not end of file, open + call open$copy +open$reel2: + call getfcb ;set parameters + xor a + jp sta$ret ;lret = 0 +; ret ;with lret = 0 + +open$r$err: ;cannot move to next extent of this file + call setlret1 ;lret = 1 + jp setfwf ;ensure that it will not be closed +; ret + +seqdiskread: ;sequential disk read operation + ld a,1 + ld (seqio),a + ;drop through to diskread + +diskread: ;(may enter from seqdiskread) + ld a,true + ld (rmf),a ;read mode flag = true (open$reel) + ;read the next record from the current fcb + call getfcb ;sets parameters for the read + ld a,(vrecord) + ld hl,rcount + cp (hl) ;vrecord-rcount + ;skip if rcount > vrecord + jp c,recordok + ;not enough records in the extent + ;record count must be 128 to continue + cp 128 ;vrecord = 128? + jp nz,diskeof ;skip if vrecord<>128 + call open$reel ;go to next extent if so + xor a + ld (vrecord),a ;vrecord=00 + ;now check for open ok + ld a,(lret) + or a + jp nz,diskeof ;stop at eof +recordok: ;arrive with fcb addressing a record to read + call index + ;error 2 if reading unwritten data + ;(returns 1 to be compatible with 1.4) + call allocated ;arecord=0000? + jp z,diskeof + ;record has been allocated, read it + call atran ;arecord now a disk address + call seek ;to proper track,sector + call rdbuff ;to dma address + jp setfcb ;replace parameter +; ret + +diskeof: + jp setlret1 ;lret = 1 +; ret + +seqdiskwrite: ;sequential disk write + ld a,1 + ld (seqio),a + ;drop through to diskwrite + +diskwrite: ;(may enter here from seqdiskwrite above) + ld a,false + ld (rmf),a ;read mode flag + ;write record to currently selected file + call check$write ;in case write protected + ld hl,(info) ;HL = .fcb(0) + call check$rofile ;may be a read-only file + call getfcb ;to set local parameters + ld a,(vrecord) + cp lstrec+1 ;vrecord-128 + ;skip if vrecord > lstrec + ;vrecord = 128, cannot open next extent + jp nc,setlret1 ;lret=1 +diskwr0: ;can write the next record, so continue + call index + call allocated + ld c,0 ;marked as normal write operation for wrbuff + jp nz,diskwr1 + ;not allocated + ;the argument to getblock is the starting + ;position for the disk search, and should be + ;the last allocated block for this file, or + ;the value 0 if no space has been allocated + call dm$position + ld (dminx),a ;save for later + ld bc,0000h ;may use block zero + or a + jp z,nopblock ;skip if no previous block + ;previous block exists at A + ld c,a + dec bc ;previous block # in BC + call getdm ;previous block # to HL + ld b,h + ld c,l ;BC=prev block# +nopblock: ;BC = 0000, or previous block # + call get$block ;block # to HL + ;arrive here with block# or zero + ld a,l + or h + jp nz,blockok + ;cannot find a block to allocate + ld a,2 + jp sta$ret ;lret=2 + +blockok: ;allocated block number is in HL + ld (arecord),hl + ex de,hl ;block number to DE + ld hl,(info) + ld bc,dskmap + add hl,bc ;HL=.fcb(dskmap) + ld a,(single) + or a ;set flags for single byte dm + ld a,(dminx) ;recall dm index + jp z,allocwd ;skip if allocating word + ;allocating a byte value + call addh + ld (hl),e ;single byte alloc + jp diskwru ;to continue + +allocwd: ;allocate a word value + ld c,a + ld b,0 ;double(dminx) + add hl,bc + add hl,bc ;HL=.fcb(dminx*2) + ld (hl),e + inc hl + ld (hl),d ;double wd +diskwru: ;disk write to previously unallocated block + ld c,2 ;marked as unallocated write +diskwr1: ;continue the write operation of no allocation error + ;C = 0 if normal write, 2 if to prev unalloc block + ld a,(lret) + or a + ret nz ;stop if non zero returned value + push bc ;save write flag + call atran ;arecord set + ld a,(seqio) + dec a + dec a + jp nz,diskwr11 + pop bc + push bc + ld a,c + dec a + dec a + jp nz,diskwr11 ;old allocation + push hl ;arecord in hl ret from atran + ld hl,(buffa) + ld d,a ;zero buffa & fill +fill0: ld (hl),a + inc hl + inc d + jp p,fill0 + call setdir + ld hl,(arecord1) + ld c,2 +fill1: ld (arecord),hl + push bc + call seek + pop bc + call wrbuff ;write fill record + ld hl,(arecord) ;restore last record + ld c,0 ;change allocate flag + ld a,(blkmsk) + ld b,a + and l + cp b + inc hl + jp nz,fill1 ;cont until cluster is zeroed + pop hl + ld (arecord),hl + call setdata +diskwr11: + call seek ;to proper file position + pop bc + push bc ;restore/save write flag (C=2 if new block) + call wrbuff ;written to disk + pop bc ;C = 2 if a new block was allocated, 0 if not + ;increment record count if rcount<=vrecord + ld a,(vrecord) + ld hl,rcount + cp (hl) ;vrecord-rcount + jp c,diskwr2 + ;rcount <= vrecord + ld (hl),a + inc (hl) ;rcount = vrecord+1 + ld c,2 ;mark as record count incremented +diskwr2: ;A has vrecord, C=2 if new block or new record# + dec c + dec c + jp nz,noupdate + push af ;save vrecord value + call getmodnum ;HL=.fcb(modnum), A=fcb(modnum) + ;reset the file write flag to mark as written fcb + and (not fwfmsk) and 0ffh;bit reset + ld (hl),a ;fcb(modnum) = fcb(modnum) and 7fh + pop af ;restore vrecord +noupdate: ;check for end of extent, if found attempt to open + ;next extent in preparation for next write + cp lstrec ;vrecord=lstrec? + jp nz,diskwr3 ;skip if not + ;may be random access write, if so we are done + ;change next + ld a,(seqio) + cp 1 + jp nz,diskwr3 ;skip next extent open op + ;update current fcb before going to next extent + call setfcb + call open$reel ;rmf=false + ;vrecord remains at lstrec causing eof if + ;no more directory space is available + ld hl,lret + ld a,(hl) + or a + jp nz,nospace + ;space available, set vrecord=255 + dec a + ld (vrecord),a ;goes to 00 next time +nospace: + ld (hl),0 ;lret = 00 for returned value +diskwr3: + jp setfcb ;replace parameters +; ret + +rseek: ;random access seek operation, C=0ffh if read mode + ;fcb is assumed to address an active file control block + ;(modnum has been set to 1100$0000b if previous bad seek) + xor a + ld (seqio),a ;marked as random access operation +rseek1: push bc ;save r/w flag + ld hl,(info) + ex de,hl ;DE will hold base of fcb + ld hl,ranrec + add hl,de ;HL=.fcb(ranrec) + ld a,(hl) + and 7fh + push af ;record number + ld a,(hl) + rla ;cy=lsb of extent# + inc hl + ld a,(hl) + rla + and 11111b ;A=ext# + ld c,a ;C holds extent number, record stacked + ld a,(hl) + rra + rra + rra + rra + and 1111b ;mod# + ld b,a ;B holds module#, C holds ext# + pop af ;recall sought record # + ;check to insure that high byte of ran rec = 00 + inc hl + ld l,(hl) ;l=high byte (must be 00) + inc l + dec l + ld l,6 ;zero flag, l=6 + ;produce error 6, seek past physical eod + jp nz,seekerr + ;otherwise, high byte = 0, A = sought record + ld hl,nxtrec + add hl,de ;HL = .fcb(nxtrec) + ld (hl),a ;sought rec# stored away + ;arrive here with B=mod#, C=ext#, DE=.fcb, rec stored + ;the r/w flag is still stacked. compare fcb values + ld hl,extnum + add hl,de + ld a,c ;A=seek ext# + sub (hl) + jp nz,ranclose ;tests for = extents + ;extents match, check mod# + ld hl,modnum + add hl,de + ld a,b ;B=seek mod# + ;could be overflow at eof, producing module# + ;of 90H or 10H, so compare all but fwf + sub (hl) + and 7fh + jp z,seekok ;same? +ranclose: + push bc + push de ;save seek mod#,ext#, .fcb + call close ;current extent closed + pop de + pop bc ;recall parameters and fill + ld l,3 ;cannot close error #3 + ld a,(lret) + inc a + jp z,badseek + ld hl,extnum + add hl,de + ld (hl),c ;fcb(extnum)=ext# + ld hl,modnum + add hl,de + ld (hl),b ;fcb(modnum)=mod# + call open ;is the file present? + ld a,(lret) + inc a + jp nz,seekok ;open successful? + ;cannot open the file, read mode? + pop bc ;r/w flag to c (=0ffh if read) + push bc ;everyone expects this item stacked + ld l,4 ;seek to unwritten extent #4 + inc c ;becomes 00 if read operation + jp z,badseek ;skip to error if read operation + ;write operation, make new extent + call make + ld l,5 ;cannot create new extent #5 + ld a,(lret) + inc a + jp z,badseek ;no dir space + ;file make operation successful +seekok: + pop bc ;discard r/w flag + xor a + jp sta$ret ;with zero set +badseek: ;fcb no longer contains a valid fcb, mark + ;with 1100$000b in modnum field so that it + ;appears as overflow with file write flag set + push hl ;save error flag + call getmodnum ;HL = .modnum + ld (hl),11000000b + pop hl ;and drop through +seekerr: + pop bc ;discard r/w flag + ld a,l + ld (lret),a ;lret=#, nonzero + ;setfwf returns non-zero accumulator for err + jp setfwf ;flag set, so subsequent close ok +; ret + +randiskread: ;random disk read operation + ld c,true ;marked as read operation + call rseek + call z,diskread ;if seek successful + ret + +randiskwrite: ;random disk write operation + ld c,false ;marked as write operation + call rseek + call z,diskwrite ;if seek successful + ret + +compute$rr: ;compute random record position for getfilesize/setrandom + ex de,hl + add hl,de + ;DE=.buf(dptr) or .fcb(0), HL = .f(nxtrec/reccnt) + ld c,(hl) + ld b,0 ;BC = 0000 0000 ?rrr rrrr + ld hl,extnum + add hl,de + ld a,(hl) + rrca + and 80h ;A=e000 0000 + add a,c + ld c,a + ld a,0 + adc a,b + ld b,a + ;BC = 0000 000? errrr rrrr + ld a,(hl) + rrca + and 0fh + add a,b + ld b,a + ;BC = 000? eeee errrr rrrr + ld hl,modnum + add hl,de + ld a,(hl) ;A=XXX? mmmm + add a,a + add a,a + add a,a + add a,a ;cy=? A=mmmm 0000 + push af + add a,b + ld b,a + ;cy=?, BC = mmmm eeee errr rrrr + push af ;possible second carry + pop hl ;cy = lsb of L + ld a,l ;cy = lsb of A + pop hl ;cy = lsb of L + or l ;cy/cy = lsb of A + and 1 ;A = 0000 000? possible carry-out + ret + +getfilesize: ;compute logical file size for current fcb + ld c,extnum + call search + ;zero the receiving ranrec field + ld hl,(info) + ld de,ranrec + add hl,de + push hl ;save position + ld (hl),d + inc hl + ld (hl),d + inc hl + ld (hl),d ;=00 00 00 +getsize: + call end$of$dir + jp z,setsize + ;current fcb addressed by dptr + call getdptra + ld de,reccnt ;ready for compute size + call compute$rr + ;A=0000 000? BC = mmmm eeee errr rrrr + ;compare with memory, larger? + pop hl + push hl ;recall, replace .fcb(ranrec) + ld e,a ;save cy + ld a,c + sub (hl) + inc hl ;ls byte + ld a,b + sbc a,(hl) + inc hl ;middle byte + ld a,e + sbc a,(hl) ;carry if .fcb(ranrec) > directory + jp c,getnextsize ;for another try + ;fcb is less or equal, fill from directory + ld (hl),e + dec hl + ld (hl),b + dec hl + ld (hl),c +getnextsize: + call searchn + jp getsize + +setsize: + pop hl ;discard .fcb(ranrec) + ret + +setrandom: ;set random record from the current file control block + ld hl,(info) + ld de,nxtrec ;ready params for computesize + call compute$rr ;DE=info, A=cy, BC=mmmm eeee errr rrrr + ld hl,ranrec + add hl,de ;HL = .fcb(ranrec) + ld (hl),c + inc hl + ld (hl),b + inc hl + ld (hl),a ;to ranrec + ret + +select: ;select disk info for subsequent input or output ops + ld hl,(dlog) + ld a,(curdsk) + ld c,a + call hlrotr + push hl + ex de,hl ;save it for test below, send to seldsk + call selectdisk + pop hl ;recall dlog vector + call z,sel$error ;returns true if select ok + ;is the disk logged in? + ld a,l + rra + ret c ;return if bit is set + ;disk not logged in, set bit and initialize + ld hl,(dlog) + ld c,l + ld b,h ;call ready + call set$cdisk + ld (dlog),hl ;dlog=set$cdisk(dlog) + jp initialize +; ret + +curselect: + ld a,(linfo) + ld hl,curdsk + cp (hl) + ret z ;skip if linfo=curdsk + ld (hl),a ;curdsk=info + jp select +; ret + +reselect: ;check current fcb to see if reselection necessary + ld a,true + ld (resel),a ;mark possible reselect + ld hl,(info) + ld a,(hl) ;drive select code + and 11111b ;non zero is auto drive select + dec a ;drive code normalized to 0..30, or 255 + ld (linfo),a ;save drive code + cp 30 + jp nc,noselect + ;auto select function, save curdsk + ld a,(curdsk) + ld (olddsk),a ;olddsk=curdsk + ld a,(hl) + ld (fcbdsk),a ;save drive code + and 11100000b + ld (hl),a ;preserve hi bits + call curselect +noselect: ;set user code + ld a,(usrcode) ;0...31 + ld hl,(info) + or (hl) + ld (hl),a + ret + +; individual function handlers +func12: ;return version number + ld a,dvers + jp sta$ret ;lret = dvers (high = 00) +; ret +; jp goback + +func13: ;reset disk system - initialize to disk 0 + ld hl,0 + ld (rodsk),hl + ld (dlog),hl + xor a + ld (curdsk),a ;note that usrcode remains unchanged + ld hl,tbuff + ld (dmaad),hl ;dmaad = tbuff + call setdata ;to data dma address + jp select +; ret +; jp goback + +func14 equ curselect ;select disk info +; ret +; jp goback + +func15: ;open file + call clrmodnum ;clear the module number + call reselect + jp open +; ret +; jp goback + +func16: ;close file + call reselect + jp close +; ret +; jp goback + +func17: ;search for first occurrence of a file + ld c,0 ;length assuming '?' true + ex de,hl ;was lhld info + ld a,(hl) + cp '?' ;no reselect if ? + jp z,qselect ;skip reselect if so + ;normal search + call getexta + ld a,(hl) + cp '?' ; + call nz,clrmodnum ;module number zeroed + call reselect + ld c,namlen +qselect: + call search + jp dir$to$user ;copy directory entry to user +; ret +; jp goback + +func18: ;search for next occurrence of a file name + ld hl,(searcha) + ld (info),hl + call reselect + call searchn + jp dir$to$user ;copy directory entry to user +; ret +; jp goback + +func19: ;delete a file + call reselect + call delete + jp copy$dirloc +; ret +; jp goback + +func20: ;read a file + call reselect + jp seqdiskread +; jp goback + +func21: ;write a file + call reselect + jp seqdiskwrite +; jp goback + +func22: ;make a file + call clrmodnum + call reselect + jp make +; ret +; jp goback + +func23: ;rename a file + call reselect + call rename + jp copy$dirloc +; ret +; jp goback + +func24: ;return the login vector + ld hl,(dlog) + jp sthl$ret +; ret +; jp goback + +func25: ;return selected disk number + ld a,(curdsk) + jp sta$ret +; ret +; jp goback + +func26: ;set the subsequent dma address to info + ex de,hl ;was lhld info + ld (dmaad),hl ;dmaad = info + jp setdata ;to data dma address +; ret +; jp goback + +func27: ;return the login vector address + ld hl,(alloca) + jp sthl$ret +; ret +; jp goback + +func28 equ set$ro + ;write protect current disk +; ret +; jp goback + +func29: ;return r/o bit vector + ld hl,(rodsk) + jp sthl$ret +; ret +; jp goback + +func30: ;set file indicators + call reselect + call indicators + jp copy$dirloc ;lret=dirloc +; ret +; jp goback + +func31: ;return address of disk parameter block + ld hl,(dpbaddr) +sthl$ret: + ld (aret),hl + ret +; jp goback + +func32: ;set user code + ld a,(linfo) + cp 0ffh + jp nz,setusrcode + ;interrogate user code instead + ld a,(usrcode) + jp sta$ret ;lret=usrcode +; ret +; jp goback + +setusrcode: + and 1fh + ld (usrcode),a + ret +; jp goback + +func33: ;random disk read operation + call reselect + jp randiskread ;to perform the disk read +; ret +; jp goback + +func34: ;random disk write operation + call reselect + jp randiskwrite ;to perform the disk write +; ret +; jp goback + +func35: ;return file size (0-65536) + call reselect + jp getfilesize +; ret +; jp goback + +func36 equ setrandom ;set random record +; ret +; jp goback + +func37: ld hl,(info) + ld a,l + cpl + ld e,a + ld a,h + cpl + ld hl,(dlog) + and h + ld d,a + ld a,l + and e + ld e,a + ld hl,(rodsk) + ex de,hl + ld (dlog),hl + ld a,l + and e + ld l,a + ld a,h + and d + ld h,a + ld (rodsk),hl + ret + +goback: ;arrive here at end of processing to return to user + ld a,(resel) + or a + jp z,retmon + ;reselection may have taken place + ld hl,(info) + ld (hl),0 ;fcb(0)=0 + ld a,(fcbdsk) + or a + jp z,retmon + ;restore disk number + ld (hl),a ;fcb(0)=fcbdsk + ld a,(olddsk) + ld (linfo),a + call curselect + +; return from the disk monitor +retmon: ld hl,(entsp) + ld sp,hl ;user stack restored + ld hl,(aret) + ld a,l + ld b,h ;BA = HL = aret + ret + +func38 equ func$ret +func39 equ func$ret +func40: ;random disk write with zero fill of unallocated block + call reselect + ld a,2 + ld (seqio),a + ld c,false + call rseek1 + call z,diskwrite ;if seek successful + ret + +; data areas + +; initialized data +efcb: db empty ;0e5=available dir entry +rodsk: dw 0 ;read only disk vector +dlog: dw 0 ;logged-in disks +dmaad: dw tbuff ;initial dma address + +; curtrka - alloca are set upon disk select +; (data must be adjacent, do not insert variables) +; (address of translate vector, not used) +cdrmaxa: + ds word ;pointer to cur dir max value +curtrka: + ds word ;current track address +curreca: + ds word ;current record address +buffa: ds word ;pointer to directory dma address +dpbaddr: + ds word ;current disk parameter block address +checka: ds word ;current checksum vector address +alloca: ds word ;current allocation vector address +addlist equ $-buffa ;address list size + +; sectpt - offset obtained from disk parm block at dpbaddr +; (data must be adjacent, do not insert variables) +sectpt: ds word ;sectors per track +blkshf: ds byte ;block shift factor +blkmsk: ds byte ;block mask +extmsk: ds byte ;extent mask +maxall: ds word ;maximum allocation number +dirmax: ds word ;largest directory number +dirblk: ds word ;reserved allocation bits for directory +chksiz: ds word ;size of checksum vector +offset: ds word ;offset tracks at beginning +dpblist equ $-sectpt ;size of area + +; local variables +tranv: ds word ;address of translate vector +fcb$copied: + ds byte ;set true if copy$fcb called +rmf: ds byte ;read mode flag for open$reel +dirloc: ds byte ;directory flag in rename, etc. +seqio: ds byte ;1 if sequential i/o +linfo: ds byte ;low(info) +dminx: ds byte ;local for diskwrite +searchl: + ds byte ;search length +searcha: + ds word ;search address +tinfo: ds word ;temp for info in "make" +single: ds byte ;set true if single byte allocation map +resel: ds byte ;reselection flag +olddsk: ds byte ;disk on entry to bdos +fcbdsk: ds byte ;disk named in fcb +rcount: ds byte ;record count in current fcb +extval: ds byte ;extent number and extmsk +vrecord: + ds word ;current virtual record +arecord: + ds word ;current actual record +arecord1: + ds word ;current actual block# * blkmsk + +; local variables for directory access +dptr: ds byte ;directory pointer 0,1,2,3 +dcnt: ds word ;directory counter 0,1,...,dirmax +drec: ds word ;directory record 0,1,...,dirmax/4 + +;bios equ ($ and 0ff00h)+100h;next module + +;;dwg;; end + +;; dwg ; end dri source code here + +_bdos_end:: + .area _CODE + .area _CABS diff --git a/doug/src/dribdos.sym b/doug/src/dribdos.sym new file mode 100755 index 00000000..7e06663e --- /dev/null +++ b/doug/src/dribdos.sym @@ -0,0 +1,139 @@ + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 1. +'Bdos Interface, Bdos, Version 2.2 Feb, 1980' +Symbol Table + + .__.ABS.= 0000 G | 6 _bdos 0000 GR | 6 _bdos_en 0AC6 GR + 6 _bdos_st 0000 GR | 6 addh 03D1 R | addlist **** X + 6 alloca 0AC6 R | 6 allocate 030F R | 6 allocwd 0801 R + 6 arecord 0AC6 R | 6 arecord1 0AC6 R | 6 aret 01FC R + 6 atran 0315 R | 6 atran0 031B R | 6 backsp 0199 R + 6 backup 00D6 R | 6 backx 0158 R | 6 badseek 08E7 R + 6 bdose 0011 R | 6 blkmsk 0AC6 R | 6 blkshf 0AC6 R + 6 blockok 07E8 R | 6 buffa 0AC6 R | 6 buffnzer 06BE R + 6 cdrmaxa 0AC6 R | 6 check$ro 03BA R | 6 check$ro 03BD R + 6 check$wr 03C4 R | 6 checka 0AC6 R | 6 checksum 0402 R + 6 chksiz 0AC6 R | 6 close 0688 R | 6 clrmodnu 03DC R + 6 column 01FC R | 6 compcdr 03E5 R | 6 compcol 01FC R + 6 compext 0538 R | 6 compout 00AB R | 6 compute$ 0377 R + 6 compute$ 0902 R | 6 computec 037B R | 6 conb0 008D R + 6 conb1 0090 R | 6 conbrk 0074 R | 6 conech 0061 R + 6 conin 005B R | coninf **** X | 6 conout 0091 R + conoutf **** X | constf **** X | 6 copy$dir 0609 R + 6 copy$dir 0532 R | 6 copy$fcb 0609 R | cr **** X + 6 crlf 00F0 R | 6 crlfp 00DF R | 6 crlfp0 00E5 R + ctl **** X | ctlc **** X | ctle **** X + ctlh **** X | 6 ctlout 00BB R | ctlp **** X + ctlr **** X | ctls **** X | ctlu **** X + ctlx **** X | 6 curdsk 01FC R | 6 curreca 0AC6 R + 6 curselec 0984 R | 6 curtrka 0AC6 R | 6 dcnt 0AC6 R + 6 delete 05B1 R | 6 delete0 05B7 R | 6 diocomp 025A R + 6 dir$to$u 0445 R | 6 dirblk 0AC6 R | 6 dirinp 01D7 R + 6 dirloc 0AC6 R | 6 dirmax 0AC6 R | 6 diskeof 07A8 R + 6 diskread 0775 R | 6 diskwr0 07C3 R | 6 diskwr1 0807 R + 6 diskwr11 0850 R | 6 diskwr2 0862 R | 6 diskwr3 0885 R + 6 diskwrit 07AE R | 6 diskwru 0807 R | 6 dlog 0AC6 R + 6 dm$posit 02D5 R | 6 dmaad 0AC6 R | 6 dminx 0AC6 R + 6 dmpos0 02D9 R | 6 dmpos1 02E5 R | 6 dmpos2 02EE R + 6 dmset 06DA R | 6 dpbaddr 0AC6 R | dpblist **** X + 6 dptr 0AC6 R | 6 drec 0AC6 R | 6 dskerr 004A R + dskmap **** X | 6 dskmsg 004A R | dskmsk **** X + dskshf **** X | dvers **** X | 6 echoc 006F R + 6 efcb 0AC6 R | empty **** X | 6 end$of$d 044F R + enddir **** X | 6 endmerge 06EE R | 6 endsearc 059F R + 6 entsp 01FC R | 6 errflg 004A R | 6 extmsk 0AC6 R + extnum **** X | 6 extval 0AC6 R | false **** X + 6 fcb$copi 0AC6 R | 6 fcbdsk 0AC6 R | fcblen **** X + 6 fcbnzero 06B8 R | fcbshf **** X | 6 fill0 0825 R + 6 fill1 0831 R | 6 func$ret 01F8 R | 6 func1 01BF R + 6 func11 01F2 R | 6 func12 09B2 R | 6 func13 09B5 R + 6 func15 09C8 R | 6 func16 09D1 R | 6 func17 09D7 R + 6 func18 09EC R | 6 func19 09FB R | 6 func20 0A04 R + 6 func21 0A0A R | 6 func22 0A10 R | 6 func23 0A19 R + 6 func24 0A22 R | 6 func25 0A28 R | 6 func26 0A2E R + 6 func27 0A35 R | 6 func29 0A3B R | 6 func3 01C5 R + 6 func30 0A41 R | 6 func31 0A4A R | 6 func32 0A51 R + 6 func33 0A61 R | 6 func34 0A67 R | 6 func35 0A6D R + 6 func37 0A73 R | 6 func40 0AB9 R | 6 func6 01CB R + 6 func7 01E4 R | 6 func8 01EA R | 6 func9 01EC R + 6 functab 0037 R | fwfmsk **** X | 6 get$bloc 05CD R + 6 getalloc 0485 R | 6 getdm 02F0 R | 6 getdmd 02FE R + 6 getdptra 03CB R | 6 getexta 0331 R | 6 getfcb 033D R + 6 getfcba 0336 R | 6 getfiles 091F R | 6 getmodnu 03D6 R + 6 getnexts 094B R | 6 getsize 092C R | 6 goback 0A94 R + 6 goerr 01FC R | 6 hlrotl 0382 R | 6 hlrotl0 0383 R + 6 hlrotr 036A R | 6 hlrotr0 036B R | 6 home 0240 R + homef **** X | 6 index 0304 R | 6 indic0 063B R + 6 indicato 0638 R | 6 info 01FC R | 6 initial$ 0428 R + 6 initial0 04F0 R | 6 initial2 050B R | 6 initiali 04E4 R + ioloc **** X | 6 kbchar 01FC R | 6 lefttst 05CF R + lf **** X | 6 linelen 0173 R | 6 linfo 0AC6 R + 6 listcp 01FC R | listf **** X | lret **** X + 6 lstack 01FC R | lstrec **** X | 6 make 06F6 R + 6 make0 070E R | 6 maxall 0AC6 R | maxext **** X + maxmod **** X | 6 merge0 06AA R | 6 merged 06C5 R + 6 mergerr 06F4 R | 6 mergezer 067A R | modnum **** X + 6 move 0201 R | 6 move0 0202 R | namlen **** X + 6 newcheck 0402 R | nfuncs **** X | 6 nopblock 07DD R + 6 noselect 09A9 R | 6 nospace 0885 R | not **** X + 6 notbacks 00B9 R | 6 notc 01B6 R | 6 note 014A R + 6 noth 012D R | 6 notp 0154 R | 6 notr 01A3 R + 6 notrub 013B R | 6 notu 0170 R | 6 notx 0166 R + 6 noupdate 086D R | 6 nowrite 0399 R | nxtrec **** X + 6 offset 0AC6 R | 6 olddsk 0AC6 R | 6 open 0648 R + 6 open$cop 064F R | 6 open$mod 0740 R | 6 open$r$e 076C R + 6 open$rcn 0674 R | 6 open$ree 071F R | 6 open$ree 0746 R + 6 open$ree 0762 R | 6 open$ree 0765 R | 6 pctlh 00DC R + 6 pdollar 0529 R | 6 pererr 0009 R | 6 permsg 004A R + 6 persub 0037 R | 6 print 00F6 R | 6 qselect 09E6 R + 6 ranclose 08B6 R | 6 randiskr 08F4 R | 6 randiskw 08FB R + ranrec **** X | 6 rcount 0AC6 R | 6 rd$dir 0436 R + 6 rdbuff 0251 R | 6 rdech1 01A6 R | 6 rdecho 01A3 R + 6 read 0102 R | 6 read$dir 0459 R | 6 read$dir 046D R + 6 read$dir 0470 R | 6 readen 01BA R | readerf **** X + readf **** X | 6 readn0 0110 R | 6 readnx 010E R + reboot **** X | reccnt **** X | 6 recordok 0793 R + recsiz **** X | 6 rename 061C R | 6 rename0 0628 R + 6 rep0 017B R | 6 rep1 018D R | 6 resel 0AC6 R + 6 reselect 098D R | 6 retblock 05FB R | 6 retblock 0603 R + 6 retmon 0AAF R | 6 retselec 023E R | 6 righttst 05E0 R + 6 rmf 0AC6 R | 6 roderr 000D R | 6 rodmsg 004A R + 6 rodsk 0AC6 R | 6 rodsub 0041 R | 6 roferr 000F R + rofile **** X | 6 rofmsg 004A R | 6 rofsub 0044 R + 6 rotl 04A0 R | 6 rotr 04AC R | 6 rseek 0888 R + 6 rseek1 088C R | rubout **** X | 6 scandm 04B3 R + 6 scandm0 04B8 R | 6 scandm1 04C9 R | 6 scandm2 04CF R + 6 scanm3 04DE R | 6 search 0547 R | 6 search$f 05AB R + 6 searcha 0AC6 R | 6 searchex 058F R | 6 searchl 0AC6 R + 6 searchlo 0577 R | 6 searchn 0557 R | 6 searchne 0570 R + 6 searchok 0598 R | 6 sectpt 0AC6 R | sectran **** X + 6 seek 026B R | 6 seek$cop 0616 R | 6 seek$dir 025F R + 6 seek0 027B R | 6 seek1 0291 R | 6 seek2 02A6 R + 6 seekerr 08EC R | 6 seekok 08E2 R | 6 sel$erro 01FC R + seldskf **** X | 6 select 0960 R | 6 selectdi 020B R + 6 selerr 000B R | 6 selmsg 004A R | 6 selsub 003E R + 6 seqdiskr 0772 R | 6 seqdiskw 07AB R | 6 seqio 0AC6 R + 6 set$allo 04A6 R | 6 set$cdis 0389 R | 6 set$end$ 0455 R + 6 set$ro 03A5 R | 6 setcdr 03F2 R | 6 setdata 043C R + 6 setdir 043F R | 6 setdma 043F R | setdmaf **** X + 6 setfcb 0354 R | 6 setfcb1 035E R | 6 setfwf 03E0 R + 6 setlret1 01F9 R | 6 setrando 0953 R | setsecf **** X + 6 setsize 0951 R | settrkf **** X | 6 setusrco 0A5D R + 6 single 0AC6 R | 6 sta$ret 01F5 R | 6 sthl$ret 0A4D R + 6 strtcol 01FC R | 6 subdh 03FB R | tab **** X + 6 tab0 00CC R | 6 tabout 00C8 R | tbuff **** X + 6 tinfo 0AC6 R | 6 tranv 0AC6 R | true **** X + ubytes **** X | 6 usrcode 01FC R | 6 vrecord 0AC6 R + 6 wait$err 0044 R | 6 wrbuff 0257 R | 6 wrdir 042A R + writef **** X + ASxxxx Assembler V02.00 + NoICE + SDCC mods + Flat24 (Zilog Z80 / Hitachi HD64180), page 2. +'Bdos Interface, Bdos, Version 2.2 Feb, 1980' +Area Table + + 0 _CODE size 0 flags 0 + 1 _DATA size 0 flags 0 + 2 _OVERLAY size 0 flags 0 + 3 _HOME size 0 flags 0 + 4 _GSINIT size 0 flags 0 + 5 _GSFINAL size 0 flags 0 + 6 _BDOS size AC6 flags 0 + 7 _CABS size 0 flags 0 diff --git a/doug/src/dricbiosx.mac b/doug/src/dricbiosx.mac new file mode 100755 index 00000000..d02d7f18 --- /dev/null +++ b/doug/src/dricbiosx.mac @@ -0,0 +1,1400 @@ +; ALTAIR 8800 BIOS with 8800 disk drives - 256 files each +; +; +; 02-May-2009, P. Schorn, removed DJNZ, bug found by Michael Rychlik +; 19-Apr-2009, P. Schorn, added automatic disk parameter block creation +; for disks with sector length 128 +; 15-Jan-2007, P. Schorn, added PSH and PHM in DPB for BIOS3 compatibility +; 05-Nov-2006, P. Schorn, configurable initial command after booting +; 14-Oct-2006, P. Schorn, made patching and Z80 check configurable +; 09-Oct-2002, P. Schorn, added support for simulated hard disk +; 01-Oct-2002, P. Schorn, changed computation for memory configuration (proposed +; by Scott LaBombard) +; 28-Apr-2002, P. Schorn, updated for new boot ROM +; 15-Apr-2002, P. Schorn, code clean up and simplification +; sanity check of (cdisk) to avoid loop on "Select" error +; 03-Apr-2002, P. Schorn, added CCP patches to allow SUBMIT +; on non-A boot drive as well +; moved lower case patch into BIOS +; 01-Apr-2002, P. Schorn, fixed bug in 'gotoit' +; 31-Mar-2002, P. Schorn, added BDOS patch to reboot in case of +; Bad Sector message and ^C typed +; 29-Mar-2002, P. Schorn, added symbol at end +; warm boot now uses the correct drive +; 23-Mar-2002, P. Schorn, added some CEO patches to BDOS + +false equ 0 +true equ not false + +initCmd equ false ; if true then cold boot invokes a command +sleepol equ true ; if true then sleep a bit while status polling + ; Note: requires SIMH + + .8080 +jpopcod equ (jmp) ; jp op-code +jpzopcd equ (jz) ; jp z op-code + + .Z80 + aseg + org 100h + maclib MEMCFG.LIB ; define configuration parameters + + .phase biosph +ccp equ ccpph ; ccp start address +bdos equ bdosph + 6 ; bdos start address +bios equ biosph ; bios start address + +; default values in case configuration parameters are left undefined + ifndef nhdisks +nhdisks equ 0 + endif + + ifndef needZ80 +needZ80 equ false + endif + + ifndef patchOS +patchOS equ false + endif + +wbotloc equ 0000h ; warm boot location +bdosloc equ 0005h ; BDOS entry location +bioserr equ 1 ; 1 indicates BIOS error +cdisk equ 0004h ; current disk location +ndisks equ 8 ; total number of Altair disks +tracks equ 254 ; number of tracks for regular drives +track1 equ tracks+1 ; indicator for unknown track position +asecsiz equ 137 ; sector size Altair +csecsiz equ 0080h ; sector size CP/M +rom equ 0ff00h ; address of Altair bootstrap loader in ROM +bootdr1 equ rom+0037h ; taken from dskboot (offset unitnooffset1) +bootdr2 equ rom+00b4h ; taken from dskboot (offset unitnooffset2) + +; Address Mode Function +; ------- ---- -------- +; selout Out Selects and enables controller and drive +; statin In Indicates status of drive and controller +; dskcon Out Controls disk function +; secpos In Indicates current sector position of disk +; dskwrit Out Write data +; dskread In Read data + +selout equ 8 ; port to select and enable controller and drive (OUT) +; +---+---+---+---+---+---+---+---+ +; | C | X | X | X | Device | +; +---+---+---+---+---+---+---+---+ +; +; C = If this bit is 1, the disk controller selected by 'device' is +; cleared. If the bit is zero, 'device' is selected as the +; device being controlled by subsequent I/O operations. +; X = not used +; Device = value zero thru 15, selects drive to be controlled. + +statin equ 8 ; port indicating status of drive and controller (IN) +; +---+---+---+---+---+---+---+---+ +; | R | Z | I | X | X | H | M | W | +; +---+---+---+---+---+---+---+---+ +; +; W - When 0, write circuit ready to write another byte. +; M - When 0, head movement is allowed +; H - When 0, indicates head is loaded for read/write +; X - not used (will be 0) +; I - When 0, indicates interrupts enabled (not used this simulator) +; Z - When 0, indicates head is on track 0 +; R - When 0, indicates that read circuit has new byte to read + +dskcon equ 9 ; port to control disc function (OUT) +; +---+---+---+---+---+---+---+---+ +; | W | C | D | E | U | H | O | I | +; +---+---+---+---+---+---+---+---+ +; +; I - When 1, steps head IN one track +; O - When 1, steps head OUT one track +; H - When 1, loads head to drive surface +; U - When 1, unloads head +; E - Enables interrupts (ignored by this simulator) +; D - Disables interrupts (ignored by this simulator) +; C - When 1 lowers head current (ignored by this simulator) +; W - When 1, starts Write Enable sequence: +; W bit on device 'statin' (see above) will go 1 and data will be read from +; port 'dskread' until 137 bytes have been read by the controller from +; that port. The W bit will go off then, and the sector data will be written +; to disk. Before you do this, you must have stepped the track to the desired +; number, and waited until the right sector number is presented on +; device 'secpos', then set this bit. + +secpos equ 9 ; port to indicate current sector position of disk (IN) +; As the sectors pass by the read head, they are counted and the +; number of the current one is available in this register. +; +; +---+---+---+---+---+---+---+---+ +; | X | X | Sector Number | T | +; +---+---+---+---+---+---+---+---+ +; +; X = Not used +; Sector number = binary of the sector number currently under the head, 0-31. +; T = Sector True, is a 1 when the sector is positioned to read or write. + +dskwrit equ 10 ; port to write data (OUT) +dskread equ 10 ; port to read data (IN) + +; All I/O is via programmed I/O. Each device has a status port +; and a data port. A write to the status port can select +; some options for the device although the simulator only +; recognizes the reset command (0x03). +; A read of the status port gets the port status: +; +; +---+---+---+---+---+---+---+---+ +; | X | X | X | X | X | X | O | I | +; +---+---+---+---+---+---+---+---+ +; +; I - A 1 in this bit position means a character has been received +; on the data port and is ready to be read. +; O - A 1 in this bit means the port is ready to receive a character +; on the data port and transmit it out over the serial line. +; +; A read to the data port gets the buffered character, a write +; to the data port writes the character to the device. +constat equ 16 ; sio port 1 status port +condata equ 17 ; sio port 1 data port +punstat equ 18 ; sio port 2 status port +pundata equ 19 ; sio port 2 data port + +; masks for disk controller (statin) +mhm equ 02h ; head movement mask +mtzero equ 40h ; head on track zero mask +mall equ 0ffh ; everything ok mask + +; commands for disk controller (dskcon) +cstepin equ 01h ; step in command +cstepot equ 02h ; step out command +cload equ 04h ; load head to drive surface command +cuload equ 08h ; unload head from drive surface command +cwrseq equ 80h ; 'start write enable sequence' command + +; masks for SIO controller (constat, punstat) +mout equ 02h ; output allowed mask + +; commands for SIO controller (constat, punstat) +creset equ 3 ; reset command + + if nhdisks gt 0 +; constants for hard disk port +hdskReset equ 1 ; command to reset controller +hdskRead equ 2 ; read command +hdskWrite equ 3 ; write command +hdskParam equ 4 ; param command +hdskport equ 0fdh ; control port for simulated hard disk +firstSector equ 17 ; first sector to load +firstTrack equ 0 ; from this track +firstDiskAddr equ 256*firstTrack+firstSector +sectors equ (ccplen+bdoslen)/csecsiz + endif + +dirent equ 255 ; number of directory entries +restrk equ 6 ; reserved tracks +dsm06 equ 1efh ; maximum data block number for disks 0 to 6 +dsm07 equ 254 ; maximum data block number for disk 7 +spt equ 32 ; sectors per track +sptmask equ spt-1 ; mask corresponding to 'spt' +cks equ (dirent+1)/4 +cr equ 13 ; Carriage Return +lf equ 10 ; Line Feed + + jp boot ; cold start +wboote: jp wboot ; warm start (reboot) + jp const ; console status + jp conin ; console input + jp conout ; console output + jp list ; list character out + jp punch ; punch character out + jp reader ; read character in + jp home ; move disk head to home + jp seldsk ; select disk drive + jp settrk ; set track number + jp setsec ; set sector number + jp setdma ; set disk memory read/write address + jp read ; read sector + jp write ; write sector + jp listst ; list dev status test + jp sectrn ; sector translate + +; The BOOT entry point gets control from the cold start loader and is +; responsible for basic system initialization, including sending a sign-on +; message, which can be omitted in the first version. If the IOBYTE function +; is implemented, it must be set at this point. The various system parameters +; that are set by the WBOOT entry point must be initialized, and control is +; transferred to the CCP at 3400 + b for further processing. Note that +; register C must be set to zero to select drive A. +boot: ld sp,chk02 + ld a,(bootdr1) ; load current disk with boot drive + ld (cdisk),a + ld de,msg1 ; print welcome message + call msg + + if needZ80 +entcpm: xor a + dec a + jp po,ent2 ; all eight bits set means parity even for 8080, po is Z80 + ld de,msg2 ; got an 8080 which is no good + call msg ; warn user + halt ; wait for processor to be changed + jp entcpm ; and try again +ent2 equ $ + else +entcpm equ $ + endif + + ld a,jpopcod ; jp instruction code + ld (wbotloc),a ; store at entry to warm boot + ld hl,wboote ; get jump location + ld (wbotloc+1),hl ; and store it after jp instruction + ld (bdosloc),a ; jp instruction code for entry to BDOS + ld hl,bdos ; get jump location + ld (bdosloc+1),hl ; and store it after jp instruction + + if patchOS +; begin patch CCP and BDOS + ld b,low ((patche-patchs) shr 2) ; number of entries in patch table + ld hl,patchs ; start of patch table +patch1: ld e,(hl) ; is lower byte of address for jp instruction + inc hl ; point to upper byte + ld d,(hl) ; points to address for jp instruction + inc hl ; points to lower byte of source jp address + ld a,jpopcod ; jp op code + ld (de),a ; store jp op-code to appropriate location + inc de ; points to lower byte of destination jp address + ld a,(hl) ; get lower byte of address + ld (de),a ; store it + inc hl ; point to upper byte source jp address + inc de ; point to upper byte destination jp address + ld a,(hl) ; get upper byte of address + ld (de),a ; store it + inc hl ; point to next table pair + dec b ; entry done + jp nz,patch1 ; if more to do + +; patch bdos to perform a ROM reboot in case of Bad Sector error +; is detected and user has typed ^C. This is to make sure that one +; can recover from errors due to non-existing drives. + ld hl,rom + ld (bdos+009ch),hl ; at bdos+9bh we now have jp z,rom instead of jp z,0 + +; patch ccp to look on ipl drive if file not found + ld a,jpzopcd ; replace jp opcode with jp z opcode + ld (ccp+06dbh),a ; plug into ccp at intercept point + + ld hl,lctabs + ld c,low ((lctabe-lctabs) / 3) ; number of table entries +;precondition: points to table with structure (byte length, word address)* +;at 'address' starts a character string of length 'length' which is to be translated to +;lower case +tolc: ld b,(hl) ; points to length byte + inc hl ; points to lower byte of address + ld e,(hl) ; E := lower byte of address + inc hl ; points to upper byte of address + ld d,(hl) ; D := upper byte of address + inc hl ; points to next length byte + ex de,hl +tolc1: ld a,(hl) ; get character to be transformed + cp 'A' + jp c,tolc2 ; next character if less than 'A' + cp 'Z'+1 + jp nc,tolc2 ; next character if greater than 'Z' + add a,'a'-'A' ; to lower case + ld (hl),a ; store back +tolc2: inc hl ; point to next character + dec b ; count down length + jp nz,tolc1 ; repeat if necessary + ex de,hl ; points to next length byte + dec c ; update number of table entries processed + jp nz,tolc ; if not equal to zero, continue +;end patch CCP and BDOS + endif + + + if initCmd + ld de,ccp+7 ; destination in CCP + ld hl,cmdBeg ; command length, command, 0 +movCmd: ld a,(hl) ; get byte + ld (de),a ; store at destination + or a ; check byte + jp z,doneMv ; zero byte is the last, done + inc hl ; next source + inc de ; next destination + jp movCmd ; repeat +doneMv: ld (cmdBeg),a ; execute only once + endif + + ld a,creset ; reset command + out (constat),a ; reset console device + out (punstat),a ; and list/punch device + ld bc,0080h + call setdma + ld a,(cdisk) ; get current disk + cp ndisks+nhdisks ; does it exist? + jp c,ent1 ; yes, proceed + ld a,(bootdr1) ; get boot drive + ld (cdisk),a ; and make it current disk +ent1: ld c,a ; inform CCP + ei + jp ccp + + if initCmd +cmdBeg: db cmdEnd-cmdBeg-2,'DO INITMAKE',0 +cmdEnd equ $ + endif + + + if patchOS +; DD40 3A E3EF ld a,(cdisk) +; DD43 B7 or a +; DD44 3E 00 ld a,0 +; DD46 C4 DCBD call nz,select +; DD49 11 E3AC ld de,subfcb +;DD43: jp ccpp1 +ccpp1: ld e,a ; := current disk + ld a,(bootdr1) ; := boot drive + cp e ; compare boot drive with current disk + jp ccp+0146h ; a select of boot drive occurs iff current disk <> boot drive + +; DD7D 3A E3EF ld a,(cdisk) +; DD80 B7 or a +; DD81 C4 DCBD call nz,select +; DD84 21 DC08 ld hl,combuf +;DD7D: jp ccpp2 +ccpp2: ld a,(bootdr1) ; := boot drive + ld e,a ; := boot drive + ld a,(ccp+07efh) ; := current disk + cp e ; compare boot drive with current disk + jp ccp+0181h ; a select of current disk occurs iff current disk <> boot drive + +; DDE3 36 00 ld (hl),0 ;submit flag is set to false +; DDE5 AF xor a +; DDE6 CD DCBD call select ;on drive a to erase file +; DDE9 11 E3AC ld de,subfcb +;DDE3: jp ccpp3 +ccpp3: ld (hl),0 ; patched over + ld a,(bootdr1) ; := boot drive + jp ccp+01e6h ; go select boot drive + +; patch bdos to change the drive selected by +; BDOS Function 13 (Reset Disk System). +f13pat: ld a,(bootdr1) ; get boot drive + ld (bdos+033ch),a ; store into curdsk (BDOS) + jp bdos+0c8ah + +; patch ccp to look on ipl drive if file not found +ccpat: ld hl,ccp+07f0h ; look at drive spec in command + or (hl) ; zero means default was taken + jp nz,ccp+076bh ; if nonzero don't change it + ld a,(bootdr1) ; take boot drive and increment it since + inc a ; for a FCB A=1, B=2, ... + ld (hl),a ; modify command line + ld de,ccp+07d6h ; setup for retry + jp ccp+06cdh ; go retry command + +; patch ccp to show current user number in prompt +propat: call ccp+0113h ; get current user no + or a + jp z,prono ; do not show it if it's 0 + cp 10 ; see if 1 or 2 digits + jp nc,pro2 + add a,'0' +pro1: call ccp+008ch ; output a character +prono: ld a,'>' ; prompt character + call ccp+008ch ; output it + jp ccp+0395h ; resume ! +pro2: add a,'0' - 10 + push af + ld a,'1' + call ccp+008ch + pop af + jp pro1 + +; patch bdos to look at user 0 if file not found in current user # +pubpat: ld a,b ; get char count + or a ; looking at first byte? + jp nz,pubno ; no, skipit + ld a,(de) ; get user # from directory + cp 0e5h ; active dir entry? + jp z,pubno ; no + ld a,(hl) ; get user# from dir entry + or a ; is it user # 0? + jp z,bdos+0776h ; yes, force char match regardless +pubno: ld a,b + cp 13 + jp bdos+075bh + endif + +; print the message pointed to by and terminated by '$' to the console +; leaves unchanged +msg: ld a,(de) ; get character + cp '$' ; is is the terminating character? + ret z ; yes, we are done + ld c,a ; 'conout' expects the character in + call conout ; disply it on console + inc de ; point to next character + jp msg ; and repeat + +; The WBOOT entry point gets control when a warm start occurs. A warm +; start is performed whenever a user program branches to location 0000H, or +; when the CPU is reset from the front panel. The CP/M system must be +; loaded from the first two tracks of drive A up to, but not including, the +; BIOS, or CBIOS, if the user has completed the patch. System parameters +; must be initialized as follows: +; location 0,1,2 Set to JMP WBOOT for warm starts +; (000H: JMP 4A03H + b) +; location 3 Set initial value of IOBYTE, if implemented in the +; CBIOS +; location 4 High nibble = current user no; low nibble current +; drive +; location 5,6,7 Set to JMP BDOS, which is the primary entry point +; to CP/M for transient programs. (0005H: JMP 3C06H + b) +; Upon completion of the initialization, the WBOOT program must branch to the +; CCP at 3400H + b to restart the system. Upon entry to the CCP, register C +; is set to the drive to select after system initialization. The WBOOT +; routine should read location 4 in memory, verify that is a legal drive, and +; pass it to the CCP in register C. +wboot: ld sp,chk02 + ld a,(bootdr1) ; make sure that ccp and bdos are loaded from correct disk + + if nhdisks gt 0 + cp ndisks + jp c,altdsk + ld b,32 ; reset hard disk controller + ld a,hdskReset ; by issuing the reset command 32 times +rhdsk: out (hdskPort),a + dec b + jp nz,rhdsk ; post condition is := 0 + ld de,firstDiskAddr ; := 0 (Track), := 8 (Sector) + ld hl,ccp ; DMA address + ld c,sectors ; is loop counter +again: ld a,hdskRead + out (hdskport),a ; send read command to hard disk port + ld a,(bootdr1) ; in real life take disk number from boot ROM + sub ndisks ; correct for Altair disks + out (hdskport),a ; send drive to boot from to hard disk port + ld a,e + out (hdskport),a ; send sector + ld a,d + out (hdskport),a ; send lower byte of track + xor a + out (hdskport),a ; send higher byte of track which is always 0 + ld a,l + out (hdskport),a ; send lower byte of DMA address + ld a,h + out (hdskport),a ; send upper byte of DMA address + in a,(hdskport) ; perform operation and get result + or a + jp z,cont ; continue if no error + halt ; halt otherwise +cont: ld a,c ; save in + ld c,csecsiz ; is now 128 since always zero + add hl,bc ; get next DMA address + ld c,a ; restore from + dec c ; decrement loop counter + jp z,entcpm + inc e ; Sector := Sector + 2 + inc e + ld a,e + cp spt ; is new Sector equal to 32 + jp z,switch ; yes, need to go to odd sectors + cp spt+1 ; is new Sector equal to 33 + jp nz,again ; no, proceed with read + ld e,0 ; Sector := 0 + inc d ; Track := Track + 1 + jp again ; proceed with read +switch: ld e,1 ; Sector := 1 + jp again ; proceed with read +altdsk equ $ + endif + + out (selout),a ; select it + ld a,cload ; load head command + out (dskcon),a ; load head to drive surface + call dhome ; position disk head on track zero + ld de,ccp ; destination load address + ld b,17 ; first sector to read on track zero +nextsc: push bc ; save current sector to read, is undefined + push de ; save current destination load address + call seclp2 ; position to sector in + call blread ; read the sector + pop de ; restore current destination load address, is destination + ld hl,altbuf+3 ; ignore first three byte of buffer, is source + call ldir ; has been set by 'blread' + pop bc ; is current sector, is undefined + ld hl,bios ; when reaches this address we are done + ld a,d + cp h + jp nz,decide + ld a,e + cp l +decide: jp nc,gotoit ; jump if everything loaded + inc b ; compute next sector number + inc b + ld a,b + cp spt ; compare new sector number with sectors per track + jp c,nextsc ; continue if less + ld b,1 ; otherwise prepare for odd numbered sectors + jp z,nextsc ; if old sector number was equal to sectors per track + call whmove ; loop until head movement is allowed + ld a,cstepin ; step in one track command + out (dskcon),a ; step in one track + ld b,0 ; start with even sectors + jp nextsc +gotoit: ld a,(bootdr2) ; clear disk controller of correct disk + out (selout),a ; do it + ld hl,ontrk0 ; start address of table for current track positions + ld b,ndisks ; number of disks +resett: ld (hl),track1 ; reset entry for disk + inc hl ; point to next entry + dec b ; decrement counter for disks to go + jp nz,resett ; jump if not yet done + jp entcpm + +; You should sample the status of the currently assigned console device and +; return 0FFH in register A if a character is ready to read and 00H in register +; A if no console characters are ready. +; +; console in/out routines - use sio port 1 +; +const: in a,(constat) ; get console status + rra ; I bit into carry + ld a,0 ; prepare no character available + ret nc ; I bit clear means no character, done + dec a ; character available, result is 0ffh + ret ; done + +; The next console character is read into register A, and the parity bit is set, +; high-order bit, to zero. If no console character is ready, wait until a +; character is typed before returning. + if sleepol + +conin: in a,(constat) ; get console status + rra ; I bit into carry + jp c,getchr ; get character + ld a,27 ; otherwise sleep for SIMHSleep microseconds + out (0feh),a ; execute command + jp conin ; try again +getchr: in a,(condata) ; read character + and 7fh ; clear bit 8 + ret + + else + +conin: in a,(constat) ; get console status + rra ; I bit into carry + jp nc,conin ; jump back if no character available + in a,(condata) ; read character + and 7fh ; clear bit 8 + ret + + endif + +; The character is sent from register C to the console output device. The +; character is in ASCII, with high-order parity bit set to zero. You might +; want to include a time-out on a line-feed or carriage return, if the console +; device requires some time interval at the end of the line (such as a TI Silent +; 700 terminal). You can filter out control characters that cause the console +; device to react in a strange way (CTRL-Z causes the Lear-Siegler terminal +; to clear the screen, for example). +conout: in a,(constat) ; get console status + and mout ; mask output bit + jp z,conout ; jump back if not ready for output + ld a,c ; prepare character for output + out (condata),a ; do it + ret + +; +; reader/punch routines use sio port 2 +; +; The character is sent from register C to the currently assigned listing +; device. The character is in ASCII with zero parity bit. +list: ; list aliased to punch +; The character is sent from register C to the currently assigned punch +; device. The character is in ASCII with zero parity. +punch: in a,(punstat) ; get punch status + and mout ; mask output bit + jp z,punch ; jump back if not ready for output + ld a,c ; prepare character for output + out (pundata),a ; do it + ret + +; The next character is read from the currently assigned reader device into +; register A with zero parity (high-order bit must be zero); an end-of-file +; condition is reported by returning an ASCII CTRL-Z(1AH). +reader: in a,(punstat) ; get reader status + rra ; I bit into carry + jp nc,reader ; jump back if no character available + in a,(pundata) ; read character + ret + +; The disk drive given by register C is selected for further operations, where +; register C contains 0 for drive A, 1 for drive B, and so on up to 15 for +; drive P (the standard CP/M distribution version supports four drives). On +; each disk select, SELDSK must return in HL the base address of a 16-byte +; area, called the Disk Parameter Header, described in Section 6.10. For +; standard floppy disk drives, the contents of the header and associated +; tables do not change; thus, the program segment included in the sample +; CBIOS performs this operation automatically. +; If there is an attempt to select a nonexistent drive, SELDSK returns HL = +; 0000H as an error indicator. Although SELDSK must return the header +; address on each call, it is advisable to postpone the physical disk select +; operation until an I/O function (seek, read, or write) is actually performed, +; because disk selects often occur without ultimately performing any disk +; I/O, , and many controllers unload the head of the current disk before +; selecting the new drive. This causes an excessive amount of noise and disk +; wear. The least significant bit of register E is zero if this is the first +; occurrence of the drive select since the last cold or warm start. +seldsk: ld hl,0 ; select disk number + ld a,c + ld (diskno),a + cp ndisks+nhdisks ; number of disk drives + ret nc ; error - disk number too high + ld l,a ; := disk number + ld h,0 + add hl,hl ; disk number * 2 + add hl,hl ; disk number * 4 + add hl,hl ; disk number * 8 + add hl,hl ; disk number * 16 + ld de,dpbase ; dpbase entries have size of 16 bytes + add hl,de ; = 16 * disknumber + dpbase + + if nhdisks gt 0 + ld a,(diskno) + cp ndisks ; is it a hard disk? + ret c ; no + push hl ; Preserve pointer to disk descriptor + ld bc,10 ; offset to disk parameter block address + add hl,bc + ld a,(hl) + inc hl + ld h,(hl) + ld l,a ; point at disk dpb + push hl ; save this pointer + ld a,hdskParam + out (hdskPort),a ; send 'get parameters' command + ld a,(diskno) + sub ndisks + out (hdskPort),a ; send selected HDSK number + ld b,17 +hdskpl: in a,(hdskPort) ; read 17-bytes of DPB + ld (hl), a + inc hl + dec b + jp nz,hdskpl + in a,(hdskPort) ; read LSB of disk's physical sector size. + cp 128 ; is it 128? + jp nz,secnok1 ; no, fail + in a,(hdskPort) ; read MSB of disk's physical sector size. + or a ; is it 0? + jp nz,secnok2 ; no, sector size is not 128, fail + pop hl ; restore disk parameter block + ld bc,11 ; offset to CKS + add hl,bc ; points to CKS + ld a,(hl) ; get lower byte + inc hl + or (hl) ; or with higher byte + jp z,secok ; success if zero + ld de,secmsg3 ; otherwise not a hard disk + jp prmsg ; print error message +secok: pop hl ; restore pointer to disk descriptor + ret +secnok1: + in a,(hdskPort) ; get and drop MSB +secnok2: + ld de,secmsg2 ; physical sector is not 128 +prmsg: call msg ; print error message + halt + jp rom +secmsg2: + db cr, lf, 'Physical sector size must be 128 bytes.', cr, lf, '$' + +secmsg3: + db cr, lf, 'Must be a hard disk.', cr, lf, '$' + + else + ret + endif + +; The disk head of the currently selected disk (initially disk A) is moved to +; the track 00 position. If the controller allows access to the track 0 flag +; from the drive, the head is stepped until the track 0 flag is detected. If the +; controller does not support this feature, the HOME call is translated into a +; call to SETTRK with a parameter of 0. +home: ld bc,0 ; move to track 00 + ; fall into settrk + +; Register BC contains the track number for subsequent disk accesses on the +; currently selected drive. The sector number in BC is the same as the +; number returned from the SECTRAN entry point. You can choose to seek +; the selected track at this time or delay the seek until the next read or write +; actually occurs. Register BC can take on values in the range 0-76 +; corresponding to valid track numbers for standard floppy disk drives and +; 0-65535 for nonstandard disk subsystems. +settrk: ld l,c ; save track + ld h,b + ld (track),hl + ret + +; Register BC contains the sector number, 1 through 26, for subsequent disk +; accesses on the currently selected drive. The sector number in BC is the +; same as the number returned from the SECTRAN entry point. You can +; choose to send this information to the controller at this point or delay +; sector selection until a read or write operation occurs. +setsec: ld a,c ; set sector + ld (sector),a + ret + +; Logical-to-physical sector translation is performed to improve the overall +; response of CP/M. Standard CP/M systems are shipped with a skew factor +; of 6, where six physical sectors are skipped between each logical read +; operation. This skew factor allows enough time between sectors for most +; programs to load their buffers without missing the next sector. In particular +; computer systems that use fast processors, memory, and disk subsystems, +; the skew factor might be changed to improve overall response. However, +; the user should maintain a single-density IBM-compatible version of CP/M +; for information transfer into and out of the computer system, using a skew +; factor of 6. +; In general, SECTRAN receives a logical sector number relative to zero in +; BC and a translate table address in DE. The sector number is used as an +; index into the translate table, with the resulting physical sector number in +; HL. For standard systems, the table and indexing code is provided in the +; CBIOS and need not be changed. +sectrn: + if nhdisks gt 0 + ld l,c ; := BC, prepration for = 0 + ld h,b ; load upper byte + inc hl ; rebase to one + ld a,e ; get lower byte of translate table address + or d ; or with upper byte + ret z ; if equal to zero, no translation necessary + endif + ex de,hl ; := translate table address + add hl,bc ; add sector number + ld l,(hl) ; get pointed to byte + ld h,0 ; set upper byte to zero + ret ; done + +; Register BC contains the DMA (Disk Memory Access) address for +; subsequent read or write operations. For example, if B = 00H and C = 80H +; when SETDMA is called, all subsequent read operations read their data +; into 80H through 0FFH and all subsequent write operations get their data +; from 80H through 0FFH, until the next call to SETDMA occurs. The initial +; DMA address is assumed to be 80H. The controller need not actually +; support Direct Memory Access. If, for example, all data transfers are +; through I/O ports, the CBIOS that is constructed uses the 128byte area +; starting at the selected DMA address for the memory buffer during the +; subsequent read or write operations. +setdma: ld l,c ; set dma address + ld h,b + ld (dmaad),hl + ret + +; +; altair disk read/write drivers +; +; Assuming the drive has been selected, the track has been set, and +; the DMA address has been specified, the READ subroutine attempts to +; read eone sector based upon these parameters and returns the following +; error codes in register A: +; +; 0 no errors occurred +; +; 1 nonrecoverable error condition occurred +; +; Currently, CP/M responds only to a zero or nonzero value as the return +; code. That is, if the value in register A is 0, CP/M assumes that the disk +; operation was completed properly. IF an error occurs the CBIOS should +; attempt at least 10 retries to see if the error is recoverable. When an error +; is reported the BDOS prints the message BDOS ERR ON x: BAD +; SECTOR. The operator then has the option of pressing a carriage return to +; ignore the error, or CTRL-C to abort. + if nhdisks gt 0 +read: ld a,(diskno) ; get disk number + cp ndisks ; compare with number of Altair disks + jp c,aread ; carry means we got an Altair disk + ld a,hdskRead ; otherwise perform hard disk read + jp shdpar ; send hard disk parameters +aread equ $ + else +read equ $ + endif + call poshed ; select disk 'diskno' and position disk head to 'track' + call secget ; position head to desired sector + di + call blread + ld a,cuload ; unload head command + out (dskcon),a ; do it + ei + ld de,altbuf+3 ; address of sector just read + ld hl,(dmaad) ; destination address + ex de,hl ; prepare for ldir + call ldir ; move + +; You return the ready status of the list device used by the DESPOOL +; program to improve console response during its operation. The value 00 is +; returned in A if the list device is not ready to accept a character and 0FFH +; if a character can be sent to the printer. A 00 value should be returned if +; LIST status is not implemented. +listst: xor a ; := 0 means no error + ret + +; Data is written from the currently selected DMA address to the currently +; selected drive, track, and sector. For floppy disks, the data should be +; marked as nondeleted data to maintain compatibility with other CP/M +; systems. The error codes given in the READ command are returned in +; register A, with error recovery attempts as described above. + if nhdisks gt 0 +write: ld a,(diskno) ; get disk number + cp ndisks ; compare with number of Altair disks + jp c,awrite ; carry means we got an Altair disk + ld a,hdskWrite ; otherwise perform hard disk write +shdpar: out (hdskPort),a ; send command + ld a,(diskno) ; get disk number + sub ndisks ; rebase + out (hdskPort),a ; send rebased disk number + ld a,(sector) ; get sector + dec a ; rebase to 0 + out (hdskPort),a ; send rebased sector number + ld a,(track) ; get lower byte of track + out (hdskPort),a ; send lower byte of track + ld a,(track+1) ; get upper byte of track + out (hdskPort),a ; send upper byte of track + ld a,(dmaad) ; get lower byte DMA address + out (hdskPort),a ; send lower byte of DMA address + ld a,(dmaad+1) ; get upper byte of DMA address + out (hdskPort),a ; send upper byte of DMA address + in a,(hdskPort) ; perform command and get result + ret +awrite equ $ + else +write equ $ + endif + call poshed ; select desired disk and position to desired track + call secget ; position head to desired sector + ld hl,(dmaad) ; source of sector is in 'dmaad' + ld de,altbuf+3 ; destination inside local buffer + ld bc,csecsiz ; sector size is 128 + call ldir ; block move + ld a,cwrseq ; command for 'start write enable sequence' + out (dskcon),a ; do it + di + ld hl,altbuf ; point to first byte in local buffer + ld b,asecsiz+1 ; number of bytes to write (additional byte triggers 'real' write) +wready: in a,(statin) ; get status + rra ; get bit for ready for write + jp c,wready ; loop until ready for write + ld a,(hl) ; byte to write + out (dskwrit),a ; write byte + inc hl ; point to next byte + dec b ; decrement counter of bytes + jp nz,wready ; jp if not done + ld a,cuload ; unload head command + out (dskcon),a ; do it + ei + xor a ; := 0 means no error + ret + +; Postcondition: 'altbuf' contains 'asecsiz' many bytes, is set to 'csecsiz' +blread: ld hl,altbuf ; address of sector buffer + ld e,asecsiz ; number of bytes to read +blrd1: in a,(statin) ; get disk status + or a ; set sign of byte + jp m,blrd1 ; loop until disk has new byte to read + in a,(dskread) ; read byte of sector + ld (hl),a ; store into buffer + inc hl ; point to next position in buffer + dec e ; decrement size counter + jp nz,blrd1 ; if not zero, we need to continue + ld bc,csecsiz ; sector size in preparation for call to 'ldir' + ret + +; position disk on track zero, == 0 at the end +dhome: in a,(statin) ; position disk to track 0 + and mtzero ; mask for 'head is on track zero' + ret z ; track zero reached, done + call whmove ; loop until head movement is allowed + ld a,cstepot ; command for 'step head out one track' + out (dskcon),a ; do it + jp dhome ; try again + +; Select disk 'diskno' and position disk head to 'track' +poshed: call calcd ; position altair disk head + ld a,d ; select disk , cur track in + out (selout),a ; select disk + in a,(statin) ; get status of selected drive + cp mall ; ok? + jp z,selerr ; no! + ld a,b ; := track of selected disk + cp track1 ; compare with non-existing track + jp nz,alseek ; if a regular track, proceed to seek + call dhome ; position disk to track 0 + ld b,a ; := 0 (current track) +;Input: location 'track' contains desired track +; contains current track +;Output: desired track is reached and stored in track array +alseek: ld a,(track) ; seek to 'track' (cur track in b) + ld e,a ; := desired track + ld a,b ; := current track + sub e ; := current track - desired track + ret z ; we are already at desired track + ld e,a ; e is the number of "step in" or "step out" + jp c,stpin ; current track < desired track + ld c,cstepot ; command for step head out one track + jp aseek ; perform steps +stpin: ld c,cstepin ; command for step head in one track + cpl ; := ~(current track - desired track) + inc a ; := desired track - current track (positive) + ld e,a ; is positive number of tracks to move +aseek: call whmove ; loop until head movement is allowed + ld a,c ; get command (step in or step out) + out (dskcon),a ; perform it + dec e ; next iteration + jp nz,aseek ; loop if not done + call calcd ; get pointer to 'track' of 'diskno' + ld a,(track) ; this is the current track + ld (hl),a ; update 'track' of 'diskno' + ret +selerr: pop hl ; discard return address + ld a,bioserr ; := 1 means error + ret + +; loop until head movement is allowed +whmove: in a,(statin) ; get status + and mhm ; mask for 'head movement allowed' + jp nz,whmove ; loop until movement allowed + ret + +; Input: - implicit input is location 'diskno' +; Output: contains the current track of 'diskno' +; , and contain 'diskno' +; points to 'track' of 'diskno' +calcd: ld a,(diskno) ; get 'diskno' + ld e,a ; := 'diskno' + ld hl,ontrk0 + ld d,0 + add hl,de ; points to 'track' of 'diskno' + ld b,(hl) ; := 'track' of 'diskno' + ld d,e ; := 'diskno' + ret + +; Input: 'sector' contains desired sector number +; Output: head is positioned at desired sector +secget: ld a,cload ; command to load head to drive surface + out (dskcon),a ; do it + ld a,(sector) ; := desired sector + dec a ; adjust to range 0..(spt-1) + ld b,a ; := adjusted, desired sector + cp spt ; compare with sectors per track + jp c,seclp2 ; desired sector is less than total sectors per track, ok + ld de,secmsg ; prepare error message + call msg ; print it + halt ; not much we can do +seclp2: in a,(secpos) ; get sector position + rra ; rotate T bit into carry + jp c,seclp2 ; loop until sector is positioned to read or write + and sptmask ; now contains the sector under the head + cp b ; compare with desired sector + jp nz,seclp2 ; repeat if not equal + ret + +; Move bytes from start address to destination . +; This is equivalent to the Z80 instruction 'LDIR'. +; This subroutine dynamically determines the processor. +ldir: xor a ; := 0 + dec a ; := 1111'1111b + jp pe,ldir1 ; on an 8080 this means parity is even + ldir ; otherwise we have a Z80 + ret +ldir1: ld a,(hl) ; get byte from source + ld (de),a ; put byte to destination + inc hl ; point to next source address + inc de ; point to next destination address + dec bc ; decrement number of bytes to move + ld a,c ; := ( or ) + or b + jp nz,ldir1 ; not zero, move again + ret + + if patchOS +lctabs: db 9 ; (R)EAD ERROR + dw ccp+03e0h ; DFE0 + db 6 ; (N)O FILE + dw ccp+03f1h ; DFF1 + db 2 ; (A)LL + dw ccp+0553h ; E153 + db 7 ; (N)O SPACE + dw ccp+0608h ; E208 + db 10 ; (F)ILE EXISTS + dw ccp+0683h ; E283 + db 7 ; (B)AD LOAD + dw ccp+077bh ; E37B +lctabe equ $ + +patchs: dw ccp+0143h, ccpp1 ; DD43: jp ccpp1 + dw ccp+017dh, ccpp2 ; DD7D: jp ccpp2 + dw ccp+01e3h, ccpp3 ; DDE3: jp ccpp3 + dw ccp+0392h, propat + dw ccp+06dbh, ccpat + dw bdos+0c86h, f13pat + dw bdos+0758h, pubpat +patche equ $ + endif + +; In general, each disk drive has an associated (16-byte) disk parameter +; header that contains information about the disk drive and provides a +; scratch pad area for certain BDOS operations. The format of the disk +; parameter header for each drive is shown below, where each element is a +; word (16-bit) value. +; +; DISK PARAMETER HEADER +; +-------+------+------+------+----------+-------+-------+-------+ +; | XLT | 0000 | 0000 | 0000 |DIRBUF| DPB | CSV | ALV | +; +------+------+------+-------+----------+-------+-------+-------+ +; 16B 16B 16B 16B 16B 16B 16B 16B +; +; XLT Address of the logical-to-physical translation vector, if used +; for this particular drive, or the value 0000H if no sector translation +; takes place (that is, the physical and logical sector numbers are the +; same). Disk drives with identical sector skew factors share the same +; translate tables. +; +; 0000 Scratch pad values for use within the BDOS, initial value is +; unimportant. DIRBUF Address of a 128-byte scratch pad area for directory +; operations within BDOS. All DPHs address the same scratch pad area. +; +; DPB Address of a disk parameter block for this drive. Drives +; withidentical disk characteristics address the same disk parameter block. +; +; CSV Address of a scratch pad area used for software check for +; changed disks. This address is different for each DPH. +; +; ALV Address of a scratch pad area used by the BDOS to keep disk +; storage allocation information. This address is different for each DPH. +; +; Given n disk drives, the DPHs are arranged in a table whose first row of 16 +; bytes corresponds to drive 0, with the last row corresponding to drive n-1. +; In the following figure the label DPBASE defines the base address of the +; DPH table. +; +; DPBASE: +; 00 XLT00 0000 0000 0000 DIRBUF DBP00 CSV00 ALV00 +; 01 XLT01 0000 0000 0000 DIRBUF DBP01 CSV01 ALV01 +; (and so on through) +; n-1 XLTn-1 0000 0000 0000 DIRBUF DBPn-1 CSVn-1 ALVn-1 + +; +; The translation vectors, XLT00 through XLTn-1, are located elsewhere in the +; BIOS, and simply correspond one-for-one with the logical sector numbers +; zero through the sector count 1. The Disk Parameter Block (DPB) for each +; drive is more complex. As shown below, particular DPB, that is addressed by +; one or more DPHS, takes the general form: +; +; +---+---+---+---+---+---+---+---+---+---+ +; |SPT|BSH|BLM|EXM|DSM|DRM|AL0|AL1|CKS|OFF| +; +---+---+---+---+---+---+---+---+---+---+ +; 16B 8B 8B 8B 16B 16B 8B 8B 16B 16B +; +; where each is a byte or word value, as shown by the 8b or 16b indicator +; below the field. +; +; The following field abbreviations are used in the figure above: +; SPT is the total number of sectors per track. +; BSH is the data allocation block shift factor, determined by +; the data block allocation size. +; BLM is the data allocation block mask (2[BSH-1]). +; EXM is the extent mask, determined by the data block +; allocation size and the number of disk blocks. +; DSM determines the total storage capacity of the disk drive. +; DRM determines the total number of directory entries that +; can be stored on this drive. +; AL0, AL1 determine reserved directory blocks. +; CKS is the size of the directory check vector. +; +; OFF is the number of reserved tracks at the beginning of the +; (logical) disk. +; +; The values of BSH and BLM determine the data allocation size BLS, which is +; not an entry in the DPB. Given that the designer has selected a value for +; BLS, the values of BSH and BLM are shown in the following table. +; +; BLS BSH BLM +; 1,024 3 7 +; 2,048 4 15 +; 4,096 5 31 +; 8,192 6 63 +; 16,384 7 127 +; +; where all values are in decimal. The value of EXM depends upon both the BLS +; and whether the DSM value is less than 256 or greater than 255, as shown in +; the table below. +; +; EXM values +; BLS DSM<256 DSM>255 +; 1,024 0 N/A +; 2,048 1 0 +; 4,096 3 1 +; 8,192 7 3 +; 16,384 15 7 +; +; The value of DSM is the maximum data block number supported by this +; particular drive, measured in BLS units. The product (DSM + 1) is the total +; number of bytes held by the drive and must be within the capacity of the +; physical disk, not counting the reserved operating system tracks. +; +; The DRM entry is the one less than the total number of directory entries +; that can take on a 16-bit value. The values of AL0 and AL1, however, are +; determined by DRM. The values AL0 and AL1 can together be considered a +; string of 16-bits, as shown below. +; +; |--------- AL0 ---------|-------- AL1 ----------| +; 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 +; +; Position 00 corresponds to the high-order bit of the byte labeled AL0 and +; 15 corresponds to the low-order bit of the byte labeled AL1. Each bit +; position reserves a data block for number of directory entries, thus +; allowing a total of 16 data blocks to be assigned for directory entries +; (bits are assigned starting at 00 and filled to the right until position +; 15). Each directory entry occupies 32 bytes, resulting in the following +; tabulation: +; +; BLS Directory Entries +; 1,024 32 times # bits +; 2,048 64 times # bits +; 4,096 128 times # bits +; 8,192 256 times # bits +; 16,384 512 times # bits +; +; Thus, if DRM = 127 (128 directory entries) and BLS = 1024, there are 32 +; directory entries per block, requiring 4 reserved blocks. In this case, the +; 4 high-order bits of AL0 are set, resulting in the values AL0 = 0F0H and +; AL1 = 00H. +; +; The CKS value is determined as follows: if the disk drive media is +; removable, then CKS = (DRM + 1)/4, where DRM is the last directory entry +; number. If the media are fixed, then set CKS = 0 (no directory records are +; checked in this case). +; +; Finally, the OFF field determines the number of tracks that are skipped at +; the beginning of the physical disk. This value is automatically added +; whenever SETTRK is called and can be used as a mechanism for skipping +; reserved operating system tracks or for partitioning a large disk into +; smaller segmented sections. +; +; To complete the discussion of the DPB, several DPHs can address the same +; DPB if their drive characteristics are identical. Further, the DPB can be +; dynamically changed when a new drive is addressed by simply changing the +; pointer in the DPH; because the BDOS copies the DPB values to a local area +; whenever the SELDSK function is invoked. +; +; Returning back to DPH for a particular drive, the two address values CSV +; and ALV remain. Both addresses reference an area of uninitialized memory +; following the BIOS. The areas must be unique for each drive, and the size +; of each area is determined by the values in the DPB. +; +; The size of the area addressed by CSV is CKS bytes, which is sufficient to +; hold the directory check information for this particular drive. If CKS = +; (DRM + 1)/4, you must reserve (DRM + 1)/4 bytes for directory check use. If +; CKS = 0, no storage is reserved. +; +; The size of the area addressed by ALV is determined by the maximum number +; of data blocks allowed for this particular disk and is computed as (DSM/8) +; + 1. + +; +; diskette drives +; +dpbase equ $ + dw atrans,0,0,0,dirbf,mits2,chk00,all00 + dw atrans,0,0,0,dirbf,mits2,chk01,all01 + dw atrans,0,0,0,dirbf,mits2,chk02,all02 + dw atrans,0,0,0,dirbf,mits2,chk03,all03 + dw atrans,0,0,0,dirbf,mits2,chk04,all04 + dw atrans,0,0,0,dirbf,mits2,chk05,all05 + dw atrans,0,0,0,dirbf,mits2,chk06,all06 + dw atrans,0,0,0,dirbf,mits, chk07,all07 + + if nhdisks gt 0 +defdw macro ?value + dw all0&?value + endm + +defdp macro ?number + local ?hdi +?hdi defl 8 + rept ?number + dw 0,0,0,0,dirbf,simhd,0 + defdw %?hdi +?hdi defl ?hdi+1 + endm + endm + + defdp nhdisks + +simhd: dw spt ; SPT, sectors per track + db 5 ; BSH, data allocation block shift factor, for BLS=4,096 + db 31 ; BLM, data allocation block mask, for BLS=4,096 + db 1 ; extent mask for BLS=4,096 and DSM>255 + dw 2047-restrk ; DSM, maximum data block number + dw 1023 ; DRM, number of directory entries - 1 + db 0ffh,0 ; AL0, AL1, 8 blocks reserved to hold all entries + ; (number of directory entries)*32 = (number of reserved blocks)*(block size BLS) + ; 1024 * 32 = 8 * 4096 + dw 0 ; CKS, set 0 since hard disk is fixed + dw restrk ; OFF, number of tracks skipped at beginning of disk + db 0 ; PSH + db 0 ; PHM + endif + +; copylib (default) format +mits: dw spt ; spt, sectors per track + db 3 ; allocation block shift factor, bsh + db 7 ; data allocation block mask, blm, allocation size (bls) = 1024 + db 0 ; extent mask + dw dsm07 ; dsm, maximum data block number + dw dirent ; drm, number of directory entries - 1 + db 0ffh,0 ; al0, al1, 8 blocks reserved to hold all entries + ; 256 * 32 = 8 * 1024 + ; (drm+1) * 32 = (number of bits in al0 and al1) * bls + dw cks ; cks = (drm + 1)/4 + dw restrk ; off, number of tracks skipped at beginning of disk + db 0 ; PSH + db 0 ; PHM + +mits2: dw spt ; spt, sectors per track + db 4 ; allocation block shift factor, bsh + db 15 ; data allocation block mask, blm, allocation size (bls) = 2048 + db 0 ; extent mask + dw dsm06 ; dsm, maximum data block number + dw dirent ; drm, number of directory entries - 1 + db 0f0h,0 ; al0, al1, 4 blocks reserved to hold all entries + ; 256 * 32 = 4 * 2048 + ; (drm+1) * 32 = (number of bits in al0 and al1) * bls + dw cks ; cks = (drm + 1)/4 + dw restrk ; off, number of tracks skipped at beginning of disk + db 0 ; PSH + db 0 ; PHM + +; speedball (copylib) skewtable +atrans: db 01,18,03,20,05,22,07,24 + db 09,26,11,28,13,30,15,32 + db 17,02,19,04,21,06,23,08 + db 25,10,27,12,29,14,31,16 + +msg1: db cr, lf + db '0' + (msize/10) + db '0' + (msize MOD 10) + db 'K Dougs CP/M Version 2.2 (SIMH ALTAIR 8800, BIOS V1.27, ' + + if nhdisks gt 0 + db '0' + nhdisks + db ' HD, ' + endif + + db '02-May-2009)' + db cr, lf, '$' + + if needZ80 +msg2: db cr, lf, '8080 CPU detected. Need Z80.', cr, lf, '$' + endif + +secmsg: db cr, lf, 'Cannot find sector in register ', cr, lf, '$' + +; position disk drive head +ontrk0: db track1 ; current track# drive 0 (logical 1) + db track1 ; current track# drive 1 (logical 2) + db track1 ; current track# drive 2 (logical 3) + db track1 ; current track# drive 3 (logical 4) + db track1 ; current track# drive 4 (logical 5) + db track1 ; current track# drive 5 (logical 6) + db track1 ; current track# drive 6 (logical 7) + db track1 ; current track# drive 7 (logical 8) + +diskno: db 0 +sector: db 0 +track: dw 0 +dmaad: dw 0 + +; begin scratch area for bdos +dirbf: ds 128 ; directory work space +all00: ds ((dsm06+1)/8)+1 +all01: ds ((dsm06+1)/8)+1 +all02: ds ((dsm06+1)/8)+1 +all03: ds ((dsm06+1)/8)+1 +all04: ds ((dsm06+1)/8)+1 +all05: ds ((dsm06+1)/8)+1 +all06: ds ((dsm06+1)/8)+1 +all07: ds ((dsm07+1)/8)+1 + + if nhdisks gt 0 + +deflab macro ?value +all0&?value equ $ + endm + +defall macro ?number + local ?hdi +?hdi defl 8 + rept ?number + deflab %?hdi + ds 256 +?hdi defl ?hdi+1 + endm + endm + + defall nhdisks + endif + +chk00: ds cks +chk01: ds cks +chk02: ds cks +chk03: ds cks +chk04: ds cks +chk05: ds cks +chk06: ds cks +chk07: ds cks +altbuf: ds asecsiz+1 + +biosend equ $ +biossiz equ biosend-bios + +; fill remainder with 0 + +fillmod equ biossiz AND 00ffh + if fillmod gt 0 +fillsiz equ 100h-fillmod + ds fillsiz + endif + + if2 +padjust macro ?newsiz + .printx /Adjust bioslen in MEMCFG.LIB to ?newsiz/ + endm + +psize macro ?val1,?val2,?val3,?val4 + .printx /BIOS extends from ?val1 to ?val2 (Size ?val3, bioslen = ?val4)/ + endm + +psave macro ?value + .printx /SAVE ?value CPMBOOT.COM/ + endm + + .radix 16 + psize %bios,%biosend,%biossiz,%bioslen + if biossiz gt bioslen + padjust %(100h*((biossiz + 0ffh) / 100h)) + endif + .radix 10 + if biosend gt 0ff00h + .printx /Warning: BIOS extends into Altair ROM/ + endif + + psave %(9+(ccplen + bdoslen + bioslen) / 100h) + + endif + + .dephase + + end diff --git a/doug/src/driccp.mac b/doug/src/driccp.mac new file mode 100755 index 00000000..38d61a66 --- /dev/null +++ b/doug/src/driccp.mac @@ -0,0 +1,1205 @@ + title 'console command processor (CCP), ver 2.0' + + .Z80 + aseg + org 100h + maclib MEMCFG.LIB ; define configuration parameters + .phase ccpph ; CCPLOC not needed, we use ccpph instead + +; assembly language version of the CP/M console command processor +; +; version 2.2 February, 1980 + +; Copyright (c) 1976, 1977, 1978, 1979, 1980 +; Digital Research +; Box 579, Pacific Grove, +; California, 93950 + +bdosl equ bdosph ;bdos location +tran equ 100h +tranm equ $ +ccploc equ $ + +; ******************************************************** +; * Base of CCP contains the following code/data * +; * ccp: jmp ccpstart (start with command) * +; * jmp ccpclear (start, clear command) * +; * ccp+6 127 (max command length) * +; * ccp+7 comlen (command length = 00) * +; * ccp+8 ' ... ' (16 blanks) * +; ******************************************************** +; * Normal entry is at ccp, where the command line given * +; * at ccp+8 is executed automatically (normally a null * +; * command with comlen = 00). An initializing program * +; * can be automatically loaded by storing the command * +; * at ccp+8, with the command length at ccp+7. In this * +; * case, the ccp executes the command before prompting * +; * the console for input. Note that the command is exe-* +; * cuted on both warm and cold starts. When the command* +; * line is initialized, a jump to "jmp ccpclear" dis- * +; * ables the automatic command execution. * +; ******************************************************** + + jp ccpstart ;start ccp with possible initial command + jp ccpclear ;clear the command buffer +maxlen: db 127 ;max buffer length +comlen: db 0 ;command length (filled in by dos) + +; (command executed initially if comlen non zero) +combuf: db ' ' ;8 character fill + db ' ' ;8 character fill + db 'COPYRIGHT (C) 1979, DIGITAL RESEARCH '; 38 + ds 128-($-combuf) +; total buffer length is 128 characters + +comaddr: + dw combuf ;address of next to char to scan +staddr: ds 2 ;starting address of current fillfcb request + +diska equ 0004h ;disk address for current disk +bdos equ 0005h ;primary bdos entry point +buff equ 0080h ;default buffer +fcb equ 005ch ;default file control block + +rcharf equ 1 ;read character function +pcharf equ 2 ;print character function +pbuff equ 9 ;print buffer function +rbuff equ 10 ;read buffer function +breakf equ 11 ;break key function +liftf equ 12 ;lift head function (no operation) +initf equ 13 ;initialize bdos function +self equ 14 ;select disk function +openf equ 15 ;open file function +closef equ 16 ;close file function +searf equ 17 ;search for file function +searnf equ 18 ;search for next file function +delf equ 19 ;delete file function +dreadf equ 20 ;disk read function +dwritf equ 21 ;disk write function +makef equ 22 ;file make function +renf equ 23 ;rename file function +logf equ 24 ;return login vector +cself equ 25 ;return currently selected drive number +dmaf equ 26 ;set dma address +userf equ 32 ;set user number + +; special fcb flags +rofile equ 9 ;read only file +sysfile equ 10 ;system file flag + +; special characters +cr equ 13 ;carriage return +lf equ 10 ;line feed +la equ 5fh ;left arrow +eofile equ 1ah ;end of file + +; utility procedures +printchar: + ld e,a + ld c,pcharf + jp bdos + +printbc: ;print character, but save b,c registers + push bc + call printchar + pop bc + ret + +crlf: ld a,cr + call printbc + ld a,lf + jp printbc + +blank: ld a,' ' + jp printbc + +print: ;print string starting at b,c until next 00 entry + push bc + call crlf + pop hl ;now print the string +prin0: ld a,(hl) + or a + ret z ;stop on 00 + inc hl + push hl ;ready for next + call printchar + pop hl ;character printed + jp prin0 ;for another character + +initialize: + ld c,initf + jp bdos + +select: ld e,a + ld c,self + jp bdos + +bdos$inr: + call bdos + ld (dcnt),a + inc a + ret + +open: ;open the file given by d,e + ld c,openf + jp bdos$inr + +openc: ;open comfcb + xor a + ld (comrec),a ;clear next record to read + ld de,comfcb + jp open + +close: ;close the file given by d,e + ld c,closef + jp bdos$inr + +search: ;search for the file given by d,e + ld c,searf + jp bdos$inr + +searchn: ;search for the next occurrence of the file given by d,e + ld c,searnf + jp bdos$inr + +searchcom: ;search for comfcb file + ld de,comfcb + jp search + +delete: ;delete the file given by d,e + ld c,delf + jp bdos + +bdos$cond: + call bdos + or a + ret + +diskread: ;read the next record from the file given by d,e + ld c,dreadf + jp bdos$cond + +diskreadc: ;read the comfcb file + ld de,comfcb + jp diskread + +diskwrite: ;write the next record to the file given by d,e + ld c,dwritf + jp bdos$cond + +make: ;create the file given by d,e + ld c,makef + jp bdos$inr + +renam: ;rename the file given by d,e + ld c,renf + jp bdos + +getuser: ;return current user code in a + ld e,0ffh ;drop through to setuser + +setuser: + ld c,userf + jp bdos ;sets user number + +saveuser: ;save user#/disk# before possible ^c or transient + call getuser ;code to a + add a,a + add a,a + add a,a + add a,a ;rot left + ld hl,cdisk + or (hl) ;4b=user, 4b=disk + ld (diska),a ;stored away in memory for later + ret + +setdiska: + ld a,(cdisk) + ld (diska),a ;user/disk + ret + +translate: ;translate character in register A to upper case + cp 61h + ret c ;return if below lower case a + cp 7bh + ret nc ;return if above lower case z + and 5fh + ret ;translated to upper case + +readcom: ;read the next command into the command buffer + ;check for submit file + ld a,(submit) + or a + jp z,nosub + ;scanning a submit file + ;change drives to open and read the file + ld a,(cdisk) + or a + ld a,0 + call nz,select + ;have to open again in case xsub present + ld de,subfcb + call open + jp z,nosub ;skip if no sub + ld a,(subrc) + dec a ;read last record(s) first + ld (subcr),a ;current record to read + ld de,subfcb + call diskread ;end of file if last record + jp nz,nosub + ;disk read is ok, transfer to combuf + ld de,comlen + ld hl,buff + ld b,128 + call move0 + ;line is transferred, close the file with a + ;deleted record + ld hl,submod + ld (hl),0 ;clear fwflag + inc hl + dec (hl) ;one less record + ld de,subfcb + call close + jp z,nosub + ;close went ok, return to original drive + ld a,(cdisk) + or a + call nz,select + ;print to the 00 + ld hl,combuf + call prin0 + call break$key + jp z,noread + call del$sub + jp ccp ;break key depressed + +nosub: ;no submit file + call del$sub + ;translate to upper case, store zero at end + call saveuser ;user # save in case control c + ld c,rbuff + ld de,maxlen + call bdos + call setdiska ;no control c, so restore diska +noread: ;enter here from submit file + ;set the last character to zero for later scans + ld hl,comlen + ld b,(hl) ;length is in b +readcom0: + inc hl + ld a,b + or a ;end of scan? + jp z,readcom1 + ld a,(hl) ;get character and translate + call translate + ld (hl),a + dec b + jp readcom0 + +readcom1: ;end of scan, h,l address end of command + ld (hl),a ;store a zero + ld hl,combuf + ld (comaddr),hl ;ready to scan to zero + ret + +break$key: ;check for a character ready at the console + ld c,breakf + call bdos + or a + ret z + ld c,rcharf + call bdos ;character cleared + or a + ret + +cselect: ;get the currently selected drive number to reg-A + ld c,cself + jp bdos + +setdmabuff: ;set default buffer dma address + ld de,buff ;(drop through) + +setdma: ;set dma address to d,e + ld c,dmaf + jp bdos + +del$sub: ;delete the submit file, and set submit flag to false + ld hl,submit + ld a,(hl) + or a + ret z ;return if no sub file + ld (hl),0 ;submit flag is set to false + xor a + call select ;on drive a to erase file + ld de,subfcb + call delete + ld a,(cdisk) + jp select ;back to original drive + +serialize: ;check serialization + ld de,serial + ld hl,bdosl + ld b,6 ;check six bytes +ser0: ld a,(de) + cp (hl) + jp nz,badserial + inc de + inc hl + dec b + jp nz,ser0 + ret ;serial number is ok + +comerr: ;error in command string starting at position + ;'staddr' and ending with first delimiter + call crlf ;space to next line + ld hl,(staddr) ;h,l address first to print +comerr0: ;print characters until blank or zero + ld a,(hl) + cp ' ' + jp z,comerr1 ; not blank + or a + jp z,comerr1 ; not zero, so print it + push hl + call printchar + pop hl + inc hl + jp comerr0 ; for another character +comerr1: ;print question mark,and delete sub file + ld a,'?' + call printchar + call crlf + call del$sub + jp ccp ;restart with next command + + ; fcb scan and fill subroutine (entry is at fillfcb below) + ;fill the comfcb, indexed by A (0 or 16) + ;subroutines +delim: ;look for a delimiter + ld a,(de) + or a + ret z ;not the last element + cp ' ' + jp c,comerr ;non graphic + ret z ;treat blank as delimiter + cp '=' + ret z + cp la + ret z ;left arrow + cp '.' + ret z + cp ':' + ret z + cp ';' + ret z + cp '<' + ret z + cp '>' + ret z + ret ;delimiter not found + +deblank: ;deblank the input line + ld a,(de) + or a + ret z ;treat end of line as blank + cp ' ' + ret nz + inc de + jp deblank + +addh: ;add a to h,l + add a,l + ld l,a + ret nc + inc h + ret + +fillfcb0: ;equivalent to fillfcb(0) + ld a,0 + +fillfcb: + ld hl,comfcb + call addh + push hl + push hl ;fcb rescanned at end + xor a + ld (sdisk),a ;clear selected disk (in case A:...) + ld hl,(comaddr) + ex de,hl ;command address in d,e + call deblank ;to first non-blank character + ex de,hl + ld (staddr),hl ;in case of errors + ex de,hl + pop hl ;d,e has command, h,l has fcb address + ;look for preceding file name A: B: ... + ld a,(de) + or a + jp z,setcur0 ;use current disk if empty command + sbc a,'A'-1 + ld b,a ;disk name held in b if : follows + inc de + ld a,(de) + cp ':' + jp z,setdsk ;set disk name if : + +setcur: ;set current disk + dec de ;back to first character of command +setcur0: + ld a,(cdisk) + ld (hl),a + jp setname + +setdsk: ;set disk to name in register b + ld a,b + ld (sdisk),a ;mark as disk selected + ld (hl),b + inc de ;past the : + +setname: ;set the file name field + ld b,8 ;file name length (max) +setnam0: call delim + jp z,padname ;not a delimiter + inc hl + cp '*' + jp nz,setnam1 ;must be ?'s + ld (hl),'?' + jp setnam2 ;to dec count + +setnam1: + ld (hl),a ;store character to fcb + inc de +setnam2: + dec b ;count down length + jp nz,setnam0 + + ;end of name, truncate remainder +trname: call delim + jp z,setty ;set type field if delimiter + inc de + jp trname + +padname: + inc hl + ld (hl),' ' + dec b + jp nz,padname + +setty: ;set the type field + ld b,3 + cp '.' + jp nz,padty ;skip the type field if no . + inc de ;past the ., to the file type field +setty0: ;set the field from the command buffer + call delim + jp z,padty + inc hl + cp '*' + jp nz,setty1 + ld (hl),'?' ;since * specified + jp setty2 + +setty1: ;not a *, so copy to type field + ld (hl),a + inc de +setty2: ;decrement count and go again + dec b + jp nz,setty0 + + ;end of type field, truncate +trtyp: ;truncate type field + call delim + jp z,efill + inc de + jp trtyp + +padty: ;pad the type field with blanks + inc hl + ld (hl),' ' + dec b + jp nz,padty + +efill: ;end of the filename/filetype fill, save command address + ;fill the remaining fields for the fcb + ld b,3 +efill0: inc hl + ld (hl),0 + dec b + jp nz,efill0 + ex de,hl + ld (comaddr),hl ;set new starting point + + ;recover the start address of the fcb and count ?'s + pop hl + ld bc,11 ;b=0, c=8+3 +scnq: inc hl + ld a,(hl) + cp '?' + jp nz,scnq0 + ;? found, count it in b + inc b +scnq0: dec c + jp nz,scnq + ;number of ?'s in c, move to a and return with flags set + ld a,b + or a + ret + +intvec: ;intrinsic function names (all are four characters) + db 'DIR ' + db 'ERA ' + db 'TYPE' + db 'SAVE' + db 'REN ' + db 'USER' +intlen equ ($-intvec)/4 ;intrinsic function length +serial: db 0,0,0,0,0,0 + + +intrinsic: ;look for intrinsic functions (comfcb has been filled) + ld hl,intvec + ld c,0 ;c counts intrinsics as scanned +intrin0: + ld a,c + cp intlen ;done with scan? + ret nc + ;no, more to scan + ld de,comfcb+1 ;beginning of name + ld b,4 ;length of match is in b +intrin1: + ld a,(de) + cp (hl) ;match? + jp nz,intrin2 ;skip if no match + inc de + inc hl + dec b + jp nz,intrin1 ;loop while matching + ;complete match on name, check for blank in fcb + ld a,(de) + cp ' ' + jp nz,intrin3 ;otherwise matched + ld a,c + ret ;with intrinsic number in a + +intrin2: ;mismatch, move to end of intrinsic + inc hl + dec b + jp nz,intrin2 + +intrin3: ;try next intrinsic + inc c ;to next intrinsic number + jp intrin0 ;for another round + +ccpclear: ;clear the command buffer + xor a + ld (comlen),a + ;drop through to start ccp +ccpstart: ;enter here from boot loader + ld sp,stack + push bc ;save initial disk number + ;(high order 4bits=user code, low 4bits=disk#) + ld a,c + rra + rra + rra + rra + and 0fh ;user code + ld e,a + call setuser ;user code selected + ;initialize for this user, get $ flag + call initialize ;0ffh in accum if $ file present + ld (submit),a ;submit flag set if $ file present + pop bc ;recall user code and disk number + ld a,c + and 0fh ;disk number in accumulator + ld (cdisk),a ;clears user code nibble + call select ;proper disk is selected, now check sub files + ;check for initial command + ld a,(comlen) + or a + jp nz,ccp0 ;assume typed already + +ccp: ;enter here on each command or error condition + ld sp,stack + call crlf ;print d> prompt, where d is disk name + call cselect ;get current disk number + add a,'A' + call printchar + ld a,'>' + call printchar + call readcom ;command buffer filled +ccp0: ;(enter here from initialization with command full) + ld de,buff + call setdma ;default dma address at buff + call cselect + ld (cdisk),a ;current disk number saved + call fillfcb0 ;command fcb filled + call nz,comerr ;the name cannot be an ambiguous reference + ld a,(sdisk) + or a + jp nz,userfunc + ;check for an intrinsic function + call intrinsic + ld hl,jmptab ;index is in the accumulator + ld e,a + ld d,0 + add hl,de + add hl,de ;index in d,e + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + jp (hl) + ;pc changes to the proper intrinsic or user function +jmptab: dw direct ;directory search + dw erase ;file erase + dw type ;type file + dw save ;save memory image + dw rename ;file rename + dw user ;user number + dw userfunc ;user-defined function +badserial: + ld hl,76f3h ;'di hlt' instructions. [di or (hlt shl 8)] + ld (ccploc),hl + ld hl,ccploc + jp (hl) + + + ;utility subroutines for intrinsic handlers +readerr: ;print the read error message + ld bc,rdmsg + jp print +rdmsg: db 'READ ERROR',0 + +nofile: ;print no file message + ld bc,nofmsg + jp print +nofmsg: db 'NO FILE',0 + +getnumber: ;read a number from the command line + call fillfcb0 ;should be number + ld a,(sdisk) + or a + jp nz,comerr ;cannot be prefixed + ;convert the byte value in comfcb to binary + ld hl,comfcb+1 + ld bc,11 ;(b=0, c=11) + ;value accumulated in b, c counts name length to zero +conv0: ld a,(hl) + cp ' ' + jp z,conv1 + ;more to scan, convert char to binary and add + inc hl + sub '0' + cp 10 + jp nc,comerr ;valid? + ld d,a ;save value + ld a,b ;mult by 10 + and 11100000b + jp nz,comerr + ld a,b ;recover value + rlca + rlca + rlca ;*8 + add a,b + jp c,comerr + add a,b + jp c,comerr ;*8+*2 = *10 + add a,d + jp c,comerr ;+digit + ld b,a + dec c + jp nz,conv0 ;for another digit + ret +conv1: ;end of digits, check for all blanks + ld a,(hl) + cp ' ' + jp nz,comerr ;blanks? + inc hl + dec c + jp nz,conv1 + ld a,b ;recover value + ret + +movename: ;move 3 characters from h,l to d,e addresses + ld b,3 +move0: ld a,(hl) + ld (de),a + inc hl + inc de + dec b + jp nz,move0 + ret + +addhcf: ;buff + a + c to h,l followed by fetch + ld hl,buff + add a,c + call addh + ld a,(hl) + ret + +setdisk: ;change disks for this command, if requested + xor a + ld (comfcb),a ;clear disk name from fcb + ld a,(sdisk) + or a + ret z ;no action if not specified + dec a + ld hl,cdisk + cp (hl) + ret z ;already selected + jp select + +resetdisk: ;return to original disk after command + ld a,(sdisk) + or a + ret z ;no action if not selected + dec a + ld hl,cdisk + cp (hl) + ret z ;same disk + ld a,(cdisk) + jp select + + ;individual intrinsics follow +direct: ;directory search + call fillfcb0 ;comfcb gets file name + call setdisk ;change disk drives if requested + ld hl,comfcb+1 + ld a,(hl) ;may be empty request + cp ' ' + jp nz,dir1 ;skip fill of ??? if not blank + ;set comfcb to all ??? for current disk + ld b,11 ;length of fill ????????.??? +dir0: ld (hl),'?' + inc hl + dec b + jp nz,dir0 + ;not a blank request, must be in comfcb +dir1: ld e,0 + push de ;E counts directory entries + call searchcom ;first one has been found + call z,nofile ;not found message +dir2: jp z,endir + ;found, but may be system file + ld a,(dcnt) ;get the location of the element + rrca + rrca + rrca + and 1100000b + ld c,a + ;c contains base index into buff for dir entry + ld a,sysfile + call addhcf ;value to A + rla + jp c,dir6 ;skip if system file + ;c holds index into buffer + ;another fcb found, new line? + pop de + ld a,e + inc e + push de + ;e=0,1,2,3,...new line if mod 4 = 0 + and 11b + push af ;and save the test + jp nz,dirhdr0 ;header on current line + call crlf + push bc + call cselect + pop bc + ;current disk in A + add a,'A' + call printbc + ld a,':' + call printbc + jp dirhdr1 ;skip current line hdr +dirhdr0: + call blank ;after last one + ld a,':' + call printbc +dirhdr1: + call blank + ;compute position of name in buffer + ld b,1 ;start with first character of name +dir3: ld a,b + call addhcf ;buff+a+c fetched + and 7fh ;mask flags + ;may delete trailing blanks + cp ' ' + jp nz,dir4 ;check for blank type + pop af + push af ;may be 3rd item + cp 3 + jp nz,dirb ;place blank at end if not + ld a,9 + call addhcf ;first char of type + and 7fh + cp ' ' + jp z,dir5 + ;not a blank in the file type field +dirb: ld a,' ' ;restore trailing filename chr +dir4: + call printbc ;char printed + inc b + ld a,b + cp 12 + jp nc,dir5 + ;check for break between names + cp 9 + jp nz,dir3 ;for another char + ;print a blank between names + call blank + jp dir3 + +dir5: ;end of current entry + pop af ;discard the directory counter (mod 4) +dir6: call break$key ;check for interrupt at keyboard + jp nz,endir ;abort directory search + call searchn + jp dir2 ;for another entry +endir: ;end of directory scan + pop de ;discard directory counter + jp retcom + + +erase: call fillfcb0 ;cannot be all ???'s + cp 11 + jp nz,erasefile + ;erasing all of the disk + ld bc,ermsg + call print + call readcom + ld hl,comlen + dec (hl) + jp nz,ccp ;bad input + inc hl + ld a,(hl) + cp 'Y' + jp nz,ccp + ;ok, erase the entire diskette + inc hl + ld (comaddr),hl ;otherwise error at retcom +erasefile: + call setdisk + ld de,comfcb + call delete + inc a ;255 returned if not found + call z,nofile ;no file message if so + jp retcom + +ermsg: db 'ALL (Y/N)?',0 + +type: call fillfcb0 + jp nz,comerr ;don't allow ?'s in file name + call setdisk + call openc ;open the file + jp z,typerr ;zero flag indicates not found + ;file opened, read 'til eof + call crlf + ld hl,bptr + ld (hl),255 ;read first buffer +type0: ;loop on bptr + ld hl,bptr + ld a,(hl) + cp 128 ;end buffer + jp c,type1 + push hl ;carry if 0,1,...,127 + ;read another buffer full + call diskreadc + pop hl ;recover address of bptr + jp nz,typeof ;hard end of file + xor a + ld (hl),a ;bptr = 0 +type1: ;read character at bptr and print + inc (hl) ;bptr = bptr + 1 + ld hl,buff + call addh ;h,l addresses char + ld a,(hl) + cp eofile + jp z,retcom + call printchar + call break$key + jp nz,retcom ;abort if break + jp type0 ;for another character + +typeof: ;end of file, check for errors + dec a + jp z,retcom + call readerr +typerr: call resetdisk + jp comerr + +save: call getnumber ; value to register a + push af ;save it for later + ;should be followed by a file to save the memory image + call fillfcb0 + jp nz,comerr ;cannot be ambiguous + call setdisk ;may be a disk change + ld de,comfcb + push de + call delete ;existing file removed + pop de + call make ;create a new file on disk + jp z,saverr ;no directory space + xor a + ld (comrec),a ; clear next record field + pop af ;#pages to write is in a, change to #sectors + ld l,a + ld h,0 + add hl,hl + ld de,tran ;h,l is sector count, d,e is load address +save0: ;check for sector count zero + ld a,h + or l + jp z,save1 ;may be completed + dec hl ;sector count = sector count - 1 + push hl ;save it for next time around + ld hl,128 + add hl,de + push hl ;next dma address saved + call setdma ;current dma address set + ld de,comfcb + call diskwrite + pop de + pop hl ;dma address, sector count + jp nz,saverr ;may be disk full case + jp save0 ;for another sector + +save1: ;end of dump, close the file + ld de,comfcb + call close + inc a ; 255 becomes 00 if error + jp nz,retsave ;for another command +saverr: ;must be full or read only disk + ld bc,fullmsg + call print +retsave: ;reset dma buffer + call setdmabuff + jp retcom + +fullmsg: + db 'NO SPACE',0 + +rename: ;rename a file on a specific disk + call fillfcb0 + jp nz,comerr ;must be unambiguous + ld a,(sdisk) + push af ;save for later compare + call setdisk ;disk selected + call searchcom ;is new name already there? + jp nz,renerr3 + ;file doesn't exist, move to second half of fcb + ld hl,comfcb + ld de,comfcb+16 + ld b,16 + call move0 + ;check for = or left arrow + ld hl,(comaddr) + ex de,hl + call deblank + cp '=' + jp z,ren1 ;ok if = + cp la + jp nz,renerr2 +ren1: ex de,hl + inc hl + ld (comaddr),hl ;past delimiter + ;proper delimiter found + call fillfcb0 + jp nz,renerr2 + ;check for drive conflict + pop af + ld b,a ;previous drive number + ld hl,sdisk + ld a,(hl) + or a + jp z,ren2 + ;drive name was specified. same one? + cp b + ld (hl),b + jp nz,renerr2 +ren2: ld (hl),b ;store the name in case drives switched + xor a + ld (comfcb),a + call searchcom ;is old file there? + jp z,renerr1 + + ;everything is ok, rename the file + ld de,comfcb + call renam + jp retcom + +renerr1: ; no file on disk + call nofile + jp retcom +renerr2: ; ambigous reference/name conflict + call resetdisk + jp comerr +renerr3: ; file already exists + ld bc,renmsg + call print + jp retcom +renmsg: db 'FILE EXISTS',0 + +user: ;set user number + call getnumber ; leaves the value in the accumulator + cp 16 + jp nc,comerr ; must be between 0 and 15 + ld e,a ;save for setuser call + ld a,(comfcb+1) + cp ' ' + jp z,comerr + call setuser ;new user number set + jp endcom + +userfunc: + call serialize ;check serialization + ;load user function and set up for execution + ld a,(comfcb+1) + cp ' ' + jp nz,user0 + ;no file name, but may be disk switch + ld a,(sdisk) + or a + jp z,endcom ;no disk name if 0 + dec a + ld (cdisk),a + call setdiska ;set user/disk + call select + jp endcom +user0: ;file name is present + ld de,comfcb+9 + ld a,(de) + cp ' ' + jp nz,comerr ;type ' ' + push de + call setdisk + pop de + ld hl,comtype ;.com + call movename ;file type is set to .com + call openc + jp z,userer + ;file opened properly, read it into memory + ld hl,tran ;transient program base +load0: push hl ;save dma address + ex de,hl + call setdma + ld de,comfcb + call diskread + jp nz,load1 + ;sector loaded, set new dma address and compare + pop hl + ld de,128 + add hl,de + ld de,tranm ;has the load overflowed? + ld a,l + sub e + ld a,h + sbc a,d + jp nc,loaderr + jp load0 ;for another sector + +load1: pop hl + dec a + jp nz,loaderr ;end file is 1 + call resetdisk ;back to original disk + call fillfcb0 + ld hl,sdisk + push hl + ld a,(hl) + ld (comfcb),a ;drive number set + ld a,16 + call fillfcb ;move entire fcb to memory + pop hl + ld a,(hl) + ld (comfcb+16),a + xor a + ld (comrec),a ;record number set to zero + ld de,fcb + ld hl,comfcb + ld b,33 + call move0 + ;move command line to buff + ld hl,combuf +bmove0: ld a,(hl) + or a + jp z,bmove1 + cp ' ' + jp z,bmove1 + inc hl + jp bmove0 ;for another scan + ;first blank position found +bmove1: ld b,0 + ld de,buff+1 + ;ready for the move +bmove2: ld a,(hl) + ld (de),a + or a + jp z,bmove3 + ;more to move + inc b + inc hl + inc de + jp bmove2 +bmove3: ;b has character count + ld a,b + ld (buff),a + call crlf + ;now go to the loaded program + call setdmabuff ;default dma + call saveuser ;user code saved + ;low memory diska contains user code + call tran ;gone to the loaded program + ld sp,stack ;may come back here + call setdiska + call select + jp ccp + +userer: ;arrive here on command error + call resetdisk + jp comerr + +loaderr: ;cannot load the program + ld bc,loadmsg + call print + jp retcom +loadmsg: + db 'BAD LOAD',0 +comtype: + db 'COM' ;for com files + + +retcom: ;reset disk before end of command check + call resetdisk + +endcom: ;end of intrinsic command + call fillfcb0 ;to check for garbage at end of line + ld a,(comfcb+1) + sub ' ' + ld hl,sdisk + or (hl) + ;0 in accumulator if no disk selected, and blank fcb + jp nz,comerr + jp ccp + +; data areas + ds 16 ;8 level stack +stack: + +; 'submit' file control block +submit: db 0 ;00 if no submit file, ff if submitting +subfcb: db 0,'$$$ ' ;file name is $$$ + db 'SUB',0,0 ;file type is sub +submod: db 0 ;module number +subrc: ds 1 ;record count filed + ds 16 ;disk map +subcr: ds 1 ;current record to read + +; command file control block +comfcb: ds 32 ;fields filled in later +comrec: ds 1 ;current record to read/write +dcnt: ds 1 ;disk directory count (used for error codes) +cdisk: ds 1 ;current disk +sdisk: ds 1 ;selected disk for current operation + ;none=0, a=1, b=2 ... +bptr: ds 1 ;buffer pointer + + end ccploc diff --git a/doug/src/dwgh2b.c b/doug/src/dwgh2b.c new file mode 100755 index 00000000..53eb84c8 --- /dev/null +++ b/doug/src/dwgh2b.c @@ -0,0 +1,128 @@ +// --------------------------------------------------- +// hex2bin.c 21-May-11 Running on Mac OS X 10.6.6 +// S/n 2011-1042-654321 Written by Douglas W. Goodall +// Copyright(c)2011 Douglas W. Goodall, United States. +// --------------------------------------------------- +// This file is part of Vintage Modern Assembler Plus Tools. +// +// VMAPT is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// VMAPT is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with VMAPT. If not, see . +// + +#include +#include +#include + +#define DATA_RECORD 0x00 +#define EOF_RECORD 0x01 + +int main(int argc,char **argv) +{ + char g_szBuffer2[128]; + char szByteBuffer[2+1]; + char *p; + int i; + int iTemp; + + char cColon; + + char szLength[2+1]; + int iLength; + + char szAddress[4+1]; + unsigned int uiAddress; + + char szRecordType[2+1]; + unsigned char ucRecordType; + + char szData[80]; + unsigned char ucBinBuffer[32+1]; + + char szChecksum[2+1]; + unsigned char ucChecksum; + + unsigned int uiLastByte = 0; + + if(1 == argc) { + printf("usage - hex2bin \n"); + exit(EXIT_FAILURE); + } + + char szBinFile[255]; + char szHexFile[255]; + + strcpy(szHexFile,argv[1]); + strcpy(szBinFile,argv[1]); + + strcat(szBinFile,".bin"); + strcat(szHexFile,".hex"); + + unsigned char memory[0xfff0]; + memset(memory,0,sizeof(memory)); + + FILE * fhex = fopen(szHexFile,"r"); + if(NULL == fhex) { + printf("Sorry, cannot open %s for input\n",szHexFile); + exit(EXIT_FAILURE); + } + p = fgets(g_szBuffer2,sizeof(g_szBuffer2),fhex); + while(NULL != p) { + g_szBuffer2[strlen(g_szBuffer2)-1] = 0; + cColon = g_szBuffer2[0]; + + memset(szLength,0,sizeof(szLength)); + memcpy(szLength,&g_szBuffer2[1],2); + sscanf(szLength,"%02X",&iLength); + + memset(szAddress,0,sizeof(szAddress)); + memcpy(szAddress,&g_szBuffer2[3],4); + sscanf(szAddress,"%04X",&uiAddress); + + memset(szRecordType,0,sizeof(szRecordType)); + memcpy(szRecordType,&g_szBuffer2[7],2); + + sscanf(szRecordType,"%02X",&iTemp); + ucRecordType = (unsigned char)iTemp; + + if(0 == ucRecordType) { + memset(szData,0,sizeof(szData)); + memcpy(szData,&g_szBuffer2[9],iLength*2); + for(i=0;i +#include +#include + +#include "portab.h" +#ifndef __GNUC__ +#include "cpmbdos.h" +#include "cprintf.h" +#endif + +/* + * 1MB = 1,048,576 bytes + * 32MB = 1,048,576 * 32 = 33,554,432 + * + * physical sector is 512 bytes + * physical track is 256 sectors = 131,072 + * physical drive is 33,554,432 + * physical tracks are 33,554,432 / 131,072 = 256 + * physical tracks per physical drive are 256 + * + * logical sector is 128 bytes + * logical track is 256 sectors (aka ) + * logical drive is 8192KB (aka 8192KB/32KB = 256 logical tracks) + * + * + * 8,388,608 bytes is a logical drive + * 131,072 bytes is a physical track + * 8,388,608 / 131,072 = 64 physical tracks per logical drive + * + * One byte (0-255) will just hold the number of physical tracks needing + * to be shared amoung up to four logical drives. + * + * physical track 0 - partition sector and second-stage loader if needed + * physical tracks 1 - 64 = 8.0MB partition ( 64 * 131,072 = 8,388,608 ) + * physical tracks 65 - 128 = 8.0MB partition ( 64 * 131,072 = 8,388,608 ) + * physical tracks 129 - 192 = 8.0MB partition ( 64 * 131,072 = 8,388,608 ) + * physical tracks 193 - 255 = 7.9MB partition ( 63 * 131,072 = 8,257,536 ) + * + */ + +#define MAX_PARTS 4 +#define TRKS_PER_PHY_DRV 256 +#define TRKS_PER_LOG_DRV 64 /* 256 sectors * 512 = 128k */ + +#define SAFESTRING 80 /* make large enough to avoid accidental overrun */ + +#define U8 unsigned char + +struct PART_TABLE { /* in-memory instance of partition table */ + U8 start; /* starting track of a partition */ + U8 end; /* ending track of a partition */ +} pt[MAX_PARTS] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; + +U8 bRunning; /* scratchpad used used by the main loop */ +U8 end; /* scratchpad used to hold ending track of a part */ +U8 Index; /* scratchpad used as index for for loops */ +U8 NumParts; /* scratchpad to hold the current number of parts */ +U8 LastEnd; /* scratchpad to hold the last track allocated */ +U8 NewEnd; /* scratchpad to hold the proposed ending track */ +U8 NewMax; /* scratchpad to hold the proposed max part size */ +U8 NewSize; /* scratchpad to hold the decided new part size */ +U8 NewStart; /* scratchpad to hold the decided starting track */ +U8 start; /* scratchpad to hold the starting track of a part */ +U8 Avail; /* scratchpad to hold the remaining avialable tracks */ + +char szChoice[SAFESTRING]; /* string used to receive keystrokes */ +char szTemp[SAFESTRING]; /* string used for general purposes */ + +/* THESE ARE USED BY THE LIBRARY ROUTINES */ +#ifndef __GNUC__ +char getchar(void) +{ + struct BDOSCALL cread = { C_READ, { (unsigned int)0 } }; + return cpmbdos(&cread); +} +void outchar(char c) +{ + struct BDOSCALL cwrite = { C_WRITE, { (unsigned int)c } }; + cpmbdos(&cwrite); +} +#endif + +void display_menu(void) +{ + if(NumParts < MAX_PARTS) { + if(0 < Avail) { + printf("a - add partition #%d\n",NumParts+1); + } + } + if(0 < NumParts) { + printf("d - delete partition #%d\n",NumParts); + } + if(1 < NumParts) { + printf("D - delete all partitions, 1 - %d\n",NumParts); + } + if(0 == NumParts) { + printf("A - create all 8MB partitions\n"); + } + printf("q - quit fdisk\n\n"); +} + +char query(char *str) +{ + printf("%s",str); + gets(szTemp); + if('Y' == szTemp[0]) { + return TRUE; + } else { + return FALSE; + } +} + +void delete(void) +{ + if(0 < NumParts) { + if(TRUE == query("Delete partition(Y/n)?")) { + pt[NumParts-1].start = 0; + pt[NumParts-1].end = 0; + } + } +} + +void deleteall(void) +{ + if(0 < NumParts) { + if(TRUE == query("Delete all partitions(Y/n)?")) { + for(Index=0;Index'+$80 + .WORD W_0BRANCH +C_LLOOP: + .WORD 2+$ ; Vector to code + LD DE,0001 +C_ILOOP: + LD HL,(RPP) ; Get return stack pointer + LD A,(HL) ; Add DE to value on return stack + ADD A,E ; + LD (HL),A ; + LD E,A ; + INC HL ; + LD A,(HL) ; + ADC A,D ; + LD (HL),A ; + INC HL ; HL now points to limit value + INC D ; Get Ds sign bit + DEC D ; + LD D,A ; Result now in DE + JP M,DECR_LOOP ; Decrement loop so check > limit + ; otherwies check < limit + LD A,E ; Low byte back + SUB (HL) ; Subtract limit low + LD A,D ; High byte back + INC HL ; Point to limit high + SBC A,(HL) ; Subtract it + JR TEST_LIMIT ; +DECR_LOOP: + LD A,(HL) ; Get limit low + SUB E ; Subtract index low + INC HL ; Point to limit high + LD A,(HL) ; Get it + SBC A,D ; Subtract index high +TEST_LIMIT: + JP M,X_BRANCH ; Not reached limit so jump + INC HL ; Drop index & limit from return stack + LD (RPP),HL ; Save stack pointer + INC BC ; Skip branch offset + INC BC ; + JP NEXT + +W_PLOOP: ; Loop + stack & branch if not done + .BYTE $87,"<+LOOP",'>'+$80 + .WORD W_LLOOP +C_PLOOP: + .WORD 2+$ ; Vector to code + POP DE ; Get value from stack + JR C_ILOOP ; Go do loop increment + +W_LDO: ; Put start & end loop values on RPP + .BYTE $84,"'+$80 + .WORD W_PLOOP +C_LDO: + .WORD 2+$ + LD HL,(RPP) ; Get return stack pointer + DEC HL ; Add space for two values + DEC HL ; + DEC HL ; + DEC HL ; + LD (RPP),HL ; Save new stack pointer + POP DE ; Get start value & + LD (HL),E ; put on return stack top + INC HL ; + LD (HL),D ; + INC HL ; + POP DE ; Get end value & + LD (HL),E ; put on return stack - 1 + INC HL ; + LD (HL),D ; + JP NEXT + +W_I: ; Copy LOOP index to data stack + .BYTE $81,'I'+$80 + .WORD W_LDO +C_I: + .WORD 2+$ +X_I: + LD HL,(RPP) ; Get return stack pointer +X_I2: + LD E,(HL) ; Get LOOP index off return stack + INC HL ; + LD D,(HL) ; + PUSH DE ; Push onto data stack + JP NEXT + +W_DIGIT: ; Convert digit n2 using base n1 + .BYTE $85,"DIGI",'T'+$80 + .WORD W_I +C_DIGIT: + .WORD 2+$ + POP HL ; Get base to use + POP DE ; Get char + LD A,E ; A = char + SUB $30 ; Subtract 30h + JP M,NDIGIT + CP $0A ; Greater than 9 ? + JP M,LESS10 ; If not then skip + SUB $07 ; Convert 'A' to 10 + CP $0A ; Is it 10? + JP M,NDIGIT ; If not an error occured +LESS10: + CP L ; L is 1 digit limit + JP P,NDIGIT ; Out of range for digit + LD E,A ; Result into DE + LD HL,0001 ; Leave TRUE flag + JP NEXTS2 ; Save both & NEXT +NDIGIT: + LD L,H ; Leave FALSE flag + JP NEXTS1 ; Save & NEXT + +W_FIND: ; Find word & return vector,byte & flag + .BYTE $86,"'+$80 + .WORD W_DIGIT +C_FIND: + .WORD 2+$ ; Vector to code + POP DE ; Get pointer to next vocabulary word +COMPARE: + POP HL ; Copy pointer to word we're looking 4 + PUSH HL ; + LD A,(DE) ; Get 1st vocabulary word letter + XOR (HL) ; Compare with what we've got + AND $3F ; Ignore start flag + JR NZ,NOT_END_CHR ; No match so skip to next word +MATCH_NO_END: + INC HL ; Compare next chr + INC DE ; + LD A,(DE) ; + XOR (HL) ; + ADD A,A ; Move bit 7 to C flag + JR NZ,NO_MATCH ; No match jump + JR NC,MATCH_NO_END ; Match & not last, so next chr + LD HL,0005 ; Offset to start of code + ADD HL,DE ; HL now points to code start for word + EX (SP),HL ; Swap with value on stack +NOT_WORD_BYTE: + DEC DE ; Search back for word type byte + LD A,(DE) ; + OR A ; + JP P,NOT_WORD_BYTE ; Not yet so loop + LD E,A ; Byte into DE + LD D,$00 ; + LD HL,0001 ; Leave TRUE flag + JP NEXTS2 ; Save both & NEXT +NO_MATCH: + JR C,END_CHR ; If last chr then jump +NOT_END_CHR: + INC DE ; Next chr of this vocab word + LD A,(DE) ; Get it + OR A ; Set flags + JP P,NOT_END_CHR ; Loop if not end chr +END_CHR: + INC DE ; Now points to next word vector + EX DE,HL ; Swap + LD E,(HL) ; Vector into DE + INC HL ; + LD D,(HL) ; + LD A,D ; Check it's not last (first) word + OR E ; + JR NZ,COMPARE ; No error so loop + POP HL ; Dump pointer + LD HL,0000 ; Flag error + JP NEXTS1 ; Save & NEXT + +W_ENCLOSE: + .BYTE $87,"ENCLOS",'E'+$80 + .WORD W_FIND +C_ENCLOSE: + .WORD 2+$ ; Vector to code + POP DE ; get delimiter character + POP HL ; get address 1 + PUSH HL ; duplicate it + LD A,E ; delimiter char into A + LD D,A ; copy to D + LD E,$ff ;-1 for offset + DEC HL ; to allow for first INCR +J21E6: + INC HL ; point to next chr + INC E ; next offset + CP (HL) ; compare chr with (address) + JR Z,J21E6 ; loop if = delimiter chr + LD A,$0D ; else set CR + CP (HL) ; compare with (address) + LD A,D ; restore delimiter chr + JR Z,J21E6 ; loop if it was = CR + LD D,$00 ; zero high byte + PUSH DE ; save offset + LD D,A ; restore delimiter chr + LD A,(HL) ; get byte from address + AND A ; set the flags + JR NZ,J2202 ; branch if not null + LD D,$00 ; clear high byte + INC E ; point to next addr + PUSH DE ; save address + DEC E ; point to end + PUSH DE ; push address + JP NEXT ; done +J2202: + LD A,D ; restore delimiter chr + INC HL ; increment address + INC E ; increment offset + CP (HL) ; compare delimiter with (address) + JR Z,J2218 ; jump if = + LD A,$0D ; else get CR + CP (HL) ; compare with (address) + JR Z,J2218 ; jump if = + LD A,(HL) ; else get byte + AND A ; set the flags + JR NZ,J2202 ; loop if not null + LD D,$00 ; clear gigh byte + PUSH DE ; save address + PUSH DE ; save address + JP NEXT ; done +J2218: + LD D,$00 ; clear high byte + PUSH DE ; save address + INC E ; increment offset + PUSH DE ; save address + JP NEXT ; done + +W_EMIT: ; Output CHR from stack + .BYTE $84,"EMI",'T'+$80 + .WORD W_ENCLOSE +C_EMIT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UEMIT ; Put UEMIT addr on stack + .WORD C_FETCH ; Get UEMIT code field address + .WORD C_EXECUTE ; Jump to address on stack + .WORD C_1 + .WORD C_OUT + .WORD C_PLUSSTORE + .WORD C_STOP ; Pop BC from return stack (=next) + +W_KEY: ; Wait for key, value on stack + .BYTE $83,"KE",'Y'+$80 + .WORD W_EMIT +C_KEY: + .WORD 2+$ ; Vector to code + LD HL,(UKEY) ; Get the vector + JP (HL) ; Jump to it + +; .WORD E_COLON ; Interpret following word sequence +; .WORD C_UKEY ; Put UKEY addr on stack +; .WORD C_FETCH ; Get CF_KEY +; .WORD C_EXECUTE ; Jump to CF_KEY +; .WORD C_STOP ; Pop BC from return stack (=next) + + +W_TERMINAL: + .BYTE $89,"?TERMINA",'L'+$80 + .WORD W_KEY +C_TERMINAL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UTERMINAL + .WORD C_FETCH ; Get word from addr on stack + .WORD C_EXECUTE ; Jump to address on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CR: ; Output [CR][LF] + .BYTE $82,"C",'R'+$80 + .WORD W_TERMINAL +C_CR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UCR ; Push UCR addr + .WORD C_FETCH ; Get UCR code field addr + .WORD C_EXECUTE ; Jump to address on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CLS: ; Clear screen + .BYTE $83,"CL",'S'+$80 + .WORD W_CR +C_CLS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Put clear screen code on stack + .WORD 000Ch ; + .WORD C_EMIT ; Output it + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CMOVE: ; Move block + .BYTE $85,"CMOV",'E'+$80 + .WORD W_CLS +C_CMOVE: + .WORD 2+$ ; Vector to code + LD L,C ; Save BC for now + LD H,B ; + POP BC ; Get no. of bytes to move + POP DE ; Get destination address + EX (SP),HL ; Get source address + LD A,B ; Check it's not a 0 length block + OR C ; + JR Z,NO_BYTES ; If 0 length then do nothing + LDIR ; Move block +NO_BYTES: + POP BC ; Get BC back + JP NEXT + +W_USTAR: ; Unsigned multiply + .BYTE $82,"U",'*'+$80 + .WORD W_CMOVE +C_USTAR: + .WORD 2+$ ; Vector to code + POP DE ; get n2 + POP HL ; get n1 + PUSH BC ; save BC for now + LD C,H ; save H + LD A,L ; low byte to multiply by + CALL HALF_TIMES ; HL = A * DE + PUSH HL ; save partial result + LD H,A ; clear H + LD A,C ; high byte to multiply by + LD C,H ; clear B + CALL HALF_TIMES ; HL = A * DE + POP DE ; get last partial result + LD B,C ; add partial results + LD C,D ; add partial results + ADD HL,BC ; + ADC A,$00 ; + LD D,L ; + LD L,H ; + LD H,A ; + POP BC ; get BC back + JP NEXTS2 ; save 32 bit result & NEXT + +HALF_TIMES: ; + LD HL,$0000 ; clear partial result + LD B,08h ; eight bits to do +NEXT_BIT: + ADD HL,HL ; result * 2 + RLA ; multiply bit into C + JR NC,NO_MUL ; branch if no multiply + ADD HL,DE ; add multiplicand + ADC A,$00 ; add in any carry +NO_MUL: + DJNZ NEXT_BIT ; decr and loop if not done + RET ; + +W_UMOD: ; Unsigned divide & MOD + .BYTE $85,"U/MO",'D'+$80 + .WORD W_USTAR +C_UMOD: + .WORD 2+$ ; Vector to code + LD HL,0004 + ADD HL,SP + LD E,(HL) + LD (HL),C + INC HL + LD D,(HL) + LD (HL),B + POP BC + POP HL + LD A,L + SUB C + LD A,H + SBC A,B + JR C,J22DB + LD HL,$FFFF + LD DE,$FFFF + JR J2301 +J22DB: + LD A,10h +J22DD: + ADD HL,HL + RLA + EX DE,HL + ADD HL,HL + JR NC,J22E5 + INC DE + AND A +J22E5: + EX DE,HL + RRA + PUSH AF + JR NC,J22F2 + LD A,L + SUB C + LD L,A + LD A,H + SBC A,B + LD H,A + JR J22FC +J22F2: + LD A,L + SUB C + LD L,A + LD A,H + SBC A,B + LD H,A + JR NC,J22FC + ADD HL,BC + DEC DE +J22FC: + INC DE + POP AF + DEC A + JR NZ,J22DD +J2301: + POP BC + PUSH HL + PUSH DE + JP NEXT + +W_AND: ; AND + .BYTE $83,"AN",'D'+$80 + .WORD W_UMOD +C_AND: + .WORD 2+$ ; Vector to code + POP DE ; Get n1 off stack + POP HL ; Get n2 off stack + LD A,E ; AND lo bytes + AND L ; + LD L,A ; Result in L + LD A,D ; AND hi bytes + AND H ; + LD H,A ; Result in H + JP NEXTS1 ; Save & next + +W_OR: ; OR + .BYTE $82,"O",'R'+$80 + .WORD W_AND +C_OR: + .WORD 2+$ ; Vector to code + POP DE ; Get n1 off stack + POP HL ; Get n2 off stack + LD A,E ; OR lo bytes + OR L ; + LD L,A ; Result in L + LD A,D ; OR hi bytes + OR H ; + LD H,A ; Result in H + JP NEXTS1 ; Save & next + +W_XOR: ; XOR + .BYTE $83,"XO",'R'+$80 + .WORD W_OR +C_XOR: + .WORD 2+$ ; Vector to code + POP DE ; Get n1 off stack + POP HL ; Get n2 off stack + LD A,E ; XOR lo bytes + XOR L ; + LD L,A ; Result in L + LD A,D ; XOR hi bytes + XOR H ; + LD H,A ; Result in H + JP NEXTS1 ; Save & NEXT + +W_SPFETCH: ; Stack pointer onto stack + .BYTE $83,"SP",'@'+$80 + .WORD W_XOR +C_SPFETCH: + .WORD 2+$ ; Vector to code + LD HL,0000 ; No offset + ADD HL,SP ; Add SP to HL + JP NEXTS1 ; Save & NEXT + +W_SPSTORE: ; Set initial stack pointer value + .BYTE $83,"SP",'!'+$80 + .WORD W_SPFETCH +C_SPSTORE: + .WORD 2+$ ; Vector to code + LD HL,(DEF_SYSADDR) ; Get system base addr + LD DE,S0-SYSTEM ; Offset to stack pointer value (0006) + ADD HL,DE ; Add to base addr + LD E,(HL) ; Get SP from ram + INC HL ; + LD D,(HL) ; + EX DE,HL ; Put into HL + LD SP,HL ; Set SP + JP NEXT + +W_RPFETCH: ; Get return stack pointer + .BYTE $83,"RP",'@'+$80 + .WORD W_SPSTORE +C_RPFETCH: + .WORD 2+$ ; Vector to code + LD HL,(RPP) ; Return stack pointer into HL + JP NEXTS1 ; Save & NEXT + +W_RPSTORE: ; Set initial return stack pointer + .BYTE $83,"RP",'!'+$80 + .WORD W_RPFETCH +C_RPSTORE: + .WORD 2+$ ; Vector to code + LD HL,(DEF_SYSADDR) ; Get system base addr + LD DE,0008 ; Offset to return stack pointer value + ADD HL,DE ; Add to base addr + LD E,(HL) ; Get SP from ram + INC HL ; + LD D,(HL) ; + EX DE,HL ; Put into HL + LD (RPP),HL ; Set return SP + JP NEXT + +W_STOP: ; Pop BC from return stack (=next) + .BYTE $82,"; ",'S'+$80 + .WORD W_RPSTORE +C_STOP: + .WORD 2+$ ; Vector to code +X_STOP: + LD HL,(RPP) ; Return stack pointer to HL + LD C,(HL) ; Get low byte + INC HL ; + LD B,(HL) ; Get high byte + INC HL ; + LD (RPP),HL ; Save stack pointer + JP NEXT + +W_LEAVE: ; Quit loop by making index = limit + .BYTE $85,"LEAV",'E'+$80 + .WORD W_STOP +C_LEAVE: + .WORD 2+$ ; Vector to code + LD HL,(RPP) ; Get return stack pointer + LD E,(HL) ; Get loop limit low + INC HL ; + LD D,(HL) ; Get loop limit high + INC HL ; + LD (HL),E ; Set index low to loop limit + INC HL ; + LD (HL),D ; Set index high to loop limit + JP NEXT + +W_MOVER: ; Move from data to return stack + .BYTE $82,">",'R'+$80 + .WORD W_LEAVE +C_MOVER: + .WORD 2+$ ; Vector to code + POP DE ; Get value + LD HL,(RPP) ; Get return stack pointer + DEC HL ; Set new value + DEC HL ; + LD (RPP),HL ; Save it + LD (HL),E ; Push low byte onto return stack + INC HL ; + LD (HL),D ; Push high byte onto return stack + JP NEXT + +W_RMOVE: ; Move word from return to data stack + .BYTE $82,"R",'>'+$80 + .WORD W_MOVER +C_RMOVE: + .WORD 2+$ ; Vector to code + LD HL,(RPP) ; Get return stack pointer + LD E,(HL) ; Pop word off return stack + INC HL ; + LD D,(HL) ; + INC HL ; + LD (RPP),HL ; Save new return stack pointer + PUSH DE ; Push on data stack + JP NEXT + +W_RFETCH: ; Return stack top to data stack + .BYTE $82,"R",'@'+$80 + .WORD W_RMOVE +C_RFETCH: + .WORD X_I ; Return stack top to data stack + + +W_0EQUALS: ; =0 + .BYTE $82,"0",'='+$80 + .WORD W_RFETCH +C_0EQUALS: + .WORD 2+$ ; Vector to code +X_0EQUALS: + POP HL ; Get value from stack + LD A,L ; set flags + OR H ; + LD HL,0000 ; Not = 0 flag + JR NZ,NO_ZERO ; + INC HL ; = 0 flag +NO_ZERO: + JP NEXTS1 ; Save & NEXT + +W_NOT: ; Convert flag, same as 0= + .BYTE $83,"NO",'T'+$80 + .WORD W_0EQUALS +C_NOT: + .WORD X_0EQUALS + +W_0LESS: ; Less than 0 + .BYTE $82,"0",'<'+$80 + .WORD W_NOT +C_0LESS: + .WORD 2+$ ; Vector to code + POP HL ; Get value + ADD HL,HL ; S bit into C + LD HL,0000 ; Wasn't < 0 flag + JR NC,NOT_LT0 ; + INC HL ; Was < 0 flag +NOT_LT0: JP NEXTS1 ; Save & NEXT + +W_PLUS: ; n1 + n2 + .BYTE $81,'+'+$80 + .WORD W_0LESS +C_PLUS: + .WORD 2+$ ; Vector to code + POP DE ; Get n2 + POP HL ; Get n1 + ADD HL,DE ; Add them + JP NEXTS1 ; Save & NEXT + +W_DPLUS: ; 32 bit add + .BYTE $82,"D",'+'+$80 + .WORD W_PLUS +C_DPLUS: + .WORD 2+$ ; Vector to code + LD HL,0006 ; offset to low word + ADD HL,SP ; add stack pointer + LD E,(HL) ; get d1 low word low byte + LD (HL),C ; save BC low byte + INC HL ; point to high byte + LD D,(HL) ; get d1 low word high byte + LD (HL),B ; save BC high byte + POP BC ; get high word d2 + POP HL ; get low word d2 + ADD HL,DE ; add low words + EX DE,HL ; save result low word in DE + POP HL ; get d1 high word + LD A,L ; copy d1 high word low byte + ADC A,C ; add d2 high word low byte + ; + carry from low word add + LD L,A ; result from high word low byte into L + LD A,H ; copy d1 high word low byte + ADC A,B ; add d2 high word low byte + ; + carry from high word low byte add + LD H,A ; result from high word high byte into H + POP BC ; restore BC + JP NEXTS2 ; Save 32 bit result & NEXT + +W_NEGATE: ; Form 2s complement of n + .BYTE $86,"NEGAT",'E'+$80 + .WORD W_DPLUS +C_NEGATE: + .WORD 2+$ ; Vector to code + POP HL ; Get number + LD A,L ; Low byte into A + CPL ; Complement it + LD L,A ; Back into L + LD A,H ; High byte into A + CPL ; Complement it + LD H,A ; Back into H + INC HL ; +1 + JP NEXTS1 ; Save & NEXT + +W_DNEGATE: ; Form 2s complement of 32 bit n + .BYTE $87,"DNEGAT",'E'+$80 + .WORD W_NEGATE +C_DNEGATE: + .WORD 2+$ ; Vector to code + POP HL ; get high word + POP DE ; get low word + SUB A ; clear A + SUB E ; negate low word low byte + LD E,A ; copy back to E + LD A,$00 ; clear A + SBC A,D ; negate low word high byte + LD D,A ; copy back to D + LD A,$00 ; clear A + SBC A,L ; negate high word low byte + LD L,A ; copy back to L + LD A,$00 ; clear A + SBC A,H ; negate high word high byte + LD H,A ; copy back to H + JP NEXTS2 ; Save 32 bit result & NEXT + +W_OVER: ; Copy 2nd down to top of stack + .BYTE $84,"OVE",'R'+$80 + .WORD W_DNEGATE +C_OVER: + .WORD 2+$ ; Vector to code + POP DE ; Get top + POP HL ; Get next + PUSH HL ; Save it back + JP NEXTS2 ; Save both & NEXT + +W_DROP: ; Drop top value from stack + .BYTE $84,"DRO",'P'+$80 + .WORD W_OVER +C_DROP: + .WORD 2+$ ; Vector to code + POP HL ; Get top value + JP NEXT + +W_2DROP: ; Drop top two values from stack + .BYTE $85,"2DRO",'P'+$80 + .WORD W_DROP +C_2DROP: + .WORD 2+$ ; Vector to code + POP HL ; Get top value + POP HL ; Get top value + JP NEXT + +W_SWAP: ; Swap top 2 values on stack + .BYTE $84,"SWA",'P'+$80 + .WORD W_2DROP +C_SWAP: + .WORD 2+$ ; Vector to code + POP HL ; Get top value + EX (SP),HL ; Exchanhe with next down + JP NEXTS1 ; Save & NEXT + +W_DUP: ; Duplicate top value on stack + .BYTE $83,"DU",'P'+$80 + .WORD W_SWAP +C_DUP: + .WORD 2+$ ; Vector to code + POP HL ; Get value off stack + PUSH HL ; Copy it back + JP NEXTS1 ; Save & NEXT + +W_2DUP: ; Dup top 2 values on stack + .BYTE $84,"2DU",'P'+$80 + .WORD W_DUP +C_2DUP: + .WORD 2+$ ; Vector to code + POP HL ; Get top two values from stack + POP DE ; + PUSH DE ; Copy them back + PUSH HL ; + JP NEXTS2 ; Save both & NEXT + +W_BOUNDS: ; Convert address & n to start & end + .BYTE $86,"BOUND",'S'+$80 + .WORD W_2DUP +C_BOUNDS: + .WORD 2+$ ; Vector to code + POP HL ; get n + POP DE ; get addr + ADD HL,DE ; add addr to n + EX DE,HL ; swap them + JP NEXTS2 ; save both & NEXT + +W_PLUSSTORE: ; Add n1 to addr + .BYTE $82,"+",'!'+$80 + .WORD W_BOUNDS +C_PLUSSTORE: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + POP DE ; Get DE + LD A,(HL) ; Add low bytes + ADD A,E ; + LD (HL),A ; Store result + INC HL ; Point to high byte + LD A,(HL) ; Add high bytes + ADC A,D ; + LD (HL),A ; Store result + JP NEXT + +W_TOGGLE: ; XOR (addr) with byte + .BYTE $86,"TOGGL",'E'+$80 + .WORD W_PLUSSTORE +C_TOGGLE: + .WORD 2+$ ; Vector to code + POP DE ; Get byte + POP HL ; Get addr + LD A,(HL) ; Get byte from addr + XOR E ; Toggle it + LD (HL),A ; Save result + JP NEXT + +W_FETCH: ; Get word from addr on stack + .BYTE $81,'@'+$80 + .WORD W_TOGGLE +C_FETCH: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + LD E,(HL) ; Get low byte + INC HL ; + LD D,(HL) ; Get high byte + PUSH DE ; Save it + JP NEXT + +W_CFETCH: ; Get byte from addr on stack + .BYTE $82,"C",'@'+$80 + .WORD W_FETCH +C_CFETCH: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + LD L,(HL) ; Get byte + LD H,$00 ; Top byte = 0 + JP NEXTS1 ; Save & NEXT + +W_2FETCH: ; Get word from addr+2 and addr + .BYTE $82,"2",'@'+$80 + .WORD W_CFETCH +C_2FETCH: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + LD DE,0002 ; Plus 2 bytes + ADD HL,DE ; Get 2nd word first + LD E,(HL) ; Low byte + INC HL ; + LD D,(HL) ; High byte + PUSH DE ; Save it + LD DE,$FFFD ; Minus 2 bytes + ADD HL,DE ; Get 1st word + LD E,(HL) ; Low byte + INC HL ; + LD D,(HL) ; High byte + PUSH DE ; Save it + JP NEXT + +W_STORE: ; Store word at addr + .BYTE $81,'!'+$80 + .WORD W_2FETCH +C_STORE: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + POP DE ; Get word + LD (HL),E ; Store low byte + INC HL ; + LD (HL),D ; Store high byte + JP NEXT + +W_CSTORE: ; Store byte at addr + .BYTE $82,"C",'!'+$80 + .WORD W_STORE +C_CSTORE: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + POP DE ; Get byte + LD (HL),E ; Save it + JP NEXT + +W_2STORE: ; Store 2 words at addr (+2) + .BYTE $82,"2",'!'+$80 + .WORD W_CSTORE +C_2STORE: + .WORD 2+$ ; Vector to code + POP HL ; Get addr + POP DE ; Get word + LD (HL),E ; Save low byte + INC HL ; + LD (HL),D ; Save high byte + INC HL ; + POP DE ; Get next word + LD (HL),E ; Save low byte + INC HL ; + LD (HL),D ; Save high byte + JP NEXT + +W_COLON: + .BYTE $81,':'+$80 + .WORD W_2STORE +C_COLON: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QEXEC ; Error not if not in execute mode + .WORD C_CSPSTORE ; Set current stack pointer value + .WORD C_CURRENT ; Get CURRENT addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CONTEXT ; Make CONTEXT current vocab + .WORD C_STORE ; Store word at addr + .WORD C_XXX1 ; Puts name into dictionary + .WORD C_RIGHTBRKT ; Set STATE to compile + .WORD C_CCODE ; Execute following machine code + +E_COLON: + LD HL,(RPP) ; Get return stack pointer + DEC HL ; Put BC on return stack + LD (HL),B ; + DEC HL ; + LD (HL),C ; + LD (RPP),HL ; Save new pointer + INC DE + LD C,E + LD B,D + JP NEXT + +W_SEMICOLON: ; Terminate compilation + .BYTE $C1,'; '+$80 + .WORD W_COLON +C_SEMICOLON: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QCOMP ; Check we're allready compiling + .WORD C_WHATSTACK ; Check stack pointer, error if not ok + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_STOP ; + .WORD C_SMUDGE ; Smudge bit to O.K. + .WORD C_LEFTBRKT ; Set STATE to execute + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CONSTANT: + .BYTE $88,"CONSTAN",'T'+$80 + .WORD W_SEMICOLON +C_CONSTANT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_XXX1 + .WORD C_SMUDGE + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_CCODE ; Execute following machine code + +X_CONSTANT: ; Put next word on stack + INC DE ; Adjust pointer + EX DE,HL ; Get next word + LD E,(HL) ; + INC HL ; + LD D,(HL) ; + PUSH DE ; Put on stack + JP NEXT + +W_VARIABLE: + .BYTE $88,"VARIABL",'E'+$80 + .WORD W_CONSTANT +C_VARIABLE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_CONSTANT + .WORD C_CCODE ; Execute following machine code + +X_VARIABLE: + INC DE + PUSH DE + JP NEXT + +W_USER: + .BYTE $84,"USE",'R'+$80 + .WORD W_VARIABLE +C_USER: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CONSTANT + .WORD C_CCODE ; Execute following machine code + +X_USER: + INC DE ; Adjust to next word + EX DE,HL + LD E,(HL) + INC HL + LD D,(HL) + LD HL,(DEF_SYSADDR) + ADD HL,DE + JP NEXTS1 ; Save & NEXT + +W_ZERO: ; Put zero on stack + .BYTE $81,'0'+$80 + .WORD W_USER +C_ZERO: + .WORD X_CONSTANT ; Put next word on stack + .WORD $0000 + +W_1: ; Put 1 on stack + .BYTE $81,'1'+$80 + .WORD W_ZERO +C_1: + .WORD X_CONSTANT ; Put next word on stack + .WORD 0001h + +W_2: + .BYTE $81,'2'+$80 + .WORD W_1 +C_2: + .WORD X_CONSTANT ; Put next word on stack + .WORD 0002h + +W_3: + .BYTE $81,'3'+$80 + .WORD W_2 +C_3: + .WORD X_CONSTANT ; Put next word on stack + .WORD 0003h + +W_BL: ; Leaves ASCII for blank on stack + .BYTE $82,"B",'L'+$80 + .WORD W_3 +C_BL: + .WORD X_CONSTANT ; Put next word on stack + .WORD 0020h + +W_CL: + .BYTE $83,"C/",'L'+$80 + .WORD W_BL +C_CL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UCL + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_FIRST: + .BYTE $85,"FIRS",'T'+$80 + .WORD W_CL +C_FIRST: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UFIRST ; Put UFIRST addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LIMIT: + .BYTE $85,"LIMI",'T'+$80 + .WORD W_FIRST +C_LIMIT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ULIMIT ; Put ULIMIT on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BBUF: + .BYTE $85,"B/BU",'F'+$80 + .WORD W_LIMIT +C_BBUF: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UBBUF + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BSCR: + .BYTE $85,"B/SC",'R'+$80 + .WORD W_BBUF +C_BSCR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UBSCR ; Number of buffers per block + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_S0: ; Push S0 (initial data stack pointer) + .BYTE $82,"S",'0'+$80 + .WORD W_BSCR +C_S0: + .WORD X_USER ; Put next word on stack then do next + .WORD S0-SYSTEM + +W_R0: + .BYTE $82,"R",'0'+$80 + .WORD W_S0 +C_R0: + .WORD X_USER ; Put next word on stack then do next + .WORD R0-SYSTEM + +W_TIB: + .BYTE $83,"TI",'B'+$80 + .WORD W_R0 +C_TIB: + .WORD X_USER ; Put next word on stack then do next + .WORD TIB-SYSTEM + +W_WIDTH: + .BYTE $85,"WIDT",'H'+$80 + .WORD W_TIB +C_WIDTH: + .WORD X_USER ; Put next word on stack then do next + .WORD WIDTH-SYSTEM + +W_WARNING: ; Put WARNING addr on stack + .BYTE $87,"WARNIN",'G'+$80 + .WORD W_WIDTH +C_WARNING: + .WORD X_USER ; Put next word on stack then do next + .WORD WARNING-SYSTEM + +W_FENCE: + .BYTE $85,"FENC",'E'+$80 + .WORD W_WARNING +C_FENCE: + .WORD X_USER ; Put next word on stack then do next + .WORD FENCE-SYSTEM + +W_DP: ; Dictionary pointer addr on stack + .BYTE $82,"D",'P'+$80 + .WORD W_FENCE +C_DP: + .WORD X_USER ; Put next word on stack then do next + .WORD DP-SYSTEM + +W_VOC_LINK: + .BYTE $88,"VOC-LIN",'K'+$80 + .WORD W_DP +C_VOC_LINK: + .WORD X_USER ; Put next word on stack then do next + .WORD VOC_LINK-SYSTEM + +W_BLK: + .BYTE $83,"BL",'K'+$80 + .WORD W_VOC_LINK +C_BLK: + .WORD X_USER ; Put next word on stack then do next + .WORD BLK-SYSTEM + +W_TOIN: + .BYTE $83,">I",'N'+$80 + .WORD W_BLK +C_TOIN: + .WORD X_USER ; Put next word on stack then do next + .WORD TOIN-SYSTEM + +W_OUT: ; Put OUT buffer count addr on stack + .BYTE $83,"OU",'T'+$80 + .WORD W_TOIN +C_OUT: + .WORD X_USER ; Put next word on stack then do next + .WORD OUT-SYSTEM + +W_SCR: + .BYTE $83,"SC",'R'+$80 + .WORD W_OUT +C_SCR: + .WORD X_USER ; Put next word on stack then do next + .WORD SCR-SYSTEM + +W_OFFSET: ; Put disk block offset on stack + .BYTE $86,"OFFSE",'T'+$80 + .WORD W_SCR +C_OFFSET: + .WORD X_USER ; Put next word on stack then do next + .WORD OFFSET-SYSTEM + +W_CONTEXT: + .BYTE $87,"CONTEX",'T'+$80 + .WORD W_OFFSET +C_CONTEXT: + .WORD X_USER ; Put next word on stack then do next + .WORD CONTEXT-SYSTEM + +W_CURRENT: + .BYTE $87,"CURREN",'T'+$80 + .WORD W_CONTEXT +C_CURRENT: + .WORD X_USER ; Put next word on stack then do next + .WORD CURRENT-SYSTEM + +W_STATE: ; Push STATE addr + .BYTE $85,"STAT",'E'+$80 + .WORD W_CURRENT +C_STATE: + .WORD X_USER ; Put next word on stack then do next + .WORD STATE-SYSTEM + +W_BASE: ; Put BASE addr on stack + .BYTE $84,"BAS",'E'+$80 + .WORD W_STATE +C_BASE: + .WORD X_USER ; Put next word on stack then do next + .WORD BASE-SYSTEM + +W_DPL: + .BYTE $83,"DP",'L'+$80 + .WORD W_BASE +C_DPL: + .WORD X_USER ; Put next word on stack then do next + .WORD DPL-SYSTEM + +W_FLD: + .BYTE $83,"FL",'D'+$80 + .WORD W_DPL +C_FLD: + .WORD X_USER ; Put next word on stack then do next + .WORD FLD-SYSTEM + +W_CSP: ; Push check stack pointer addr + .BYTE $83,"CS",'P'+$80 + .WORD W_FLD +C_CSP: + .WORD X_USER ; Put next word on stack then do next + .WORD CSP-SYSTEM + +W_RHASH: + .BYTE $82,"R",'#'+$80 + .WORD W_CSP +C_RHASH: + .WORD X_USER ; Put next word on stack then do next + .WORD RHASH-SYSTEM + +W_HLD: + .BYTE $83,"HL",'D'+$80 + .WORD W_RHASH +C_HLD: + .WORD X_USER ; Put next word on stack then do next + .WORD HLD-SYSTEM + +W_UCL: + .BYTE $84,"UC/",'L'+$80 + .WORD W_HLD +C_UCL: + .WORD X_USER ; Put next word on stack then do next + .WORD UCL-SYSTEM + +W_UFIRST: + .BYTE $86,"UFIRS",'T'+$80 + .WORD W_UCL +C_UFIRST: + .WORD X_USER ; Put next word on stack then do next + .WORD UFIRST-SYSTEM + +W_ULIMIT: + .BYTE $86,"ULIMI",'T'+$80 + .WORD W_UFIRST +C_ULIMIT: + .WORD X_USER ; Put next word on stack then do next + .WORD ULIMIT-SYSTEM + +W_UBBUF: + .BYTE $86,"UB/BU",'F'+$80 + .WORD W_ULIMIT +C_UBBUF: + .WORD X_USER ; Put next word on stack then do next + .WORD UBBUF-SYSTEM + +W_UBSCR: + .BYTE $86,"UB/SC",'R'+$80 + .WORD W_UBBUF +C_UBSCR: + .WORD X_USER ; Put next word on stack then do next + .WORD UBSCR-SYSTEM + +W_UTERMINAL: + .BYTE 8Ah,"U?TERMINA",'L'+$80 + .WORD W_UBSCR +C_UTERMINAL: + .WORD X_USER ; Put next word on stack then do next + .WORD UTERMNL-SYSTEM + +W_UKEY: ; Put UKEY addr on stack + .BYTE $84,"UKE",'Y'+$80 + .WORD W_UTERMINAL +C_UKEY: + .WORD X_USER ; Put next word on stack then do next + .WORD UKEY-SYSTEM + +W_UEMIT: ; Put UEMIT addr on stack + .BYTE $85,"UEMI",'T'+$80 + .WORD W_UKEY +C_UEMIT: + .WORD X_USER ; Put next word on stack then do next + .WORD UEMIT-SYSTEM + +W_UCR: ; Push UCR addr + .BYTE $83,"UC",'R'+$80 + .WORD W_UEMIT +C_UCR: + .WORD X_USER ; Put next word on stack then do next + .WORD UCR-SYSTEM + +W_URW: + .BYTE $84,"UR/",'W'+$80 + .WORD W_UCR +C_URW: + .WORD X_USER ; Put next word on stack then do next + .WORD URW-SYSTEM + +W_UABORT: ; Put UABORT on stack + .BYTE $86,"UABOR",'T'+$80 + .WORD W_URW +C_UABORT: + .WORD X_USER ; Put next word on stack then do next + .WORD UABORT-SYSTEM + +W_RAF: + .BYTE $83,"RA",'F'+$80 + .WORD W_UABORT +C_RAF: + .WORD X_USER ; Put next word on stack then do next + .WORD RAF-SYSTEM + +W_RBC: + .BYTE $83,"RB",'C'+$80 + .WORD W_RAF +C_RBC: + .WORD X_USER ; Put next word on stack then do next + .WORD RBC-SYSTEM + +W_RDE: + .BYTE $83,"RD",'E'+$80 + .WORD W_RBC +C_RDE + .WORD X_USER ; Put next word on stack then do next + .WORD RDE-SYSTEM + +W_RHL: + .BYTE $83,"RH",'L'+$80 + .WORD W_RDE +C_RHL: + .WORD X_USER ; Put next word on stack then do next + .WORD RHL-SYSTEM + +W_RIX: + .BYTE $83,"RI",'X'+$80 + .WORD W_RHL +C_RIX: + .WORD X_USER ; Put next word on stack then do next + .WORD RIX-SYSTEM + +W_RIY: + .BYTE $83,"RI",'Y'+$80 + .WORD W_RIX +C_RIY: + .WORD X_USER ; Put next word on stack then do next + .WORD RIY-SYSTEM + +W_RAF2: + .BYTE $84,"RAF",2Ch+$80 + .WORD W_RIY +C_RAF2: + .WORD X_USER ; Put next word on stack then do next + .WORD RAF2-SYSTEM + +W_RBC2: + .BYTE $84,"RBC",2Ch+$80 + .WORD W_RAF2 +C_RBC2: + .WORD X_USER ; Put next word on stack then do next + .WORD RBC2-SYSTEM + +W_RDE2: + .BYTE $84,"RDE",2Ch+$80 + .WORD W_RBC2 +C_RDE2: + .WORD X_USER ; Put next word on stack then do next + .WORD RDE2-SYSTEM + +W_RHL2: + .BYTE $84,"RHL",2Ch+$80 + .WORD W_RDE2 +C_RHL2: + .WORD X_USER ; Put next word on stack then do next + .WORD RHL2-SYSTEM + +W_RA: + .BYTE $82,"R",'A'+$80 + .WORD W_RHL2 +C_RA: + .WORD X_USER ; Put next word on stack then do next + .WORD RAF+1-SYSTEM + +W_RF: + .BYTE $82,"R",'F'+$80 + .WORD W_RA +C_RF: + .WORD X_USER ; Put next word on stack then do next + .WORD RAF-SYSTEM + +W_RB: + .BYTE $82,"R",'B'+$80 + .WORD W_RF +C_RB: + .WORD X_USER ; Put next word on stack then do next + .WORD RBC+1-SYSTEM + +W_RC: + .BYTE $82,"R",'C'+$80 + .WORD W_RB +C_RC: + .WORD X_USER ; Put next word on stack then do next + .WORD RBC-SYSTEM + +W_RD: + .BYTE $82,"R",'D'+$80 + .WORD W_RC +C_RD: + .WORD X_USER ; Put next word on stack then do next + .WORD RDE+1-SYSTEM + +W_RE: + .BYTE $82,"R",'E'+$80 + .WORD W_RD +C_RE: + .WORD X_USER ; Put next word on stack then do next + .WORD RDE-SYSTEM + +W_RH: + .BYTE $82,"R",'H'+$80 + .WORD W_RE +C_RH: + .WORD X_USER ; Put next word on stack then do next + .WORD RHL+1-SYSTEM + +W_RL: + .BYTE $82,"R",'L'+$80 + .WORD W_RH +C_RL: + .WORD X_USER ; Put next word on stack then do next + .WORD RHL-SYSTEM + +W_CALL: + .BYTE $84,"CAL",'L'+$80 + .WORD W_RL +C_CALL: + .WORD 2+$ ; Vector to code + POP HL ; Address of routine CALLed + PUSH DE ; Save register + PUSH BC ; Save register + LD A,$C3 ; Hex code for JMP + LD (JPCODE),A ; Save it + LD (JPVECT),HL ; Save jump vector + LD HL,(RAF) ; Get register AF + PUSH HL ; Onto stack + POP AF ; POP into AF + LD BC,(RBC) ; Get register BC + LD DE,(RDE) ; Get register DE + LD HL,(RHL) ; Get register HL + LD IX,(RIX) ; Get register IX + LD IY,(RIY) ; Get register IY + CALL JPCODE ; Call jump to code + LD (RIY),IY ; Save register IY + LD (RIX),IX ; Save register IX + LD (RBC),BC ; Save register BC + LD (RDE),DE ; Save register DE + LD (RHL),HL ; Save register HL + PUSH AF ; Save register AF + POP HL ; Into HL + LD (RAF),HL ; Into memory + POP BC ; Restore BC + POP DE ; Restore DE + JP NEXT ; + +W_1PLUS: ; 1 plus + .BYTE $82,"1",'+'+$80 + .WORD W_CALL +C_1PLUS: + .WORD 2+$ ; Vector to code + POP HL ; get n + INC HL ; add 1 + JP NEXTS1 ; save result & NEXT + +W_2PLUS: ; 2 plus + .BYTE $82,"2",'+'+$80 + .WORD W_1PLUS +C_2PLUS: + .WORD 2+$ ; Vector to code + POP HL ; get n + INC HL ; add 1 + INC HL ; add 2 + JP NEXTS1 ; save result & NEXT + +W_1MINUS: ; 1 minus + .BYTE $82,"1",'-'+$80 + .WORD W_2PLUS +C_1MINUS: + .WORD 2+$ ; Vector to code + POP HL ; get n + DEC HL ; add 1 + JP NEXTS1 ; save result & NEXT + +W_2MINUS: ; 2 minus + .BYTE $82,"2",'-'+$80 + .WORD W_1MINUS +C_2MINUS: + .WORD 2+$ ; Vector to code + POP HL ; get n + DEC HL ; subtract 1 + DEC HL ; subtract 2 + JP NEXTS1 ; save result & NEXT + +W_HERE: ; Dictionary pointer onto stack + .BYTE $84,"HER",'E'+$80 + .WORD W_2MINUS +C_HERE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DP ; Dictionary pointer addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ALLOT: + .BYTE $85,"ALLO",'T'+$80 + .WORD W_HERE +C_ALLOT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DP ; Dictionary pointer addr on stack + .WORD C_PLUSSTORE ; Add n1 to addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_COMMA: ; Reserve 2 bytes and save n + .BYTE $81,','+$80 + .WORD W_ALLOT +C_COMMA: + .WORD E_COLON ; Interpret following word sequence + .WORD C_HERE ; Next free dictionary pointer onto stack + .WORD C_STORE ; Store word at addr + .WORD C_2 ; + .WORD C_ALLOT ; Move pointer + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CCOMMA: + .BYTE $82,"C",','+$80 + .WORD W_COMMA +C_CCOMMA: + .WORD E_COLON ; Interpret following word sequence + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_CSTORE ; Store byte at addr + .WORD C_1 ; Put 1 on stack + .WORD C_ALLOT + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MINUS: + .BYTE $81,'-'+$80 + .WORD W_CCOMMA +C_MINUS: + .WORD 2+$ ; Vector to code + POP DE ; get n1 + POP HL ; get n2 + CALL MINUS16 ; call subtract routine + JP NEXTS1 ; save & NEXT + +MINUS16: + LD A,L ; gel low byte + SUB E ; subtract low bytes + LD L,A ; save low byte result + LD A,H ; get high byte + SBC A,D ; subtract high bytes + LD H,A ; save high byte result + RET ; + +W_EQUALS: + .BYTE $81,'='+$80 + .WORD W_MINUS +C_EQUALS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MINUS + .WORD C_0EQUALS ; =0 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LESSTHAN: + .BYTE $81,'<'+$80 + .WORD W_EQUALS +C_LESSTHAN: + .WORD 2+$ ; Vector to code + POP DE + POP HL + LD A,D + XOR H + JP M,J298C + CALL MINUS16 +J298C: + INC H + DEC H + JP M,J2997 + LD HL,0000 + JP NEXTS1 ; Save & NEXT +J2997: + LD HL,0001 + JP NEXTS1 ; Save & NEXT + +W_ULESS: ; IF stack-1 < stack_top leave true flag + .BYTE $82,"U",'<'+$80 + .WORD W_LESSTHAN +C_ULESS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_2DUP ; Dup top 2 values on stack + .WORD C_XOR ; Exclusive OR them + .WORD C_0LESS ; Less than 0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0000-$ ; 000Ch + .WORD C_DROP ; Drop top value from stack + .WORD C_0LESS ; Less than 0 + .WORD C_0EQUALS ; =0 + .WORD C_BRANCH ; Add following offset to BC + .WORD B0001-$ ; 0006h +B0000: + .WORD C_MINUS + .WORD C_0LESS ; Less than 0 +B0001: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_GREATER: + .BYTE $81,'>'+$80 + .WORD W_ULESS +C_GREATER: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_LESSTHAN + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ROT: ; 3rd valu down to top of stack + .BYTE $83,"RO",'T'+$80 + .WORD W_GREATER +C_ROT: + .WORD 2+$ ; Vector to code + POP DE ; Top value + POP HL ; Next one down + EX (SP),HL ; Exchange with third + JP NEXTS2 ; Save both & NEXT + +W_PICK: + .BYTE $84,"PIC",'K'+$80 + .WORD W_ROT +C_PICK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate top value on stack + .WORD C_PLUS ; n1 + n2 + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_PLUS ; n1 + n2 + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SPACE: + .BYTE $85,"SPAC",'E'+$80 + .WORD W_PICK +C_SPACE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BL ; Leaves ASCII for space on stack + .WORD C_EMIT ; Output CHR from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QUERYDUP: + .BYTE $84,"?DU",'P'+$80 + .WORD W_SPACE +C_QUERYDUP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate top value on stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0002-$ ; 0004h + .WORD C_DUP ; Duplicate top value on stack +B0002: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TRAVERSE: + .BYTE $88,"TRAVERS",'E'+$80 + .WORD W_QUERYDUP +C_TRAVERSE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SWAP ; Swap top 2 values on stack +B0054: + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_PLUS ; n1 + n2 + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 007Fh + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_LESSTHAN + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0054-$ ; FFF0h + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LATEST: + .BYTE $86,"LATES",'T'+$80 + .WORD W_TRAVERSE +C_LATEST: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CURRENT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LFA: + .BYTE $83,"LF",'A'+$80 + .WORD W_LATEST +C_LFA: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0004h + .WORD C_MINUS + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CFA: + .BYTE $83,"CF",'A'+$80 + .WORD W_LFA +C_CFA: + .WORD 2+$ ; Vector to code + POP HL ; get n + DEC HL ; subtract 1 + DEC HL ; subtract 2 + JP NEXTS1 ; save result & NEXT +W_NFA: + .BYTE $83,"NF",'A'+$80 + .WORD W_CFA +C_NFA: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0005h + .WORD C_MINUS + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $FFFF + .WORD C_TRAVERSE + .WORD C_STOP ; Pop BC from return stack (=next) + +W_PFA: ; Convert NFA to PFA + .BYTE $83,"PF",'A'+$80 + .WORD W_NFA +C_PFA: + .WORD E_COLON ; Interpret following word sequence + .WORD C_1 ; Traverse up memory + .WORD C_TRAVERSE ; End of name on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0005h ; Offset to start of word code + .WORD C_PLUS ; n1 + n2 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CSPSTORE: + .BYTE $84,"!CS",'P'+$80 + .WORD W_PFA +C_CSPSTORE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_CSP ; Push check stack pointer addr + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QERROR: + .BYTE $86,"?ERRO",'R'+$80 + .WORD W_CSPSTORE +C_QERROR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_0BRANCH ; Branch if no error + .WORD B0003-$ ; 0008h + .WORD C_ERROR + .WORD C_BRANCH ; Add following offset to BC + .WORD B0004-$ ; 0004h +B0003: + .WORD C_DROP ; Drop error no. +B0004: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QCOMP: ; Error if not in compile mode + .BYTE $85,"?COM",'P'+$80 + .WORD W_QERROR +C_QCOMP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_STATE ; Push STATE addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0EQUALS ; =0 + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0011h ; Error message number + .WORD C_QERROR ; Error if state <> 0 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QEXEC: ; Error not if not in execute mode + .BYTE $85,"?EXE",'C'+$80 + .WORD W_QCOMP +C_QEXEC: + .WORD E_COLON ; Interpret following word sequence + .WORD C_STATE ; Push STATE addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0012h ; Error not if not in execute mode + .WORD C_QERROR + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QPAIRS: + .BYTE $86,"?PAIR",'S'+$80 + .WORD W_QEXEC +C_QPAIRS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MINUS + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0013h + .WORD C_QERROR + .WORD C_STOP ; Pop BC from return stack (=next) + +W_WHATSTACK: ; Check stack pointer, error if not ok + .BYTE $84,"?CS",'P'+$80 + .WORD W_QPAIRS +C_WHATSTACK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_CSP ; Push check stack pointer addr + .WORD C_FETCH ; Get check stack pointer + .WORD C_MINUS ; If ok then result is 0 + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0014h ; Error no if not ok + .WORD C_QERROR ; Error if stack top -1 <> 0 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QLOADING: + .BYTE $88,"?LOADIN",'G'+$80 + .WORD W_WHATSTACK +C_QLOADING: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0EQUALS ; =0 + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0016h + .WORD C_QERROR + .WORD C_STOP ; Pop BC from return stack (=next) + +W_COMPILE: + .BYTE $87,"COMPIL",'E'+$80 + .WORD W_QLOADING +C_COMPILE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QCOMP ; Error if not in compile mode + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_DUP ; Bump return address and put back + .WORD C_2PLUS ; + .WORD C_MOVER ; + .WORD C_FETCH ; Get word from addr on stack + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LEFTBRKT: ; Set STATE to execute + .BYTE $81,'['+$80 + .WORD W_COMPILE +C_LEFTBRKT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_STATE ; Push STATE addr + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_RIGHTBRKT: ; Set STATE to compile + .BYTE $81,']'+$80 + .WORD W_LEFTBRKT +C_RIGHTBRKT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 00$C0 + .WORD C_STATE ; Push STATE addr + .WORD C_STORE ; Set STATE to execute + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SMUDGE: + .BYTE $86,"SMUDG",'E'+$80 + .WORD W_RIGHTBRKT +C_SMUDGE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LATEST ; Push top words NFA + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0020h + .WORD C_TOGGLE ; XOR (addr) with byte + .WORD C_STOP ; Pop BC from return stack (=next) + +W_HEX: + .BYTE $83,"HE",'X'+$80 + .WORD W_SMUDGE +C_HEX: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0010h + .WORD C_BASE ; Put BASE addr on stack + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DECIMAL: ; Sets decimal mode + .BYTE $87,"DECIMA",'L'+$80 + .WORD W_HEX +C_DECIMAL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 00$0A ; Sets decimal value + .WORD C_BASE ; Put BASE addr on stack + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CCODE: ; Stop compillation & terminate word + .BYTE $87,"<; CODE",'>'+$80 + .WORD W_DECIMAL +C_CCODE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_LATEST ; Push top words NFA + .WORD C_PFA ; Convert NFA to PFA + .WORD C_CFA ; Convert PFA to CFA + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SCCODE: + .BYTE $C5,"; COD",'E'+$80 + .WORD W_CCODE +C_SCCODE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_WHATSTACK ; Check stack pointer, error if not ok + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_CCODE + .WORD C_LEFTBRKT ; Set STATE to execute + .WORD C_TASK + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CREATE: + .BYTE $86,"CREAT",'E'+$80 + .WORD W_SCCODE +C_CREATE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_CONSTANT + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DOES: + .BYTE $85,"DOES",'>'+$80 + .WORD W_CREATE +C_DOES: + .WORD E_COLON ; Interpret following word sequence + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_LATEST ; Push top words NFA + .WORD C_PFA ; Convert NFA to PFA + .WORD C_STORE ; Store word at addr + .WORD C_CCODE ; Execute following machine code + +X_DOES: + LD HL,(RPP) ; Get return stack pointer + DEC HL ; Push next pointer + LD (HL),B ; + DEC HL ; + LD (HL),C ; + LD (RPP),HL + INC DE + EX DE,HL + LD C,(HL) + INC HL + LD B,(HL) + INC HL + JP NEXTS1 ; Save & NEXT + +W_COUNT: ; Convert string at addr to addr + length + .BYTE $85,"COUN",'T'+$80 + .WORD W_DOES +C_COUNT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate address + .WORD C_1PLUS ; Add 1 (points to string start) + .WORD C_SWAP ; Get address back + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TYPE: ; Output n bytes from addr + .BYTE $84,"TYP",'E'+$80 + .WORD W_COUNT +C_TYPE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QUERYDUP ; Copy length if length <> 0 + .WORD C_0BRANCH ; Branch if length = 0 + .WORD B0005-$ ; 0018h + .WORD C_OVER ; Copy address to stack top + .WORD C_PLUS ; Add to length + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_LDO ; Put start & end loop values on RPP +B004F: + .WORD C_I ; Copy LOOP index to data stack + .WORD C_CFETCH ; Get byte from string + .WORD C_EMIT ; Output CHR from stack + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD B004F-$ ; FFF8h + .WORD C_BRANCH ; Done so branch to next + .WORD B0006-$ ; 0004h +B0005: + .WORD C_DROP ; Drop string address +B0006: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TRAILING: + .BYTE $89,"-TRAILIN",'G'+$80 + .WORD W_TYPE +C_TRAILING: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate top value on stack + .WORD C_ZERO ; Put zero on stack + .WORD C_LDO ; Put start & end loop values on RPP +B0009: + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_PLUS ; n1 + n2 + .WORD C_1 ; Put 1 on stack + .WORD C_MINUS + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_BL ; Leaves ASCII for space on stack + .WORD C_MINUS + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0007-$ ; 0008h + .WORD C_LEAVE ; Quit loop by making index = limit + .WORD C_BRANCH ; Add following offset to BC + .WORD B0008-$ ; 0006h +B0007: + .WORD C_1 ; Put 1 on stack + .WORD C_MINUS +B0008: + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD B0009-$ ; FFE0h + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CQUOTE: ; Output following string + .BYTE $84,"<.",22h,'>'+$80 + .WORD W_TRAILING +C_CQUOTE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_RFETCH ; Copy return stack top to data stack + .WORD C_COUNT ; Convert string at addr to addr + length + .WORD C_DUP ; Duplicate top value on stack + .WORD C_1PLUS ; 1 plus + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_PLUS ; Add length of string +1 + .WORD C_MOVER ; Move value from data to return stack + .WORD C_TYPE ; Output n bytes from addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QUOTE: ; Accept following text + .BYTE $C2,".",$22+$80 + .WORD W_CQUOTE +C_QUOTE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0022 + .WORD C_STATE ; Push STATE addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B000A-$ ; 0012h + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_CQUOTE + .WORD C_WORD + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_1PLUS ; 1 plus + .WORD C_ALLOT + .WORD C_BRANCH ; Add following offset to BC + .WORD B000B-$ ; 0008h +B000A: + .WORD C_WORD + .WORD C_COUNT ; Convert string at addr to addr + length + .WORD C_TYPE ; Output n bytes from addr +B000B: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_EXPECT: + .BYTE $86,"EXPEC",'T'+$80 + .WORD W_QUOTE +C_EXPECT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_OVER ; Copy buffer start addr + .WORD C_PLUS ; Add to length to give start,end + .WORD C_OVER ; Copy start + .WORD C_LDO ; Put start & end loop values on RPP +B0012: + .WORD C_KEY ; Wait for key, value on stack + .WORD C_DUP ; Duplicate key value + .WORD C_LIT ; Push backspace addr + .WORD BACKSPACE + .WORD C_FETCH ; Get backspace value + .WORD C_EQUALS ; Was it backspace ? + .WORD C_0BRANCH ; If not then jump + .WORD B000C-$ ; 002Ah + .WORD C_DROP ; Drop top value from stack + .WORD C_DUP ; Duplicate top value on stack + .WORD C_I ; Copy LOOP index to data stack + .WORD C_EQUALS + .WORD C_DUP ; Duplicate top value on stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_2 + .WORD C_MINUS + .WORD C_PLUS ; n1 + n2 + .WORD C_MOVER ; Move value from data to return stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B000D-$ ; 00$0A + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0007h + .WORD C_BRANCH ; Add following offset to BC + .WORD B000E-$ ; 0006h +B000D: + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0008h +B000E: + .WORD C_BRANCH ; Add following offset to BC + .WORD B000F-$ ; 0028h +B000C: + .WORD C_DUP ; Duplicate key value + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 00$0D ; CR + .WORD C_EQUALS ; Was it cariage return + .WORD C_0BRANCH ; If not then jump + .WORD B0010-$ ; 000Eh + .WORD C_LEAVE ; Quit loop by making index = limit + .WORD C_DROP ; Drop top value from stack + .WORD C_BL ; Leaves ASCII for space on stack + .WORD C_ZERO ; Put zero on stack + .WORD C_BRANCH ; Add following offset to BC + .WORD B0011-$ ; 0004h +B0010: + .WORD C_DUP ; Duplicate key value +B0011: + .WORD C_I ; Copy LOOP index to data stack + .WORD C_CSTORE ; Store byte at addr + .WORD C_ZERO ; Put zero on stack + .WORD C_I ; Copy LOOP index to data stack + .WORD C_1PLUS ; 1 plus + .WORD C_STORE ; Store word at addr +B000F: + .WORD C_EMIT ; Output CHR from stack + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD B0012-$ ; FF9Eh + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QUERY: + .BYTE $85,"QUER",'Y'+$80 + .WORD W_EXPECT +C_QUERY: + .WORD E_COLON ; Interpret following word sequence + .WORD C_TIB ; Put TIB addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0050 ; Max line length 50h + .WORD C_EXPECT ; Get line + .WORD C_ZERO ; Put zero on stack + .WORD C_TOIN ; Current input buffer offset + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_NULL: + .BYTE $C1,$80 + .WORD W_QUERY +C_NULL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0013-$ ; 002Ah + .WORD C_1 ; Put 1 on stack + .WORD C_BLK + .WORD C_PLUSSTORE ; Add n1 to addr + .WORD C_ZERO ; Put zero on stack + .WORD C_TOIN ; Current input buffer offset + .WORD C_STORE ; Store word at addr + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_BSCR ; Number of buffers per block on stack + .WORD C_1 ; Put 1 on stack + .WORD C_MINUS + .WORD C_AND ; AND + .WORD C_0EQUALS ; =0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0014-$ ; 0008h + .WORD C_QEXEC ; Error not if not in execute mode + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_DROP ; Drop top value from stack +B0014: + .WORD C_BRANCH ; Add following offset to BC + .WORD B0015-$ ; 0006h +B0013: + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_DROP ; Drop top value from stack +B0015: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_FILL: ; Fill with byte n bytes from addr + .BYTE $84,"FIL",'L'+$80 + .WORD W_NULL +C_FILL: + .WORD 2+$ ; Vector to code + LD L,C ; Save BC for now + LD H,B ; + POP DE ; get byte + POP BC ; get n + EX (SP),HL ; get addr and save BC + EX DE,HL ; +NEXT_BYTE: + LD A,B ; Test count + OR C ; + JR Z,NO_COUNT ; If 0 we're done + LD A,L ; Byte into A + LD (DE),A ; Save byte + INC DE ; Next addr + DEC BC ; Decr count + JR NEXT_BYTE ; Loop +NO_COUNT: + POP BC ; Get BC back + JP NEXT + +W_ERASE: ; Fill addr & length from stack with 0 + .BYTE $85,"ERAS",'E'+$80 + .WORD W_FILL +C_ERASE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_FILL ; Fill with byte n bytes from addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BLANKS: ; Fill addr & length from stack with [SP] + .BYTE $86,"BLANK",'S'+$80 + .WORD W_ERASE +C_BLANKS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BL ; Leaves ASCII for space on stack + .WORD C_FILL ; Fill with byte n bytes from addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_HOLD: + .BYTE $84,"HOL",'D'+$80 + .WORD W_BLANKS +C_HOLD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $FFFF + .WORD C_HLD + .WORD C_PLUSSTORE ; Add n1 to addr + .WORD C_HLD + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CSTORE ; Store byte at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_PAD: + .BYTE $83,"PA",'D'+$80 + .WORD W_HOLD +C_PAD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0044h + .WORD C_PLUS ; n1 + n2 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_WORD: + .BYTE $84,"WOR",'D'+$80 + .WORD W_PAD +C_WORD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0016-$ ; 000Ch + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_BLOCK + .WORD C_BRANCH ; Add following offset to BC + .WORD B0017-$ ; 0006h +B0016: + .WORD C_TIB + .WORD C_FETCH ; Get word from addr on stack +B0017: + .WORD C_TOIN ; Current input buffer offset + .WORD C_FETCH ; Get word from addr on stack + .WORD C_PLUS ; n1 + n2 + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_ENCLOSE + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0022h + .WORD C_BLANKS + .WORD C_TOIN ; Current input buffer offset + .WORD C_PLUSSTORE ; Add n1 to addr + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_MINUS + .WORD C_MOVER ; Move value from data to return stack + .WORD C_RFETCH ; Return stack top to data stack + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_CSTORE ; Store byte at addr + .WORD C_PLUS ; n1 + n2 + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_1PLUS ; 1 plus + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_CMOVE ; Move block + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CONVERT: + .BYTE $87,"CONVER",'T'+$80 + .WORD W_WORD +C_CONVERT: + .WORD E_COLON ; Interpret following word sequence +B001A: + .WORD C_1PLUS ; 1 plus + .WORD C_DUP ; Duplicate top value on stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_BASE ; Put BASE addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_DIGIT ; Convert digit n2 using base n1 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0018-$ ; 002Ch + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_BASE ; Put BASE addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_USTAR + .WORD C_DROP ; Drop top value from stack + .WORD C_ROT ; 3rd value down to top of stack + .WORD C_BASE ; Put BASE addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_USTAR + .WORD C_DPLUS + .WORD C_DPL + .WORD C_FETCH ; Get word from addr on stack + .WORD C_1PLUS ; 1 plus + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0019-$ ; 0008h + .WORD C_1 ; Put 1 on stack + .WORD C_DPL + .WORD C_PLUSSTORE ; Add n1 to addr +B0019: + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_BRANCH ; Add following offset to BC + .WORD B001A-$ ; FF$C6 +B0018: + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_NUMBER: + .BYTE $86,"NUMBE",'R'+$80 + .WORD W_CONVERT +C_NUMBER: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_ZERO ; Put zero on stack + .WORD C_ROT ; 3rd value down to top of stack + .WORD C_DUP ; Duplicate top value on stack + .WORD C_1PLUS ; 1 plus + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 002Dh ; '-' + .WORD C_EQUALS ; Is first chr = '-' + .WORD C_DUP ; Duplicate negative flag + .WORD C_MOVER ; Move value from data to return stack + .WORD C_PLUS ; n1 + n2 + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $FFFF ;-1 +B001C: + .WORD C_DPL + .WORD C_STORE ; Store word at addr + .WORD C_CONVERT + .WORD C_DUP ; Duplicate top value on stack + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_BL ; Leaves ASCII for space on stack + .WORD C_MINUS + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B001B-$ ; 0016h + .WORD C_DUP ; Duplicate top value on stack + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 002Eh ; '.' + .WORD C_MINUS + .WORD C_ZERO ; Put zero on stack + .WORD C_QERROR + .WORD C_ZERO ; Put zero on stack + .WORD C_BRANCH ; Add following offset to BC + .WORD B001C-$ ; FFDCh +B001B: + .WORD C_DROP ; Drop top value from stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B001D-$ ; 0004h + .WORD C_DNEGATE +B001D: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MFIND: + .BYTE $85,"-FIN",'D'+$80 + .WORD W_NUMBER +C_MFIND: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BL ; Leaves ASCII for space on stack + .WORD C_WORD + .WORD C_CONTEXT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_FIND ; Find word & return vector,byte & flag + .WORD C_DUP ; Duplicate top value on stack + .WORD C_0EQUALS ; =0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B001E-$ ; 00$0A + .WORD C_DROP ; Drop top value from stack + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_LATEST ; Push top words NFA + .WORD C_FIND ; Find word & return vector,byte & flag +B001E: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CABORT: + .BYTE $87,"'+$80 + .WORD W_MFIND +C_CABORT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ABORT + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ERROR: + .BYTE $85,"ERRO",'R'+$80 + .WORD W_CABORT +C_ERROR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_WARNING ; Put WARNING addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0LESS ; Less than 0 leaves true + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B001F-$ ; 0004h + .WORD C_CABORT +B001F: + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_COUNT ; Convert string at addr to addr + length + .WORD C_TYPE ; Output n bytes from addr + .WORD C_CQUOTE ; Output following string + .BYTE S_END7-S_START7 +S_START7: + .BYTE "? " +S_END7: + .WORD C_MESSAGE ; Output message + .WORD C_SPSTORE ; Set initial stack pointer value + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_QUERYDUP + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0020-$ ; 0008h + .WORD C_TOIN ; Current input buffer offset + .WORD C_FETCH ; Get word from addr on stack + .WORD C_SWAP ; Swap top 2 values on stack +B0020: + .WORD C_QUIT + +W_ID: ; Print definition name from name field addr + .BYTE $83,"ID",'.'+$80 + .WORD W_ERROR +C_ID: + .WORD E_COLON ; Interpret following word sequence + .WORD C_COUNT ; Convert string at addr to addr + length + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 001Fh ; Max length is 1Fh + .WORD C_AND ; AND lenght with 1Fh + .WORD C_TYPE ; Output n bytes from addr + .WORD C_SPACE ; Output space + .WORD C_STOP ; Pop BC from return stack (=next) + +C_XXX1: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MFIND ; Find name returns PFA,length,true or false + .WORD C_0BRANCH ; Branch if name not found + .WORD B0021-$ ; 0010h + .WORD C_DROP ; Drop length + .WORD C_NFA ; Convert PFA to NFA + .WORD C_ID ; Print definition name from name field addr + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0004 ; Message 4, name defined twice + .WORD C_MESSAGE ; Output message + .WORD C_SPACE ; Output space +B0021: + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_DUP ; Duplicate top value on stack + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_WIDTH + .WORD C_FETCH ; Get word from addr on stack + .WORD C_MIN + .WORD C_1PLUS ; 1 plus + .WORD C_ALLOT ; Which ever is smallest width or namelength + .WORD C_DUP ; Duplicate top value on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $00A0 + .WORD C_TOGGLE ; XOR (addr) with byte + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_1 ; Put 1 on stack + .WORD C_MINUS + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0080 + .WORD C_TOGGLE ; XOR (addr) with byte + .WORD C_LATEST ; Push top words NFA + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_CURRENT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STORE ; Store word at addr + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_2PLUS ; 2 plus + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CCOMPILE: + .BYTE $89,"[COMPILE",']'+$80 + .WORD W_ID +C_CCOMPILE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MFIND + .WORD C_0EQUALS ; =0 + .WORD C_ZERO ; Put zero on stack + .WORD C_QERROR + .WORD C_DROP ; Drop top value from stack + .WORD C_CFA ; Convert PFA to CFA + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LITERAL: + .BYTE $C7,"LITERA",'L'+$80 + .WORD W_CCOMPILE +C_LITERAL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_STATE ; Push STATE addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0022-$ ; 0008h + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD C_COMMA ; Reserve 2 bytes and save n +B0022: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DLITERAL: + .BYTE $C8,"DLITERA",'L'+$80 + .WORD W_LITERAL +C_DLITERAL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_STATE ; Push STATE addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0023-$ ; 0008h + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_LITERAL + .WORD C_LITERAL +B0023: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QSTACK: + .BYTE $86,"?STAC",'K'+$80 + .WORD W_DLITERAL +C_QSTACK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_S0 ; Push S0 (initial data stack pointer) + .WORD C_FETCH ; Get word from addr on stack + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_ULESS ; IF stack-1 < stack_top leave true flag + .WORD C_1 ; Put 1 on stack + .WORD C_QERROR + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0080 + .WORD C_PLUS ; n1 + n2 + .WORD C_ULESS ; IF stack-1 < stack_top leave true flag + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0007 + .WORD C_QERROR + .WORD C_STOP ; Pop BC from return stack (=next) + +W_INTERPRET: + .BYTE $89,"INTERPRE",'T'+$80 + .WORD W_QSTACK +C_INTERPRET: + .WORD E_COLON ; Interpret following word sequence +B002A: + .WORD C_MFIND ; Find name returns PFA,length,true or false + .WORD C_0BRANCH ; Branch if name not found + .WORD NO_NAME-$ + .WORD C_STATE ; STATE addr on stack + .WORD C_FETCH ; Get STATE + .WORD C_LESSTHAN ; Is it quit compile word ? + .WORD C_0BRANCH ; If so then branch + .WORD B0025-$ ; + .WORD C_CFA ; Convert PFA to CFA + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_BRANCH ; Add following offset to BC + .WORD B0026-$ ; +B0025: + .WORD C_CFA ; Convert PFA to CFA + .WORD C_EXECUTE ; Jump to address on stack +B0026: + .WORD C_QSTACK ; Error message if stack underflow + .WORD C_BRANCH ; Add following offset to BC + .WORD B0027-$ ; +NO_NAME: + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_NUMBER ; Convert string at addr to double + .WORD C_DPL ; + .WORD C_FETCH ; Get word from addr on stack + .WORD C_1PLUS ; 1 plus + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0028-$ ; + .WORD C_DLITERAL + .WORD C_BRANCH ; Add following offset to BC + .WORD B0029-$ ; +B0028: + .WORD C_DROP ; Drop top value from stack + .WORD C_LITERAL +B0029: + .WORD C_QSTACK ; Error message if stack underflow +B0027: + .WORD C_BRANCH ; Add following offset to BC + .WORD B002A-$ ; FF$C2 + +W_IMMEDIATE: + .BYTE $89,"IMMEDIAT",'E'+$80 + .WORD W_INTERPRET +C_IMMEDIATE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LATEST ; Push top words NFA + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0040 + .WORD C_TOGGLE ; XOR (addr) with byte + .WORD C_STOP ; Pop BC from return stack (=next) + +W_VOCABULARY: + .BYTE 8Ah,"VOCABULAR",'Y'+$80 + .WORD W_IMMEDIATE +C_VOCABULARY: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CREATE + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $A081 + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_CURRENT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CFA ; Convert PFA to CFA + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_VOC_LINK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_VOC_LINK + .WORD C_STORE ; Store word at addr + .WORD C_DOES + .WORD C_2PLUS ; 2 plus + .WORD C_CONTEXT + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +C_LINK: + .WORD C_2PLUS ; 2 plus + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CONTEXT + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_FORTH: + .BYTE $C5,"FORT",'H'+$80 + .WORD W_VOCABULARY +C_FORTH: + .WORD X_DOES + .WORD C_LINK + + .BYTE $81,' '+$80 + .WORD FLAST+2 +E_FORTH: + .WORD $0000 + +W_DEFINITIONS: ; Set CURRENT as CONTEXT vocabulary + .BYTE 8Bh,"DEFINITION",'S'+$80 + .WORD W_FORTH +C_DEFINITIONS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CONTEXT ; Get CONTEXT addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CURRENT ; Get CURRENT addr + .WORD C_STORE ; Set CURRENT as the context vocabulary + .WORD C_STOP ; Pop BC from return stack (=next) + +W_OPENBRKT: + .BYTE $C1,'('+$80 + .WORD W_DEFINITIONS +C_OPENBRKT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0029 + .WORD C_WORD + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) +;--------------------------------------------------------------------------------------- +; This it the last thing ever executed and is the interpreter +; outer loop. This NEVER quits. +;--------------------------------------------------------------------------------------- +W_QUIT: .BYTE $84,"QUI",'T'+$80 + .WORD W_OPENBRKT +C_QUIT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_BLK ; Get current BLK pointer + .WORD C_STORE ; Set BLK to 0 + .WORD C_LEFTBRKT ; Set STATE to execute +B002C: + .WORD C_RPSTORE ; Set initial return stack pointer + .WORD C_CR ; Output [CR][LF] + .WORD C_QUERY ; Get string from input, ends in CR + .WORD C_INTERPRET ; Interpret input stream + .WORD C_STATE ; Push STATE addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_0EQUALS ; =0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD S_END8-$ ; 0007h + .WORD C_CQUOTE ; Output following string + .BYTE S_END8-S_START8 +S_START8: + .BYTE "OK" +S_END8: + .WORD C_BRANCH ; Add following offset to BC + .WORD B002C-$ ; FFE7h + +W_ABORT: + .BYTE $85,"ABOR",'T'+$80 + .WORD W_QUIT +C_ABORT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UABORT ; Put UABORT on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_EXECUTE ; Jump to address on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +CF_UABORT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SPSTORE ; Set initial stack pointer value + .WORD C_DECIMAL ; Sets decimal mode + .WORD C_QSTACK ; Error message if stack underflow + .WORD C_CR ; Output [CR][LF] + .WORD C_CQUOTE ; Output following string + .BYTE S_END1-S_START1 ; String length +S_START1: + .BYTE "* Z80 FORTH *" +S_END1: + .WORD C_FORTH + .WORD C_DEFINITIONS ; Set CURRENT as CONTEXT vocabulary + .WORD C_QUIT + +W_WARM: + .BYTE $84,"WAR",'M'+$80 + .WORD W_ABORT +C_WARM: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD WORD1 ; Start of detault table + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD S0 ; S0 addr + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD START_TABLE-WORD1 ; (000Ch) Table length + .WORD C_CMOVE ; Move block + .WORD C_ABORT + +X_COLD: + LD HL,START_TABLE ; Copy table to ram + LD DE,FLAST ; Where the table's going + LD BC,NEXTS2-START_TABLE ; Bytes to copy + LDIR ; + LD HL,W_TASK ; Copy TASK to ram + LD DE,VOCAB_BASE ; Where it's going + LD BC,W_TASKEND-W_TASK ; Bytes to copy + LDIR ; + LD BC,FIRSTWORD ; BC to first forth word + LD HL,(WORD1) ; Get stack pointer + LD SP,HL ; Set it + JP NEXT + +FIRSTWORD: + .WORD C_COLD + +W_COLD: .BYTE $84,"COL",'D'+$80 + .WORD W_WARM + .WORD X_COLD +C_COLD: .WORD E_COLON ; Interpret following word sequence + .WORD C_EBUFFERS ; Clear pseudo disk buffer + .WORD C_ZERO ; Put zero on stack + .WORD C_OFFSET ; Put disk block offset on stack + .WORD C_STORE ; Clear disk block offset + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD WORD1 ; Start of default table + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD S0 ; S0 addr + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD START_TABLE-WORD1 ; Block length on stack (0010h) + .WORD C_CMOVE ; Move block + .WORD C_ABORT + +W_SINGTODUB: ; Change single number to double + .BYTE $84,"S->",'D'+$80 + .WORD W_COLD +C_SINGTODUB: + .WORD 2+$ ; Vector to code + POP DE ; Get number + LD HL,$0000 ; Assume +ve extend + LD A,D ; Check sign + AND $80 ; + JR Z,IS_POS ; Really +ve so jump + DEC HL ; Make -ve extension +IS_POS: + JP NEXTS2 ; Save both & NEXT + +W_PLUSMINUS: + .BYTE $82,"+",'-'+$80 + .WORD W_SINGTODUB +C_PLUSMINUS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_0LESS ; Less than 0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B002D-$ ; 0004h + .WORD C_NEGATE ; Form 2s complement of n +B002D: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DPLUSMINUS: ; Add sign of n to double + .BYTE $83,"D+",'-'+$80 + .WORD W_PLUSMINUS +C_DPLUSMINUS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_0LESS ; Less than 0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B002E-$ ; 0004h + .WORD C_DNEGATE +B002E: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ABS: + .BYTE $83,"AB",'S'+$80 + .WORD W_DPLUSMINUS +C_ABS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate top value on stack + .WORD C_PLUSMINUS + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DABS: + .BYTE $84,"DAB",'S'+$80 + .WORD W_ABS +C_DABS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate top value on stack + .WORD C_DPLUSMINUS ; Add sign of n to double + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MIN: + .BYTE $83,"MI",'N'+$80 + .WORD W_DABS +C_MIN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_2DUP ; Dup top 2 values on stack + .WORD C_GREATER + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B002F-$ ; 0004h + .WORD C_SWAP ; Swap top 2 values on stack +B002F: + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MAX: + .BYTE $83,"MA",'X'+$80 + .WORD W_MIN +C_MAX: + .WORD E_COLON ; Interpret following word sequence + .WORD C_2DUP ; Dup top 2 values on stack + .WORD C_LESSTHAN + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0030-$ ; 0004h + .WORD C_SWAP ; Swap top 2 values on stack +B0030: + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MTIMES: + .BYTE $82,"M",'*'+$80 + .WORD W_MAX +C_MTIMES: + .WORD E_COLON ; Interpret following word sequence + .WORD C_2DUP ; Dup top 2 values on stack + .WORD C_XOR ; Works out sign of result + .WORD C_MOVER ; Move value from data to return stack + .WORD C_ABS + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_ABS + .WORD C_USTAR + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_DPLUSMINUS ; Add sign of n to double + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MDIV: + .BYTE $82,"M",'/'+$80 + .WORD W_MTIMES +C_MDIV: + .WORD E_COLON ; Interpret following word sequence + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_DABS + .WORD C_RFETCH ; Return stack top to data stack + .WORD C_ABS + .WORD C_UMOD ; Unsigned divide & MOD + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_RFETCH ; Return stack top to data stack + .WORD C_XOR ; XOR + .WORD C_PLUSMINUS + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_PLUSMINUS + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TIMES: + .BYTE $81,'*'+$80 + .WORD W_MDIV +C_TIMES: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MTIMES + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DIVMOD: + .BYTE $84,"/MO",'D'+$80 + .WORD W_TIMES +C_DIVMOD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_SINGTODUB ; Change single number to double + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_MDIV + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DIV: + .BYTE $81,'/'+$80 + .WORD W_DIVMOD +C_DIV: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DIVMOD + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MOD: + .BYTE $83,"MO",'D'+$80 + .WORD W_DIV +C_MOD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DIVMOD + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TIMESDIVMOD: + .BYTE $85,"*/MO",'D'+$80 + .WORD W_MOD +C_TIMESDIVMOD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_MTIMES + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_MDIV + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TIMESDIV: + .BYTE $82,"*",'/'+$80 + .WORD W_TIMESDIVMOD +C_TIMESDIV: + .WORD E_COLON ; Interpret following word sequence + .WORD C_TIMESDIVMOD + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MDIVMOD: + .BYTE $85,"M/MO",'D'+$80 + .WORD W_TIMESDIV +C_MDIVMOD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_ZERO ; Put zero on stack + .WORD C_RFETCH ; Return stack top to data stack + .WORD C_UMOD ; Unsigned divide & MOD + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_UMOD ; Unsigned divide & MOD + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CLINE: + .BYTE $86,"'+$80 + .WORD W_MDIVMOD +C_CLINE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_CL ; Put characters/line on stack + .WORD C_BBUF ; Put bytes per block on stack + .WORD C_TIMESDIVMOD + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_BSCR ; Number of buffers per block on stack + .WORD C_TIMES + .WORD C_PLUS ; n1 + n2 + .WORD C_BLOCK + .WORD C_PLUS ; n1 + n2 + .WORD C_CL ; Put characters/line on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DOTLINE: + .BYTE $85,".LIN",'E'+$80 + .WORD W_CLINE +C_DOTLINE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CLINE + .WORD C_TRAILING + .WORD C_TYPE ; Output n bytes from addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_MESSAGE: + .BYTE $87,"MESSAG",'E'+$80 + .WORD W_DOTLINE +C_MESSAGE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_WARNING ; Put WARNING addr on stack + .WORD C_FETCH ; Get WARNING value + .WORD C_0BRANCH ; If WARNING = 0 output MSG # n + .WORD B0031-$ ; 001Eh + .WORD C_QUERYDUP + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0032-$ ; 0014h + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0004 + .WORD C_OFFSET ; Put disk block offset on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_BSCR ; Number of buffers per block on stack + .WORD C_DIV + .WORD C_MINUS + .WORD C_DOTLINE ; Output line from screen + .WORD C_SPACE ; Output space + +B0032: .WORD C_BRANCH ; Add following offset to BC + .WORD B0033-$ ; 00$0D + +B0031: .WORD C_CQUOTE ; Output following string + .BYTE S_END2-S_START2 +S_START2: .BYTE "MSG # " +S_END2: .WORD C_DOT +B0033: .WORD C_STOP ; Pop BC from return stack (=next) + +W_PORTIN: ; Fetch data from port + .BYTE $82,"P",'@'+$80 + .WORD W_MESSAGE +C_PORTIN: + .WORD 2+$ ; Vector to code + POP DE ; Get port addr + LD HL,PAT+1 ; Save in port in code + LD (HL),E ; + CALL PAT ; Call port in routine + LD L,A ; Save result + LD H,$00 ; + JP NEXTS1 ; Save & NEXT + +W_PORTOUT: ; Save data to port + .BYTE $82,"P",'!'+$80 + .WORD W_PORTIN +C_PORTOUT: + .WORD 2+$ ; Vector to code + POP DE ; Get port addr + LD HL,PST+1 ; Save in port out code + LD (HL),E ; + POP HL ; + LD A,L ; Byte to A + CALL PST ; Call port out routine + JP NEXT + +W_USE: .BYTE $83,"US",'E'+$80 + .WORD W_PORTOUT +C_USE: .WORD X_USER ; Put next word on stack then do next + .WORD USE-SYSTEM + +W_PREV: .BYTE $84,"PRE",'V'+$80 + .WORD W_USE +C_PREV: .WORD X_USER ; Put next word on stack then do next + .WORD PREV-SYSTEM + +W_PLUSBUF: + .BYTE $84,"+BU",'F'+$80 + .WORD W_PREV +C_PLUSBUF: + .WORD NEXT + +W_UPDATE: + .BYTE $86,"UPDAT",'E'+$80 + .WORD W_PLUSBUF +C_UPDATE: + .WORD NEXT + +W_EBUFFERS: ; Clear pseudo disk buffer + .BYTE $8D,"EMPTY-BUFFER",'S'+$80 + .WORD W_UPDATE +C_EBUFFERS: + .WORD E_COLON ; Interpret following word sequence + .WORD C_FIRST ; Start of pseudo disk onto stack + .WORD C_LIMIT ; End of pseudo disk onto stack + .WORD C_OVER ; Start to top of stack + .WORD C_MINUS ; Work out buffer length + .WORD C_ERASE ; Fill addr & length from stack with 0 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BUFFER: + .BYTE $86,"BUFFE",'R'+$80 + .WORD W_EBUFFERS +C_BUFFER: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BLOCK + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BLOCK: ; Put address of block n (+ offset) on stack + .BYTE $85,"BLOC",'K'+$80 + .WORD W_BUFFER +C_BLOCK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD DISK_END/BLOCK_SIZE-DISK_START/BLOCK_SIZE + ; Max number of blocks + .WORD C_MOD ; MOD to max number + .WORD C_OFFSET ; Put address of disk block offset on stack + .WORD C_FETCH ; Get disk block offset + .WORD C_PLUS ; Add offset to block # + .WORD C_BBUF ; Put bytes per block on stack + .WORD C_TIMES ; Bytes times block number + .WORD C_FIRST ; Put address of first block on stack + .WORD C_PLUS ; Add address of first to byte offset + .WORD C_STOP ; Pop BC from return stack (=next) + +W_RW: + .BYTE $83,"R/",'W'+$80 + .WORD W_BLOCK +C_RW: + .WORD E_COLON ; Interpret following word sequence + .WORD C_URW ; + .WORD C_FETCH ; Get word from addr on stack + .WORD C_EXECUTE ; Jump to address on stack + .WORD C_STOP ; Pop BC from return stack (=next) +CF_URW: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DROP ; Drop top value from stack + .WORD C_DROP ; Drop top value from stack + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_FLUSH: + .BYTE $85,"FLUS",'H'+$80 + .WORD W_RW +C_FLUSH: + .WORD E_COLON ; Interpret following word sequence + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DUMP: + .BYTE $84,"DUM",'P'+$80 + .WORD W_FLUSH +C_DUMP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_LDO ; Put start & end loop values on RPP +B0051: + .WORD C_CR ; Output [CR][LF] + .WORD C_DUP ; Duplicate top value on stack + .WORD C_ZERO ; Put zero on stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0005h + .WORD C_DDOTR + .WORD C_SPACE ; Output space + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0004h + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_ZERO ; Put zero on stack + .WORD C_LDO ; Put start & end loop values on RPP +B0050: + .WORD C_DUP ; Duplicate top value on stack + .WORD C_CFETCH ; Get byte from addr on stack + .WORD C_3 + .WORD C_DOTR + .WORD C_1PLUS ; 1 plus + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD B0050-$ ; FFF4h + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_PLOOP ; Loop + stack & branch if not done + .WORD B0051-$ ; FFD4h + .WORD C_DROP ; Drop top value from stack + .WORD C_CR ; Output [CR][LF] + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LOAD: + .BYTE $84,"LOA",'D'+$80 + .WORD W_DUMP +C_LOAD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BLK ; Get current block number (0 = keyboard) + .WORD C_FETCH ; Get word from addr on stack + .WORD C_MOVER ; Save it for now + .WORD C_TOIN ; Current input buffer offset + .WORD C_FETCH ; Get word from addr on stack + .WORD C_MOVER ; Save it for now + .WORD C_ZERO ; Put zero on stack + .WORD C_TOIN ; Current input buffer offset + .WORD C_STORE ; Set to zero + .WORD C_BSCR ; Number of buffers per block on stack + .WORD C_TIMES ; Multiply block to load by buffers/block + .WORD C_BLK ; Get BLK pointer + .WORD C_STORE ; Make load block current input stream + .WORD C_INTERPRET ; Interpret input stream + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_TOIN ; Current input buffer offset + .WORD C_STORE ; Store word at addr + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_BLK ; Current block + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_NEXTSCREEN: + .BYTE $C3,"--",'>'+$80 + .WORD W_LOAD +C_NEXTSCREEN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QLOADING + .WORD C_ZERO ; Put zero on stack + .WORD C_TOIN ; Current input buffer offset + .WORD C_STORE ; Store word at addr + .WORD C_BSCR ; Number of buffers per block on stack + .WORD C_BLK + .WORD C_FETCH ; Get word from addr on stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_MOD + .WORD C_MINUS + .WORD C_BLK + .WORD C_PLUSSTORE ; Add n1 to addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TICK: + .BYTE $81,$2C+$80 + .WORD W_NEXTSCREEN +C_TICK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MFIND ; Find name returns PFA,length,true or false + .WORD C_0EQUALS ; =0 + .WORD C_ZERO ; Put zero on stack + .WORD C_QERROR + .WORD C_DROP ; Drop top value from stack + .WORD C_LITERAL + .WORD C_STOP ; Pop BC from return stack (=next) + +W_FORGET: + .BYTE $86,"FORGE",'T'+$80 + .WORD W_TICK +C_FORGET: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CURRENT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CONTEXT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_MINUS + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0018h + .WORD C_QERROR + .WORD C_TICK + .WORD C_DUP ; Duplicate top value on stack + .WORD C_FENCE + .WORD C_FETCH ; Get word from addr on stack + .WORD C_LESSTHAN + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0015h + .WORD C_QERROR + .WORD C_DUP ; Duplicate top value on stack + .WORD C_NFA ; Convert PFA to NFA + .WORD C_DP ; Dictionary pointer addr on stack + .WORD C_STORE ; Store word at addr + .WORD C_LFA + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CONTEXT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BACK: + .BYTE $84,"BAC",'K'+$80 + .WORD W_FORGET +C_BACK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_MINUS + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_STOP ; Pop BC from return stack (=next) + +W_BEGIN: + .BYTE $C5,"BEGI",'N'+$80 + .WORD W_BACK +C_BEGIN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QCOMP ; Error if not in compile mode + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_1 ; Put 1 on stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ENDIF: + .BYTE $C5,"ENDI",'F'+$80 + .WORD W_BEGIN +C_ENDIF: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QCOMP ; Error if not in compile mode + .WORD C_2 + .WORD C_QPAIRS + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_MINUS + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_THEN: + .BYTE $C4,"THE",'N'+$80 + .WORD W_ENDIF +C_THEN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ENDIF + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DO: + .BYTE $C2,"D",'O'+$80 + .WORD W_THEN +C_DO: + .WORD E_COLON ; Interpret following word sequence + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_LDO ; Put start & end loop values on RPP + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_3 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LOOP: + .BYTE $C4,"LOO",'P'+$80 + .WORD W_DO +C_LOOP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_3 + .WORD C_QPAIRS + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD C_BACK + .WORD C_STOP ; Pop BC from return stack (=next) + +W_PLUSLOOP: + .BYTE $C5,"+LOO",'P'+$80 + .WORD W_LOOP +C_PLUSLOOP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_3 + .WORD C_QPAIRS + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_PLOOP ; Loop + stack & branch if not done + .WORD C_BACK + .WORD C_STOP ; Pop BC from return stack (=next) + +W_UNTIL: + .BYTE $C5,"UNTI",'L'+$80 + .WORD W_PLUSLOOP +C_UNTIL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_1 ; Put 1 on stack + .WORD C_QPAIRS + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD C_BACK + .WORD C_STOP ; Pop BC from return stack (=next) + +W_END: + .BYTE $C3,"EN",'D'+$80 + .WORD W_UNTIL +C_END: + .WORD E_COLON ; Interpret following word sequence + .WORD C_UNTIL + .WORD C_STOP ; Pop BC from return stack (=next) + +W_AGAIN: + .BYTE $C5,"AGAI",'N'+$80 + .WORD W_END +C_AGAIN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_1 ; Put 1 on stack + .WORD C_QPAIRS + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_BRANCH ; Add following offset to BC + .WORD C_BACK + .WORD C_STOP ; Pop BC from return stack (=next) + +W_REPEAT: + .BYTE $C6,"REPEA",'T'+$80 + .WORD W_AGAIN +C_REPEAT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_AGAIN + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_2 + .WORD C_MINUS + .WORD C_ENDIF + .WORD C_STOP ; Pop BC from return stack (=next) + +W_IF: + .BYTE $C2,"I",'F'+$80 + .WORD W_REPEAT +C_IF: + .WORD E_COLON ; Interpret following word sequence + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_ZERO ; Put zero on stack + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_2 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ELSE: + .BYTE $C4,"ELS",'E'+$80 + .WORD W_IF +C_ELSE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_2 + .WORD C_QPAIRS + .WORD C_COMPILE ; Compile next word into dictionary + .WORD C_BRANCH ; Add following offset to BC + .WORD C_HERE ; Dictionary pointer onto stack + .WORD C_ZERO ; Put zero on stack + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_2 + .WORD C_ENDIF + .WORD C_2 + .WORD C_STOP ; Pop BC from return stack (=next) + +W_WHILE: .BYTE $C5,"WHIL",'E'+$80 + .WORD W_ELSE +C_WHILE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_IF + .WORD C_2PLUS ; 2 plus + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SPACES: + .BYTE $86,"SPACE",'S'+$80 + .WORD W_WHILE +C_SPACES: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_MAX + .WORD C_QUERYDUP + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0034-$ ; 000Ch + .WORD C_ZERO ; Put zero on stack + .WORD C_LDO ; Put start & end loop values on RPP +B0035: .WORD C_SPACE ; Output space + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD B0035-$ ; FFFCh +B0034: .WORD C_STOP ; Pop BC from return stack (=next) + +W_LESSHARP: + .BYTE $82,"<",'#'+$80 + .WORD W_SPACES +C_LESSHARP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_PAD ; Save intermediate string address + .WORD C_HLD + .WORD C_STORE ; Store word at addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SHARPGT: + .BYTE $82,"#",'>'+$80 + .WORD W_LESSHARP +C_SHARPGT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DROP ; Drop top value from stack + .WORD C_DROP ; Drop top value from stack + .WORD C_HLD + .WORD C_FETCH ; Get word from addr on stack + .WORD C_PAD ; Save intermediate string address + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_MINUS + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SIGN: + .BYTE $84,"SIG",'N'+$80 + .WORD W_SHARPGT +C_SIGN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ROT ; 3rd valu down to top of stack + .WORD C_0LESS ; Less than 0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0036-$ ; 0008h + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 002Dh + .WORD C_HOLD +B0036: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SHARP: + .BYTE $81,'#'+$80 + .WORD W_SIGN +C_SHARP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BASE ; Put BASE addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_MDIVMOD + .WORD C_ROT ; 3rd valu down to top of stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0009h + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_LESSTHAN + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0037-$ ; 0008h + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0007h + .WORD C_PLUS ; n1 + n2 +B0037: + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0030 + .WORD C_PLUS ; n1 + n2 + .WORD C_HOLD + .WORD C_STOP ; Pop BC from return stack (=next) + +W_SHARPS: + .BYTE $82,"#",'S'+$80 + .WORD W_SHARP +C_SHARPS: + .WORD E_COLON ; Interpret following word sequence +B0038: + .WORD C_SHARP + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_OR ; OR + .WORD C_0EQUALS ; =0 + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0038-$ ; FFF4h + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DDOTR: + .BYTE $83,"D.",'R'+$80 + .WORD W_SHARPS +C_DDOTR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_DABS + .WORD C_LESSHARP + .WORD C_SHARPS + .WORD C_SIGN + .WORD C_SHARPGT + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_OVER ; Copy 2nd down to top of stack + .WORD C_MINUS + .WORD C_SPACES + .WORD C_TYPE ; Output n bytes from addr + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DOTR: + .BYTE $82,".",'R'+$80 + .WORD W_DDOTR +C_DOTR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_SINGTODUB ; Change single number to double + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_DDOTR + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DDOT: + .BYTE $82,"D",'.'+$80 + .WORD W_DOTR +C_DDOT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_DDOTR + .WORD C_SPACE ; Output space + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DOT: + .BYTE $81,'.'+$80 + .WORD W_DDOT +C_DOT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_SINGTODUB ; Change single number to double + .WORD C_DDOT + .WORD C_STOP ; Pop BC from return stack (=next) + +W_QUESTION: + .BYTE $81,'?'+$80 + .WORD W_DOT +C_QUESTION: + .WORD E_COLON ; Interpret following word sequence + .WORD C_FETCH ; Get word from addr on stack + .WORD C_DOT + .WORD C_STOP ; Pop BC from return stack (=next) + +W_UDOT: ; Output as unsigned value + .BYTE $82,"U",'.'+$80 + .WORD W_QUESTION +C_UDOT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_DDOT ; Output double value + .WORD C_STOP ; Pop BC from return stack (=next) + +W_VLIST: + .BYTE $85,"VLIS",'T'+$80 + .WORD W_UDOT +C_VLIST: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CONTEXT ; Leave vocab pointer on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CR ; Output [CR][LF] +B0039: + .WORD C_DUP ; Duplicate top value on stack + .WORD C_PFA ; Convert NFA to PFA + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_ID ; Print definition name from name field addr + .WORD C_LFA ; Convert param addr to link addr + .WORD C_FETCH ; Get word from addr on stack + .WORD C_DUP ; Duplicate top value on stack + .WORD C_0EQUALS ; =0 + .WORD C_TERMINAL ; Check for break key + .WORD C_OR ; OR + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0039-$ ; FFE2h + .WORD C_DROP ; Drop top value from stack + .WORD C_CR ; Output [CR][LF] + .WORD C_STOP ; Pop BC from return stack (=next) + +W_LIST: + .BYTE $84,"LIS",'T'+$80 + .WORD W_VLIST +C_LIST: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BASE ; Put BASE addr on stack + .WORD C_FETCH ; Put current base on stack + .WORD C_SWAP ; Get number of list screen to top + .WORD C_DECIMAL ; Sets decimal mode + .WORD C_CR ; Output [CR][LF] + .WORD C_DUP ; Duplicate top value on stack + .WORD C_SCR ; Set most recently listed + .WORD C_STORE ; Store word at addr + .WORD C_CQUOTE ; Output following string + .BYTE S_END3-S_START3 +S_START3: + .BYTE "SCR # " +S_END3: + .WORD C_DOT ; Output the screen number + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0010 ; 16 lines to do + .WORD C_ZERO ; From 0 to 15 + .WORD C_LDO ; Put start & end loop values on RPP +DO_LINE: + .WORD C_CR ; Output [CR][LF] + .WORD C_I ; Line number onto data stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $0003 ; Fromat right justified 3 characters + .WORD C_DOTR ; Output formatted + .WORD C_SPACE ; Output space + .WORD C_I ; Line number onto data stack + .WORD C_SCR ; Get screen number + .WORD C_FETCH ; Get word from addr on stack + .WORD C_DOTLINE ; Output line from screen + .WORD C_TERMINAL ; Check for break key + .WORD C_0BRANCH ; Jump if no break key + .WORD NO_BRK-$ + .WORD C_LEAVE ; Else set loop index to limit (quit loop) +NO_BRK: + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD DO_LINE-$ + .WORD C_CR ; Output [CR][LF] + .WORD C_BASE ; Put BASE addr on stack + .WORD C_STORE ; Restore original base + .WORD C_STOP ; Pop BC from return stack (=next) + +W_INDEX: + .BYTE $85,"INDE",'X'+$80 + .WORD W_LIST +C_INDEX: + .WORD E_COLON ; Interpret following word sequence + .WORD C_1PLUS ; 1 plus + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_LDO ; Put start & end loop values on RPP +B003D: + .WORD C_CR ; Output [CR][LF] + .WORD C_I ; Copy LOOP index to data stack + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD 0003h + .WORD C_DOTR + .WORD C_SPACE ; Output space + .WORD C_ZERO ; Put zero on stack + .WORD C_I ; Copy LOOP index to data stack + .WORD C_DOTLINE ; Output line from screen + .WORD C_TERMINAL ; Check for break key + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B003C-$ ; 0004h + .WORD C_LEAVE ; Quit loop by making index = limit +B003C: + .WORD C_LLOOP ; Increment loop & branch if not done + .WORD B003D-$ ; FFE4h + .WORD C_CR ; Output [CR][LF] + .WORD C_STOP ; Pop BC from return stack (=next) + +W_INT: + .BYTE $C4,"; IN",'T'+$80 + .WORD W_INDEX +C_INT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_WHATSTACK ; Check stack pointer, error if not ok + .WORD C_COMPILE ; Compile next word into dictionary + .WORD X_INT + .WORD C_LEFTBRKT ; Set STATE to execute + .WORD C_SMUDGE + .WORD C_STOP ; Pop BC from return stack (=next) + +X_INT: + .WORD 2+$ ; Vector to code + LD HL,INTFLAG + RES 6,(HL) + EI + JP X_STOP + +W_INTFLAG: + .BYTE $87,"INTFLA",'G'+$80 + .WORD W_INT +C_INTFLAG: + .WORD X_USER ; Put next word on stack then do next + .WORD INTFLAG-SYSTEM + +W_INTVECT: + .BYTE $87,"INTVEC",'T'+$80 + .WORD W_INTFLAG +C_INTVECT: + .WORD X_USER ; Put next word on stack then do next + .WORD INTVECT-SYSTEM + +W_CPU: + .BYTE $84,".CP",'U'+$80 + .WORD W_INTVECT +C_CPU: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CQUOTE ; Output following string + .BYTE S_END4-S_START4 +S_START4: + .BYTE "Z80 " +S_END4: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_2SWAP: + .BYTE $85,"2SWA",'P'+$80 + .WORD W_CPU +C_2SWAP: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ROT ; 3rd valu down to top of stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_ROT ; 3rd valu down to top of stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_2OVER: + .BYTE $85,"2OVE",'R'+$80 + .WORD W_2SWAP +C_2OVER: + .WORD E_COLON ; Interpret following word sequence + .WORD C_MOVER ; Move value from data to return stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_2DUP ; Dup top 2 values on stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_2SWAP + .WORD C_STOP ; Pop BC from return stack (=next) + +W_EXIT: + .BYTE $84,"EXI",'T'+$80 + .WORD W_2OVER +C_EXIT: + .WORD X_STOP + +W_J: ; Push outer loop value on stack + .BYTE $81,'J'+$80 + .WORD W_EXIT +C_J: + .WORD 2+$ ; Vector to code + LD HL,(RPP) ; Get return stack pointer + INC HL ; Skip inner loop values + INC HL ; + INC HL ; + INC HL ; + JP X_I2 + +W_ROLL: + .BYTE $84,"ROL",'L'+$80 + .WORD W_J +C_ROLL: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate top value on stack + .WORD C_ZERO ; Put zero on stack + .WORD C_GREATER + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B003E-$ ; 002Ch + .WORD C_DUP ; Duplicate top value on stack + .WORD C_MOVER ; Move value from data to return stack + .WORD C_PICK + .WORD C_RMOVE ; Move word from return to data stack + .WORD C_ZERO ; Put zero on stack + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_LDO ; Put start & end loop values on RPP +B003F: + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_I ; Copy LOOP index to data stack + .WORD C_DUP ; Duplicate top value on stack + .WORD C_PLUS ; n1 + n2 + .WORD C_PLUS ; n1 + n2 + .WORD C_DUP ; Duplicate top value on stack + .WORD C_2MINUS ; 2 minus + .WORD C_FETCH ; Get word from addr on stack + .WORD C_SWAP ; Swap top 2 values on stack + .WORD C_STORE ; Store word at addr + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $FFFF + .WORD C_PLOOP ; Loop + stack & branch if not done + .WORD B003F-$ ; FFE6h +B003E: + .WORD C_DROP ; Drop top value from stack + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DEPTH: + .BYTE $85,"DEPT",'H'+$80 + .WORD W_ROLL +C_DEPTH: + .WORD E_COLON ; Interpret following word sequence + .WORD C_S0 ; Push S0 (initial data stack pointer) + .WORD C_FETCH ; Get word from addr on stack + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_MINUS + .WORD C_2 + .WORD C_DIV + .WORD C_1MINUS ; 1 minus + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DLESSTHAN: + .BYTE $82,"D",'<'+$80 + .WORD W_DEPTH +C_DLESSTHAN: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ROT ; 3rd valu down to top of stack + .WORD C_2DUP ; Dup top 2 values on stack + .WORD C_EQUALS + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0040-$ ; 00$0A + .WORD C_2DROP ; Drop top two values from stack + .WORD C_ULESS ; IF stack-1 < stack_top leave true flag + .WORD C_BRANCH ; Add following offset to BC + .WORD B0041-$ ; 0008h +B0040: + .WORD C_2SWAP + .WORD C_2DROP ; Drop top two values from stack + .WORD C_GREATER +B0041: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_0GREATER: + .BYTE $82,"0",'>'+$80 + .WORD W_DLESSTHAN +C_0GREATER: + .WORD E_COLON ; Interpret following word sequence + .WORD C_ZERO ; Put zero on stack + .WORD C_GREATER + .WORD C_STOP ; Pop BC from return stack (=next) + +W_DOTS: + .BYTE $82,".",'S'+$80 + .WORD W_0GREATER +C_DOTS + .WORD E_COLON ; Interpret following word sequence + .WORD C_CR ; Output [CR][LF] + .WORD C_DEPTH + .WORD C_0BRANCH ; Add offset to BC if stack top = 0 + .WORD B0042-$ ; 0020h + .WORD C_SPFETCH ; Stack pointer onto stack + .WORD C_2MINUS ; 2 minus + .WORD C_S0 ; Push S0 (initial data stack pointer) + .WORD C_FETCH ; Get word from addr on stack + .WORD C_2MINUS ; 2 minus + .WORD C_LDO ; Put start & end loop values on RPP +B0043: + .WORD C_I ; Copy LOOP index to data stack + .WORD C_FETCH ; Get word from addr on stack + .WORD C_DOT + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $FFFE + .WORD C_PLOOP ; Loop + stack & branch if not done + .WORD B0043-$ ; FFF4h + .WORD C_BRANCH ; Add following offset to BC + .WORD S_END5-$ ; 0011h +B0042: + .WORD C_CQUOTE ; Output following string + .BYTE S_END5-S_START5 +S_START5: + .BYTE "STACK EMPTY " +S_END5: + .WORD C_STOP ; Pop BC from return stack (=next) + +W_CODE: + .BYTE $84,"COD",'E'+$80 + .WORD W_DOTS +C_CODE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_QEXEC ; Error not if not in execute mode + .WORD C_XXX1 + .WORD C_SPSTORE ; Set initial stack pointer value + .WORD C_STOP ; Pop BC from return stack (=next) + +W_ENDCODE: + .BYTE $88,"END-COD",'E'+$80 + .WORD W_CODE +C_ENDCODE: + .WORD E_COLON ; Interpret following word sequence + .WORD C_CURRENT + .WORD C_FETCH ; Get word from addr on stack + .WORD C_CONTEXT + .WORD C_STORE ; Store word at addr + .WORD C_QEXEC ; Error not if not in execute mode + .WORD C_WHATSTACK ; Check stack pointer, error if not ok + .WORD C_SMUDGE + .WORD C_STOP ; Pop BC from return stack (=next) + +W_NEXT: + .BYTE $C4,"NEX",'T'+$80 + .WORD W_ENDCODE +C_NEXT: + .WORD E_COLON ; Interpret following word sequence + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD $00C3 ; Jump instruction + .WORD C_CCOMMA ; Save as 8 bit value + .WORD C_LIT ; Puts next 2 bytes on the stack + .WORD NEXT ; The address of NEXT + .WORD C_COMMA ; Reserve 2 bytes and save n + .WORD C_STOP ; Pop BC from return stack (=next) + +W_IM2: ; Set interrupt mode 2 + .BYTE $83,"IM",'2'+$80 + .WORD W_NEXT +C_IM2: + .WORD 2+$ ; Vector to code + IM 2 ; Mode 2 + JP NEXT + +W_IM1: ; Set interrupt mode 1 + .BYTE $83,"IM",'1'+$80 + .WORD W_IM2 +C_IM1: + .WORD 2+$ ; Vector to code + IM 1 ; Mode 1 + JP NEXT + +W_IM0: ; Set interrupt mode 0 + .BYTE $83,"IM",'0'+$80 + .WORD W_IM1 +C_IM0: + .WORD 2+$ ; Vector to code + IM 0 ; Mode 0 + JP NEXT + +W_DI: ; Disable interrupt + .BYTE $82,"D",'I'+$80 + .WORD W_IM0 +C_DI: + .WORD 2+$ ; Vector to code + DI ; Disable interrupt + JP NEXT + +W_EI: ; Enable interrupt + .BYTE $82,"E",'I'+$80 + .WORD W_DI +C_EI: + .WORD 2+$ ; Vector to code + EI ; Enable interrupt + JP NEXT + +W_MON: ; Jump to m/c monitor + .BYTE $83,"MO",'N'+$80 + .WORD W_EI +C_MON: + .WORD 2+$ + JP MONSTART + +W_LLOAD: + .BYTE $85,"LLOA",'D'+$80 + .WORD W_MON +C_LLOAD: + .WORD E_COLON ; Interpret following word sequence + .WORD C_BLOCK ; Get block address + .WORD C_LIT ; Enter loop with null + .WORD $0000 ; +LL_BEGIN: + .WORD C_DUP ; Dup key + .WORD C_0BRANCH ; If null then don't store + .WORD LL_NULL-$ + .WORD C_DUP ; Dup key again + .WORD C_LIT ; Compare to [CR] + .WORD $000D ; + .WORD C_EQUALS + .WORD C_0BRANCH ; If not [CR] then jump + .WORD LL_STORE-$ ; + .WORD C_DROP ; Drop the [CR] + .WORD C_CL ; Get characters per line + .WORD C_PLUS ; Add to current addr + .WORD C_CL ; Make CL MOD value + .WORD C_NEGATE ; Form 2s complement of n + .WORD C_AND ; Mask out bits + .WORD C_BRANCH ; Done this bit so jump + .WORD NO_STORE-$ +LL_STORE: + .WORD C_OVER ; Get address to store at + .WORD C_STORE ; Save chr +NO_STORE: + .WORD C_1PLUS ; Next addres + .WORD C_BRANCH ; Done so jump + .WORD LL_CHAR-$ +LL_NULL: + .WORD C_DROP ; Was null so drop it +LL_CHAR: + .WORD C_KEY ; Get key + .WORD C_DUP ; Duplicate it + .WORD C_LIT ; Compare with [CTRL] Z + .WORD $001A + .WORD C_EQUALS + .WORD C_0BRANCH ; If not EOF then jump + .WORD LL_BEGIN-$ ; + .WORD C_DROP ; Drop EOF character + .WORD C_DROP ; Drop next address + .WORD C_STOP ; Pop BC from return stack (=next) + +W_TASK: + .BYTE $84,"TAS",'K'+$80 + .WORD W_LLOAD +C_TASK: + .WORD E_COLON ; Interpret following word sequence + .WORD C_STOP ; Pop BC from return stack (=next) +W_TASKEND: + +W_EDITI: + +W_CLEAR: ; Clear block n + .BYTE $85,"CLEA",'R'+$80 + .WORD W_TASK +C_CLEAR: + .WORD E_COLON ; Interpret following word sequence + .WORD C_DUP ; Duplicate number + .WORD C_SCR ; Get SCR addr + .WORD C_STORE ; Store screen number + .WORD C_BLOCK ; Get the address of the block + .WORD C_BBUF ; Put number of bytes/block on stack + .WORD C_ERASE ; Clear the block + .WORD C_STOP ; Pop BC from return stack (=next) + +CF_UKEY: ; Get key onto stack + .WORD 2+$ ; Vector to code + CALL CHR_RD ; User key in routine + LD L,A ; Put key on stack + LD H,$00 ; + JP NEXTS1 ; Save & NEXT + +CF_UEMIT: ; Chr from stack to output + .WORD 2+$ ; Vector to code + POP HL ; Get CHR to output + LD A,L ; Put in A + PUSH BC ; Save regs + PUSH DE ; + CALL CHR_WR ; User output routine + POP DE ; Restore regs + POP BC ; + JP NEXT ; + +CF_UCR: ; CR output + .WORD 2+$ ; Vector to code + PUSH BC ; Save regs + PUSH DE ; Just in case + LD A,$0D ; Carrage return + CALL CHR_WR ; User output routine + LD A,$0A ; Line feed + CALL CHR_WR ; User output routine + POP DE ; Get regs back + POP BC ; + JP NEXT ; Next + +CF_UQTERMINAL: ; Test for user break + .WORD 2+$ ; Vector to code + PUSH BC ; Save regs + PUSH DE ; Just in case + CALL BREAKKEY ; User break test routine + POP DE ; Get regs back + POP BC ; + LD H,$00 ; Clear H + LD L,A ; Result in L + JP NEXTS1 ; Store it & Next + +;------------------------------------------------------------------------------ +; SERIAL I/O ROUTINES +; Change these to suit your target system ..... +;------------------------------------------------------------------------------ +;------------------------------------------------------------------------------ +; RXA - Receive a byte over SIO/0 Ch A +;------------------------------------------------------------------------------ +RXA CALL CKSIOA ; Get the status word + JR NC,RXA ; Loop until a character arrives + IN A,($74) ; Get the character + RET ; Char ready in A +;------------------------------------------------------------------------------ +; TXA - Transmit a byte over SIO/0 Ch A +;------------------------------------------------------------------------------ +TXA PUSH AF ; Store character + CALL CKSIOA ; See if SIO channel A is finished transmitting + JR Z,TXA+1 ; Loop until SIO flag signals ready + POP AF ; Retrieve character + OUT ($74),A ; Output the character + RET +;------------------------------------------------------------------------------ +; Check SIO Channel A status flag, RX char ready=CY, TX buffer clear=NZ +;------------------------------------------------------------------------------ +CKSIOA XOR A ; Zeroize A + OUT ($76),A ; Select Register 0 + IN A,($76) ; Retrieve Status Word + RRCA ; RX status into CY flag + BIT 1,A ; TX Buffer Empty into Z flag + RET +;------------------------------------------------------------------------------ +CHR_RD: CALL RXA ; GET A CHARACTER + CP $61 ; Is UCASE already? + JR C,CHR_RD1 ; It is, leave it alone + CP $7A ; <= "z" ? + JR NC,CHR_RD1 ; + AND $5F ; It's A-Z, or a-z make it upper case +CHR_RD1 RET + +NO_BUF_KEY: + JP RXA ; GET A CHARACTER + +BREAKKEY: CALL CKSIOA ; CHECK USART + JR NC,NO_KEY ; NOTHING + IN A,($74) ; READ THE CHARACTER + CP $03 ; BREAK? + JR Z,WAS_BRK ; YES + CP $61 ; Is UCASE already? + JR C,BRK01 ; It is, leave it alone + CP $7A ; <= "z" ? + JR NC,BRK01 + AND $5F ; It's A-Z, or a-z make it upper case +BRK01 RET ; ELSE RETURN WITH KEY + +NO_KEY: XOR A ; Wasn't break, or no key, so clear + RET + +WAS_BRK: LD A,$01 ; Was break so set flag + RET + +CHR_WR: RST 08H ; WRITE CHARACTER + RET +;------------------------------------------------------------------------------ +FINIS .END +_forth_end:: + .area _CODE + .area _CABS diff --git a/doug/src/hc-old.arf b/doug/src/hc-old.arf new file mode 100755 index 00000000..3370ec02 --- /dev/null +++ b/doug/src/hc-old.arf @@ -0,0 +1,13 @@ +-mjx +-i homecomp.ihx +-k /usr/local/share/sdcc/lib/z80 +-l z80 +-b _CCPB03 = 0x0900 +-b _BDOSB01 = 0xD800 +-b _CBIOS = 0xE600 +-b _DBGMON = 0x0200 +loaderhc.rel +dbgmon.rel +ccpb03.rel +bdosb01.rel +cbios.rel diff --git a/doug/src/jrcb2h.c b/doug/src/jrcb2h.c new file mode 100755 index 00000000..5b8bebd2 --- /dev/null +++ b/doug/src/jrcb2h.c @@ -0,0 +1,528 @@ +/* hex2bin.c -- yet another reader and writer of Intel hex files + Copyright (C) 2011 John R Coffman . +*********************************************************************** + When invoked as 'hex2bin' read a sequence of Intel hex files + and create an overlaid binary file. + + When invoked as 'bin2hex' read a binary file and create an + Intel hex file. + + All command line numeric constants may be specified in any + radix. +*********************************************************************** + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + in the file COPYING in the distribution directory along with this + program. If not, see . + +**********************************************************************/ +#include +#include +#include +#include "jrctypes.h" + +#define true 1 +#define false 0 +#define SEG_MASK 0x00FFFFu +#define LBA_MASK 0x00FF0000ul +#define MAX_MASK (LBA_MASK|SEG_MASK) +#define ONE_MEG 0x100000ul + +dword upper_lba = 0; /* upper address */ +dword address_mask = SEG_MASK; /* address mask */ +byte pad = 0xFF; +byte *buffer; +dword rom_size = 0; +dword overwrite; /* count of possible overwrites */ +byte h2b, verbose; +char *outfilename = NULL; +char *binfilename = NULL; +dword source_address, source_limit; +dword dest_address, dest_limit; +FILE *infile; +FILE *outfile; +byte checksum; +char line[1024]; +char *lp; +long int lineno; + + + +dword convert_constant(char *str) +{ + char *final; + dword value = strtoul(str, &final, 0); + + if (*final == 'k' || *final == 'K') value *= 1024ul; + else if (*final == 'M' || *final == 'm') value *= ONE_MEG; + + return value; +} + +void error(byte level, char *msg) +{ + printf("%s(%d): %s\n", + level>1 ? "Error" : "Warning", (int)level, msg); + if (level>1) exit(level); + else if (level==0) printf("line %ld %s", lineno, line); +} + + +int getnibble(void) +{ + char ch; + + if (lp) { + ch = *lp++; + if (ch>='0' && ch<='9') ch -= '0'; + else if (ch>='A' && ch<='F') ch -= 'A'-10; + else if (ch>='a' && ch<='f') ch -= 'a'-10; + else { + error(0,"Illegal hex digit"); + ch = -1; + } + } + else error(0,"Line is too short"); + return (int)ch; +} + +int getbyte(void) +{ + int b = getnibble(); + b <<= 4; + b += getnibble(); + checksum += b; + return b; +} + +int getword(void) +{ + int w = getbyte(); + w <<= 8; + w += getbyte(); + return w; +} + +dword getdword(void) +{ + dword d = getword(); + d <<= 16; + d += getword(); + return d; +} + + +void putbyte(dword address, byte data) +{ + if (address < source_address || address > source_limit) return; + address -= source_address; + address += dest_address; + if (address > dest_limit) return; + if (address >= rom_size) { + printf("Line %ld ",lineno); error(2,"Data beyond end of ROM"); + } + if (buffer[address] != pad) { + overwrite++; + if (verbose || overwrite<=100) printf("Warning(1): Overwrite at ROM address 0x%lX\n", address); + } + buffer[address] = data; +} + + +void usage(void) +{ + printf("hex2bin.c (bin2hex) -- " __DATE__ " " __TIME__ ".\n" + "Copyright (c) 2011 John R Coffman. All rights reserved.\n" + "Distributed under the GNU General Public License, a copy of which\n" + "is contained in the file COPYING in the distribution directory.\n\n"); + if (h2b) printf( + "Usage:\n" + " hex2bin [ ]+\n\n" + " Options:\n" + " -o \n" + " -p \n" + " -R default 64K\n" + " -v []\n" + " Flags:\n" + " -d \n" + " -D \n" + " -s \n" + " -S \n" + ); + else printf( + "Usage:\n" + " bin2hex [ ]+\n\n" + " Options:\n" + " -o \n" + " -p \n" + " -R default 1024K\n" + " -v []\n" + " Flags:\n" + " -d \n" + " -D \n" + " -s \n" + " -S \n" + ); +} + + +void hout_byte(byte data) +{ + checksum -= data; + fprintf(outfile, "%02X", (int)data); +} +void hout_word(word data) +{ + hout_byte(data>>8); + hout_byte(data); +} +void begin_record(byte length) +{ + checksum = 0; + fputc(':', outfile); + hout_byte(length); +} +void end_record(void) +{ + hout_byte(checksum); + fputc('\n', outfile); +} + +void write_lba(dword address) +{ + if (verbose==5) printf("Address: %06lX\n", address); + + if ((address & LBA_MASK) != upper_lba) { + upper_lba = address & LBA_MASK; + begin_record(2); + hout_word(0); + if (rom_size > ONE_MEG) { + hout_byte(4); /* linear address */ + hout_word(upper_lba>>16); + } + else { /* handle ROMs 1meg and smaller */ + hout_byte(2); /* segment address */ + hout_word(upper_lba>>4); + } + end_record(); + } +} + +void write_data(word nbytes, byte *buf, dword address) +{ + /* compress from the high end */ + while (nbytes && buf[nbytes-1]==pad) --nbytes; + /* compress from the low end */ + while (nbytes && *buf==pad) { + ++buf; + ++address; + --nbytes; + } + if (nbytes) { + write_lba(address); + begin_record(nbytes); + hout_word(address & 0xFFFFu); + hout_byte(0); /* data record */ + while(nbytes--) hout_byte(*buf++); + end_record(); + } +} + +#define min(a,b) ((a)<(b)?(a):(b)) +#define NREC 16 + +void write_hex_file(FILE *outfile) +{ + dword nbytes; + dword vaddr; + dword n; + byte *buf; + + buf = buffer; + vaddr = 0; + nbytes = rom_size; + n = min(nbytes, NREC); + do { + write_data(n, buf, vaddr); + buf += n; + vaddr += n; + nbytes -= n; + n = min(nbytes, NREC); + } while (n); +/* write the end-of-file record */ + fprintf(outfile,":00000001FF\n"); +} + + +void scan_bin_file(char *filename) +{ + dword length; + dword nbytes; + int data; + dword inaddr; + + infile = fopen(filename, "rb"); + if (!infile) { + strcpy(line,"Cannot find file: "); + error(5, strcat(line, filename)); + } + + fseek(infile,0L,SEEK_END); + length = ftell(infile); + +// length = filelength(fileno(infile)); + + nbytes = 0; + inaddr = dest_address; + if (source_address < length) { + fseek(infile, source_address, SEEK_SET); + while (inaddr=3) printf("%s", lp-1); + checksum = 0; + ldata = getbyte(); + laddr = getword(); + rectype = getbyte(); + switch (rectype) { + case 0: /* data record */ + index = 0; + while (ldata--) { + data = getbyte(); + putbyte(upper_lba + ((laddr + index)&address_mask), data); + index++; + } + break; + case 1: /* end of file record */ + EndOfFile = 1; + break; + case 2: /* segment address */ + address_mask = SEG_MASK; + value = getword(); + upper_lba = value<<4; /* start of segment */ + ldata -= 2; + break; + case 4: /* linear upper address */ + address_mask = MAX_MASK; + value = getword(); + upper_lba = value<<16; /* full 32-bit address range */ + ldata -= 2; + break; + case 3: /* start CS:IP */ + case 5: /* linear start address */ + value = getdword(); + ldata -= 4; + default: + error(0,"Unknown record type:"); + } + getbyte(); /* get final checksum */ + if (checksum) { + error(0,"Checksum failure"); + } + } while (lp && !EndOfFile); + fclose(infile); +} + + +void global_options(int argc, char *argv[]) +{ + int iarg; + char *cp; + char *tp; + char ch; + + h2b = false; + rom_size = ONE_MEG; /* bin2hex default value */ +/* decide which conversion to do */ + if (strstr(argv[0],"hex2bin") +#ifdef MSDOS + || strstr(argv[0],"HEX2BIN") +#endif + ) { + h2b = true; + rom_size = 64 * 1024ul; /* default value */ + } /* assume 'bin2hex' otherwise */ + + if (argc<2) { usage(); exit(0); } + +/* scan the global command line options */ + for (iarg = 0; iarg MAX_MASK+1) error(5, "ROM size too big"); + if (rom_size < 256) error(5, "ROM size too small"); + *cp = *tp = 0; + break; + case 'v': /* print verbose statistics */ + verbose++; + if (!*tp) tp = argv[++iarg]; + if (*tp>='1' && *tp<='5' && tp[1]==0) verbose += (*tp - '1'); + else tp = cp; + *cp = *tp = 0; + break; + case 'Y': { + int i; + for (i=0; i. +*********************************************************************** + When invoked as 'hex2bin' read a sequence of Intel hex files + and create an overlaid binary file. + + When invoked as 'bin2hex' read a binary file and create an + Intel hex file. + + All command line numeric constants may be specified in any + radix. +*********************************************************************** + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + in the file COPYING in the distribution directory along with this + program. If not, see . + +**********************************************************************/ +#include +#include +#include +#include "jrctypes.h" + +#define true 1 +#define false 0 +#define SEG_MASK 0x00FFFFu +#define LBA_MASK 0x00FF0000ul +#define MAX_MASK (LBA_MASK|SEG_MASK) +#define ONE_MEG 0x100000ul + +dword upper_lba = 0; /* upper address */ +dword address_mask = SEG_MASK; /* address mask */ +byte pad = 0xFF; +byte *buffer; +dword rom_size = 0; +dword overwrite; /* count of possible overwrites */ +byte h2b, verbose; +char *outfilename = NULL; +char *binfilename = NULL; +dword source_address, source_limit; +dword dest_address, dest_limit; +FILE *infile; +FILE *outfile; +byte checksum; +char line[1024]; +char *lp; +long int lineno; + + + +dword convert_constant(char *str) +{ + char *final; + dword value = strtoul(str, &final, 0); + + if (*final == 'k' || *final == 'K') value *= 1024ul; + else if (*final == 'M' || *final == 'm') value *= ONE_MEG; + + return value; +} + +void error(byte level, char *msg) +{ + printf("%s(%d): %s\n", + level>1 ? "Error" : "Warning", (int)level, msg); + if (level>1) exit(level); + else if (level==0) printf("line %ld %s", lineno, line); +} + + +int getnibble(void) +{ + char ch; + + if (lp) { + ch = *lp++; + if (ch>='0' && ch<='9') ch -= '0'; + else if (ch>='A' && ch<='F') ch -= 'A'-10; + else if (ch>='a' && ch<='f') ch -= 'a'-10; + else { + error(0,"Illegal hex digit"); + ch = -1; + } + } + else error(0,"Line is too short"); + return (int)ch; +} + +int getbyte(void) +{ + int b = getnibble(); + b <<= 4; + b += getnibble(); + checksum += b; + return b; +} + +int getword(void) +{ + int w = getbyte(); + w <<= 8; + w += getbyte(); + return w; +} + +dword getdword(void) +{ + dword d = getword(); + d <<= 16; + d += getword(); + return d; +} + + +void putbyte(dword address, byte data) +{ + if (address < source_address || address > source_limit) return; + address -= source_address; + address += dest_address; + if (address > dest_limit) return; + if (address >= rom_size) { + printf("Line %ld ",lineno); error(2,"Data beyond end of ROM"); + } + if (buffer[address] != pad) { + overwrite++; + if (verbose || overwrite<=100) printf("Warning(1): Overwrite at ROM address 0x%lX\n", address); + } + buffer[address] = data; +} + + +void usage(void) +{ + printf("hex2bin.c (bin2hex) -- " __DATE__ " " __TIME__ ".\n" + "Copyright (c) 2011 John R Coffman. All rights reserved.\n" + "Distributed under the GNU General Public License, a copy of which\n" + "is contained in the file COPYING in the distribution directory.\n\n"); + if (h2b) printf( + "Usage:\n" + " hex2bin [ ]+\n\n" + " Options:\n" + " -o \n" + " -p \n" + " -R default 64K\n" + " -v []\n" + " Flags:\n" + " -d \n" + " -D \n" + " -s \n" + " -S \n" + ); + else printf( + "Usage:\n" + " bin2hex [ ]+\n\n" + " Options:\n" + " -o \n" + " -p \n" + " -R default 1024K\n" + " -v []\n" + " Flags:\n" + " -d \n" + " -D \n" + " -s \n" + " -S \n" + ); +} + + +void hout_byte(byte data) +{ + checksum -= data; + fprintf(outfile, "%02X", (int)data); +} +void hout_word(word data) +{ + hout_byte(data>>8); + hout_byte(data); +} +void begin_record(byte length) +{ + checksum = 0; + fputc(':', outfile); + hout_byte(length); +} +void end_record(void) +{ + hout_byte(checksum); + fputc('\n', outfile); +} + +void write_lba(dword address) +{ + if (verbose==5) printf("Address: %06lX\n", address); + + if ((address & LBA_MASK) != upper_lba) { + upper_lba = address & LBA_MASK; + begin_record(2); + hout_word(0); + if (rom_size > ONE_MEG) { + hout_byte(4); /* linear address */ + hout_word(upper_lba>>16); + } + else { /* handle ROMs 1meg and smaller */ + hout_byte(2); /* segment address */ + hout_word(upper_lba>>4); + } + end_record(); + } +} + +void write_data(word nbytes, byte *buf, dword address) +{ + /* compress from the high end */ + while (nbytes && buf[nbytes-1]==pad) --nbytes; + /* compress from the low end */ + while (nbytes && *buf==pad) { + ++buf; + ++address; + --nbytes; + } + if (nbytes) { + write_lba(address); + begin_record(nbytes); + hout_word(address & 0xFFFFu); + hout_byte(0); /* data record */ + while(nbytes--) hout_byte(*buf++); + end_record(); + } +} + +#define min(a,b) ((a)<(b)?(a):(b)) +#define NREC 16 + +void write_hex_file(FILE *outfile) +{ + dword nbytes; + dword vaddr; + dword n; + byte *buf; + + buf = buffer; + vaddr = 0; + nbytes = rom_size; + n = min(nbytes, NREC); + do { + write_data(n, buf, vaddr); + buf += n; + vaddr += n; + nbytes -= n; + n = min(nbytes, NREC); + } while (n); +/* write the end-of-file record */ + fprintf(outfile,":00000001FF\n"); +} + + +void scan_bin_file(char *filename) +{ + dword length; + dword nbytes; + int data; + dword inaddr; + + infile = fopen(filename, "rb"); + if (!infile) { + strcpy(line,"Cannot find file: "); + error(5, strcat(line, filename)); + } + + fseek(infile,0L,SEEK_END); + length = ftell(infile); + +// length = filelength(fileno(infile)); + + nbytes = 0; + inaddr = dest_address; + if (source_address < length) { + fseek(infile, source_address, SEEK_SET); + while (inaddr=3) printf("%s", lp-1); + checksum = 0; + ldata = getbyte(); + laddr = getword(); + rectype = getbyte(); + switch (rectype) { + case 0: /* data record */ + index = 0; + while (ldata--) { + data = getbyte(); + putbyte(upper_lba + ((laddr + index)&address_mask), data); + index++; + } + break; + case 1: /* end of file record */ + EndOfFile = 1; + break; + case 2: /* segment address */ + address_mask = SEG_MASK; + value = getword(); + upper_lba = value<<4; /* start of segment */ + ldata -= 2; + break; + case 4: /* linear upper address */ + address_mask = MAX_MASK; + value = getword(); + upper_lba = value<<16; /* full 32-bit address range */ + ldata -= 2; + break; + case 3: /* start CS:IP */ + case 5: /* linear start address */ + value = getdword(); + ldata -= 4; + default: + error(0,"Unknown record type:"); + } + getbyte(); /* get final checksum */ + if (checksum) { + error(0,"Checksum failure"); + } + } while (lp && !EndOfFile); + fclose(infile); +} + + +void global_options(int argc, char *argv[]) +{ + int iarg; + char *cp; + char *tp; + char ch; + + h2b = false; + rom_size = ONE_MEG; /* bin2hex default value */ +/* decide which conversion to do */ + if (strstr(argv[0],"hex2bin") +#ifdef MSDOS + || strstr(argv[0],"HEX2BIN") +#endif + ) { + h2b = true; + rom_size = 64 * 1024ul; /* default value */ + } /* assume 'bin2hex' otherwise */ + + if (argc<2) { usage(); exit(0); } + +/* scan the global command line options */ + for (iarg = 0; iarg MAX_MASK+1) error(5, "ROM size too big"); + if (rom_size < 256) error(5, "ROM size too small"); + *cp = *tp = 0; + break; + case 'v': /* print verbose statistics */ + verbose++; + if (!*tp) tp = argv[++iarg]; + if (*tp>='1' && *tp<='5' && tp[1]==0) verbose += (*tp - '1'); + else tp = cp; + *cp = *tp = 0; + break; + case 'Y': { + int i; + for (i=0; i +#include +#include + +int main(int argc,char **argv) +{ + char szTemp[128]; + int index; + + strcpy(szTemp,argv[1]); + for(index=0;index +#include +#include + +int main(int argc,char **argv) +{ + char szTemp[128]; + int index; + + strcpy(szTemp,argv[1]); + for(index=0;index +#include +#include + +int main(int argc,char **argv) +{ + char szTemp[128]; + int index; + + strcpy(szTemp,argv[1]); + for(index=0;index +#include +#include + +int main(int argc,char **argv) +{ + char szTemp[128]; + int index; + + strcpy(szTemp,argv[1]); + for(index=0;index2) { + printf(" "); + strcpy(szTemp,argv[2]); + for(index=0;index3) { + printf(" "); + strcpy(szTemp,argv[3]); + for(index=0;index4) { + printf(" "); + strcpy(szTemp,argv[4]); + for(index=0;index +#include +#include + +int main(int argc,char **argv) +{ + char szTemp[128]; + int index; + + strcpy(szTemp,argv[1]); + for(index=0;index. +// + +#include +#include +#include + +#define DATA_RECORD 0x00 +#define EOF_RECORD 0x01 + +int main(int argc,char **argv) +{ + FILE * fcom, * fhex; + char g_szBuffer2[128]; + char szByteBuffer[2+1]; + char *p; + int iTemp; + + char cColon; + + char szLength[2+1]; + int iLength; + + char szAddress[4+1]; + unsigned int uiAddress; + + char szRecordType[2+1]; + unsigned char ucRecordType; + + char szData[80]; + unsigned char ucBinBuffer[32+1]; + + char szChecksum[2+1]; + unsigned char ucChecksum; + + unsigned int uiLastByte = 0; + + char szComFile[255]; + char szHexFile[255]; + int i; + + unsigned char memory[0xfff0]; + + if(1 == argc) { + printf("usage - load \n"); + exit(EXIT_FAILURE); + } + + strcpy(szHexFile,argv[1]); + strcpy(szComFile,argv[1]); + + strcat(szComFile,".com"); + strcat(szHexFile,".hex"); + + memset(memory,0,sizeof(memory)); + + fhex = fopen(szHexFile,"r"); + if(NULL == fhex) { + printf("Sorry, cannot open %s for input\n",szHexFile); + exit(EXIT_FAILURE); + } + p = fgets(g_szBuffer2,sizeof(g_szBuffer2),fhex); + while(NULL != p) { + g_szBuffer2[strlen(g_szBuffer2)-1] = 0; + cColon = g_szBuffer2[0]; + + memset(szLength,0,sizeof(szLength)); + memcpy(szLength,&g_szBuffer2[1],2); + sscanf(szLength,"%02X",&iLength); + + memset(szAddress,0,sizeof(szAddress)); + memcpy(szAddress,&g_szBuffer2[3],4); + sscanf(szAddress,"%04X",&uiAddress); + + memset(szRecordType,0,sizeof(szRecordType)); + memcpy(szRecordType,&g_szBuffer2[7],2); + + sscanf(szRecordType,"%02X",&iTemp); + ucRecordType = (unsigned char)iTemp; + + if(0 == ucRecordType) { + memset(szData,0,sizeof(szData)); + memcpy(szData,&g_szBuffer2[9],iLength*2); + for(i=0;i +#include +#include +#include "portab.h" +#include "scsi2ide.h" +#include "ns16550.h" + + +/* THESE ARE USED BY THE LIBRARY ROUTINES */ +char get_char(void) +{ + while(UART_RDA & rUART_LSR) ; + return rUART_RDR; +} +void out_char(char c) +{ + while(UART_TBE & rUART_LSR) ; + wUART_TDR = c; +} + + +void xdisable(void) +{ +} + +void xenable(void) +{ +} + +void intmode(U8 xmode) +{ + if(xmode); +} + +int main(void) +{ + /* uart init must be done before library + uses input or output primitives */ + wUART_LCR = UART_DLAB; + wUART_DIV_HI = 0; + wUART_DIV_LO = 12; /* 9600 baud */ + wUART_LCR = 0x03; /* 8N1 */ + wUART_MCR = 0x03; + + + printf("\nN8VEM SCSI2IDE-0111 %s Dated %s %s\n", + __FILE__,__DATE__,__TIME__); + + printf("\nmain() completed\n"); + + return (0); +} + diff --git a/doug/src/sdcc.man b/doug/src/sdcc.man new file mode 100644 index 00000000..bc405a00 --- /dev/null +++ b/doug/src/sdcc.man @@ -0,0 +1,170 @@ +SDCC : mcs51/gbz80/z80/ds390/TININative/ds400/hc08 3.0.2 #6489 (May 10 2011) (Mac OS X x86_64) +Usage : sdcc [options] filename +Options :- + +General options: + --help Display this help + -v --version Display sdcc's version + --verbose Trace calls to the preprocessor, assembler, and linker + -V Execute verbosely. Show sub commands as they are run + -d + -D Define macro as in -Dmacro + -I Add to the include (*.h) path, as in -Ipath + -A + -U + -M Preprocessor option + -W Pass through options to the pre-processor (p), assembler (a) or linker (l) + -S Compile only; do not assemble or link + -c --compile-only Compile and assemble, but do not link + -E --preprocessonly Preprocess only, do not compile + --c1mode Act in c1 mode. The standard input is preprocessed code, the output is assembly code. + -o Place the output into the given path resp. file + --print-search-dirs display the directories in the compiler's search path + --vc messages are compatible with Micro$oft visual studio + --use-stdout send errors to stdout instead of stderr + --nostdlib Do not include the standard library directory in the search path + --nostdinc Do not include the standard include directory in the search path + --less-pedantic Disable some of the more pedantic warnings + --disable-warning Disable specific warning + --Werror Treat the warnings as errors + --debug Enable debugging symbol output + --cyclomatic Display complexity of compiled functions + --std-c89 Use C89 standard only + --std-sdcc89 Use C89 standard with SDCC extensions (default) + --std-c99 Use C99 standard only (incomplete) + --std-sdcc99 Use C99 standard with SDCC extensions (incomplete) + --fdollars-in-identifiers Permit '$' as an identifier character + --funsigned-char Make "char" unsigned by default + --use-non-free Search / include non-free licensed libraries and header files + +Code generation options: + -m Set the port to use e.g. -mz80. + -p Select port specific processor e.g. -mpic14 -p16f84 + --model-small internal data space is used (default) + --model-medium external paged data space is used + --model-large external data space is used + --model-huge functions are banked, data in external space + --stack-auto Stack automatic variables + --xstack Use external stack + --int-long-reent Use reentrant calls on the int and long support functions + --float-reent Use reentrant calls on the float support functions + --main-return Issue a return after main() + --xram-movc Use movc instead of movx to read xram (xdata) + --callee-saves Cause the called function to save registers instead of the caller + --profile On supported ports, generate extra profiling information + --fomit-frame-pointer Leave out the frame pointer. + --all-callee-saves callee will always save registers used + --stack-probe insert call to function __stack_probe at each function prologue + --no-xinit-opt don't memcpy initialized xram from code + --no-c-code-in-asm don't include c-code as comments in the asm file + --no-peep-comments don't include peephole optimizer comments + --fverbose-asm include code generator comments + --short-is-8bits Make short 8 bits (for old times sake) + --codeseg use this name for the code segment + --constseg use this name for the const segment + +Optimization options: + --nooverlay Disable overlaying leaf function auto variables + --nogcse Disable the GCSE optimisation + --nolabelopt Disable label optimisation + --noinvariant Disable optimisation of invariants + --noinduction Disable loop variable induction + --nojtbound Don't generate boundary check for jump tables + --noloopreverse Disable the loop reverse optimisation + --no-peep Disable the peephole assembly file optimisation + --no-reg-params On some ports, disable passing some parameters in registers + --peep-asm Enable peephole optimization on inline assembly + --peep-return Enable peephole optimization for return instructions + --no-peep-return Disable peephole optimization for return instructions + --peep-file use this extra peephole file + --opt-code-speed Optimize for code speed rather than size + --opt-code-size Optimize for code size rather than speed + +Internal debugging options: + --dumpraw Dump the internal structure after the initial parse + --dumpgcse + --dumploop + --dumpdeadcode + --dumpliverange + --dumpregpack + --dumpregassign + --dumptree dump front-end AST before generating iCode + --dumpall Dump the internal structure at all stages + --i-code-in-asm include i-code as comments in the asm file + +Linker options: + -l Include the given library in the link + -L Add the next field to the library search path + --lib-path use this path to search for libraries + --out-fmt-ihx Output in Intel hex format + --out-fmt-s19 Output in S19 hex format + --xram-loc External Ram start location + --xram-size External Ram size + --iram-size Internal Ram size + --xstack-loc External Stack start location + --code-loc Code Segment Location + --code-size Code Segment size + --stack-loc Stack pointer initial value + --data-loc Direct data start location + --idata-loc + +Special options for the mcs51 port: + --stack-size Tells the linker to allocate this space for stack + --parms-in-bank1 use Bank1 for parameter passing + --pack-iram Tells the linker to pack variables in internal ram (default) + --no-pack-iram Deprecated: Tells the linker not to pack variables in internal ram + --acall-ajmp Use acall/ajmp instead of lcall/ljmp + +Special options for the gbz80 port: + -bo use code bank + -ba use data bank + --callee-saves-bc Force a called function to always save BC + --codeseg use this name for the code segment + --constseg use this name for the const segment + --no-std-crt0 For the z80/gbz80 do not link default crt0.rel + +Special options for the z80 port: + --callee-saves-bc Force a called function to always save BC + --portmode= Determine PORT I/O mode (z80/z180) + --asm= Define assembler name (rgbds/asxxxx/isas/z80asm) + --codeseg use this name for the code segment + --constseg use this name for the const segment + --no-std-crt0 For the z80/gbz80 do not link default crt0.rel + --reserve-regs-iy Do not use IY + +Special options for the ds390 port: + --model-flat24 use the flat24 model for the ds390 (default) + --stack-8bit use the 8bit stack for the ds390 (not supported yet) + --stack-size Tells the linker to allocate this space for stack + --pack-iram Tells the linker to pack variables in internal ram (default) + --no-pack-iram Deprecated: Tells the linker not to pack variables in internal ram + --stack-10bit use the 10bit stack for ds390 (default) + --use-accelerator generate code for ds390 arithmetic accelerator + --protect-sp-update will disable interrupts during ESP:SP updates + --parms-in-bank1 use Bank1 for parameter passing + +Special options for the TININative port: + --model-flat24 use the flat24 model for the ds390 (default) + --stack-8bit use the 8bit stack for the ds390 (not supported yet) + --stack-size Tells the linker to allocate this space for stack + --pack-iram Tells the linker to pack variables in internal ram (default) + --no-pack-iram Deprecated: Tells the linker not to pack variables in internal ram + --stack-10bit use the 10bit stack for ds390 (default) + --use-accelerator generate code for ds390 arithmetic accelerator + --protect-sp-update will disable interrupts during ESP:SP updates + --parms-in-bank1 use Bank1 for parameter passing + --tini-libid LibraryID used in -mTININative + +Special options for the ds400 port: + --model-flat24 use the flat24 model for the ds400 (default) + --stack-8bit use the 8bit stack for the ds400 (not supported yet) + --stack-size Tells the linker to allocate this space for stack + --pack-iram Tells the linker to pack variables in internal ram (default) + --no-pack-iram Deprecated: Tells the linker not to pack variables in internal ram + --stack-10bit use the 10bit stack for ds400 (default) + --use-accelerator generate code for ds400 arithmetic accelerator + --protect-sp-update will disable interrupts during ESP:SP updates + --parms-in-bank1 use Bank1 for parameter passing + +Special options for the hc08 port: + --out-fmt-elf Output executable in ELF format diff --git a/doug/src/sysgen.c b/doug/src/sysgen.c new file mode 100755 index 00000000..fa641987 --- /dev/null +++ b/doug/src/sysgen.c @@ -0,0 +1,159 @@ +/*********************************************************************** + + sysgen utility + + Copyright (C) 2009, Max Scane + + This program allows you to build and manage the N8VEM's system ROM. + + There are three possible functions which are selected by command line parameters: + + sysgen -C xxx image.file : This command allows you to create a blank file of xxx KB in size + + sysgen -e extract.file image.file : This command extracts the 10 KB system "track" to a file + + sysgen -i insert.file image.file : This command inserts (writes) the contents of a file to the system "track" + + +*************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + + +void usage(void) +{ + printf("N8VEM sysgen v1.0\n"); + printf("usage:\n"); + printf("sysgen -C xx filename - Create filename xx KB in size\n"); + printf("sysgen -i importfile imagefile - Import the contents of importfile to Imagefile\n"); + printf("sysgen -e exportfile imagefile - Export system track to exportfile\n"); + exit(1); +} + +int main(int argc, char *argv[]) + +{ + + int i, size, fd1, fd2, nwritten, nread; + int ntotal = 0; + char buffer [10240]; + + if (argc != 4) + { + printf("\nIncorrect number of parameters\n\n"); + usage(); + } + + + if (strcmp(argv[1], "-C") == 0) /* Create command */ + { + for (i=0; i<1024; i++) buffer[i] = 229; + + fd1 = creat(argv[3],O_WRONLY|S_IRWXU); + + if ( fd1 == -1) + { + printf("error creating file %s\n",argv[3]); + exit(1); + } + for (i=0; i< (atoi(argv[2])) ; i++) + { + nwritten = write (fd1, &buffer, 1024); + if (nwritten == -1) + { + printf ("error writing file %s\n",argv[3]); + exit(1); + } + ntotal+=nwritten; + } + printf("wrote %d bytes to file %s\n",ntotal,argv[3]); + close(fd1); + exit(0); + } + + if (strcmp(argv[1], "-i") == 0) /* Import command */ + { + + fd1 = open (argv[2],O_RDONLY); + if (fd1 == -1) + { + printf("error opening input file %s\n",argv[2]); + exit(1); + } + fd2 = open (argv[3], O_WRONLY); + if ( fd2 == -1) + { + printf("error opening output file %s\n",argv[3]); + exit(1); + } + + nread = read( fd1, &buffer, 10240); + + if (nread == -1) + { + printf ("error reading from input file %s\n", argv[2]); + exit(1); + } + nwritten = write ( fd2, &buffer, nread); + if (nwritten == -1) + { + printf ("error writing to output file %s\n", argv[3]); + exit(1); + } + printf("wrote %d bytes to file %s\n",nwritten,argv[3]); + + close(fd1); + close(fd2); + + exit(0); + } + + if (strcmp(argv[1], "-e") == 0) /* Export command */ + { + + fd1 = creat(argv[2],O_WRONLY|S_IRWXU); /* export file */ + + if (fd1 == -1) + { + printf("error creating export file %s\n",argv[2]); + exit(1); + } + + fd2 = open(argv[3],O_RDONLY); /* romimage file */ + if (fd2 == -1) + { + printf("error opening romimage file %s\n",argv[3]); + exit(1); + } + nread = read( fd2, &buffer, 10240); + if (nread == -1) + { + printf ("error reading from romimage file %s\n",argv[3]); + exit(1); + } + nwritten = write( fd1, &buffer, nread); + if (nwritten == -1) + { + printf ("error writing to outputfile %s\n",argv[2]); + exit(1); + } + printf("wrote %d bytes to file %s\n",nwritten,argv[2]); + + close(fd1); + close(fd2); + + exit(0); + } + + usage(); + + return EXIT_SUCCESS; +} + + diff --git a/doug/src/tester.c b/doug/src/tester.c new file mode 100755 index 00000000..8038f31c --- /dev/null +++ b/doug/src/tester.c @@ -0,0 +1,7 @@ +#include +#include + +int main() +{ + printf( __TIMESTAMP__ ); +} diff --git a/doug/src/verify.c b/doug/src/verify.c new file mode 100755 index 00000000..05b575c2 --- /dev/null +++ b/doug/src/verify.c @@ -0,0 +1,74 @@ +#include +#include +#include + +int compare(char *file1,unsigned int offset1,char *file2,unsigned int offset2,unsigned int length) +{ + int count1,count2,index; + unsigned char buffer1[65535]; + unsigned char buffer2[65535]; + FILE * fp1,*fp2; + + fp1 = fopen(file1,"r"); + if(NULL == fp1) { + printf("Sorry, cannot open %s\n",file1); + exit(EXIT_FAILURE); + } + count1 = fread(buffer1,offset1+length,1,fp1); + if(1 != count1) { + printf("Sorry, cannot read %d bytes from %s\n",offset1+length,file1); + printf("bytes read were %d\n",count1); + printf("ferror returned %d\n",ferror(fp1)); + fclose(fp1); + exit(EXIT_FAILURE); + } + fclose(fp1); + + fp2 = fopen(file2,"r"); + if(NULL == fp2) { + printf("Sorry, cannot open %s\n",file2); + fclose(fp1); + exit(EXIT_FAILURE); + } + + count2 = fread(buffer2,length,1,fp2); + if(1 != count2) { + printf("Sorry, cannot read %d bytes from %s\n",length,file2); + fclose(fp2); + exit(EXIT_FAILURE); + } + fclose(fp2); + + for(index=0;index