diff --git a/Source/config_s100.asm b/Source/config_s100.asm index d6d93e3a..b3bff482 100644 --- a/Source/config_s100.asm +++ b/Source/config_s100.asm @@ -1,3 +1,84 @@ +; ~/RomWBW/branches/s100/Source/config_s100.asm 1/25/2013 dwg - + +S100WBWENABLE .EQU TRUE ; TRUE IF TARGETING RomWBW + +S100IOENABLE .EQU TRUE ; TRUE FOR S100COMPUTERS I/O BOARD +S100IOSCCAENABLE .EQU TRUE +S100IOSCCBENABLE .EQU TRUE +S100IO8255ENABLE .EQU TRUE + +S100IOUSBENABLE .EQU FALSE ; TRUE IF USB MODULE PRESENT +S100IOVSENABLE .EQU FALSE ; TRUE IF VStamp CHIP IS PRESENT + +S100DIDEENABLE .EQU TRUE ; TRUE IF Dual IDE IS PRESENT + +S100MSDENABLE .EQU FALSE ; TRUE IF MSDOS BOARD PRESENT + +S100ZFDCENABLE .EQU FALSE ; TRUE IF ZFDC BOARD PRESENT + +S100VFIIENABLE .EQU FALSE ; TRUE IF VERSAFLOPPY II PRESENT + +S100ISCPUENABLE .EQU FALSE ; TRUE IF INTERSYSTEMS CPU PRESENT + +S100I3ENABLE .EQU FALSE ; TRUE FOR COMPUPRO INTERFACER 3 +S100I3IOBASE .EQU 10H ; I/O base address of Interfacer 3 + +S100I4ENABLE .EQU FALSE ; TRUE FOR COMPUPRO INTERFACER 4 +S100I4IOBASE .EQU 10H ; I/O base address of Interfacer 4 + +S100I4SCREAM .EQU FALSE ; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +; Mode 1 + +; 01-- ---- ; Async 1 Stop Bitable +; --00 ---- ; No Parity +; ---- 11-- ; 8 Bits +; ---- --10 ; Async 16x Rate +; 0100 1110 + +S100I4MODE1 .EQU 01001110b + + +; Mode 2 +; ---- ---- ; notused +; --1- ---- ; Use internal transmitter clock +; ---1 ---- ; Use internal receiver clock +; ---- 1111 ; 19,200 BAUDRATE +; +S100I4MODE2 .EQU 00111111b + + +; Command (Enable Receiver, Enable Transmitter, No break, Force RTS & DTR LOW +; 00-- ---- Normal Operation +; --1------ RTS +; ---0 ---- Reset Error "normal" +; ---- 0--- Don't force BREAK +; ---- -1-- Enable Receiver +; ---- --1- DTR +; ---- ---1 Transmitter Enable +; 0010 0111 0x27 + +; Command (Enable Receiver, Enable Transmitter, No break, Force RTS & DTR HIGH +; 00-- ---- Normal Operation +; --0------ RTS +; ---0 ---- Reset Error "normal" +; ---- 0--- Don't force BREAK +; ---- -1-- Enable Receiver +; ---- --0- DTR +; ---- ---1 Transmitter Enable +; 0000 0101 0x05 + +;S100I4CMD .EQU 00000101b ; 0x05 +;S100I4CMD .EQU 00100111b ; 0x05 +S100I4CMD .EQU 11100111b ; 0xE7 ; enable remote loopback + + +S100SDSVIDENABLE .EQU FALSE + +S1008086ENABLE .EQU FALSE + +S10068KENABLE .EQU FALSE + ; ;================================================================================================== ; ROMWBW 2.X CONFIGURATION FOR N8 5/8/2012 diff --git a/Source/master-cfg.asm b/Source/master-cfg.asm new file mode 100644 index 00000000..b6e0d517 --- /dev/null +++ b/Source/master-cfg.asm @@ -0,0 +1,3079 @@ +; master-dwg.asm 1/14/2013 dwg - prepare for migration to +; RomWBW/branches/s100. + +; dougtest.asm 12/29/2012 dwg - derived dougtest from master + + +; MASTER.Z80 This is the main monitor program for my system. +; It resided in 1 2732 PROM at F000H (or top half of 28C64) +; Assemble and SLR's Z80ASM Assembler (Can also use Cromemco's Assembler) +; Use:- Z80ASM MASTER FH +; +; Note the monitor is is two sections. The F000H-F7FFH is for typical display +; move memory type functions. The second portion starts at F800H and contains +; a series of CPM BIOS compatable jumps. For compatability with some of my old +; CPM V1.4 software these locations should not be changed. You can easily build +; around them. The second section (after the above BIOS jumps section) contains +; CPM boot loader code and other more specilized stuff. +; +; To assemble under windows... +; Load Altair.EXE +; do cpm3 +; I: +; Submit master +; +; Master.HEX is written back to the same windows folder as altair.exe is in. + +; Programming an EEPROM for the Z80 Board with the VP-280 Programmer +; Using a MK28C28A EEPROM or uP28C64:- +; For monitor at F000H-FFFFH +; Load Buffer Address – 1000 +; From File address F000H +; This will put the code (4K) in the top “half” of the 8K EEPROM. It can be seen/edited at 1000H + +; Recent History... + +; 26/2/09 Added ability to switch CO/CI to ACIA serial from PC. +; 5/3/09 Adjust RTS/CTS levels for Modem +; V3.5 6/3/09 Set talker messages for new V-Stamp chip. +; 12/09/09 Add SD Systems IO-8 board Serial ports. +; V3.52 16/9/09 Add SD Systems IO-8 Board clock display on signon +; v3.6 21/9/09 Add display command for greater than 64K RAM, removed +; V4.0 10/26/09 Switched in 8255 driven IDE HD Controller (Removed XComp) +; some old commands to make more room. +; V4.1 11/7/09 Added input ports scan/diagnostic +; V4.2 11/14/09 Remove Date (keep time) from Clock (Chip is messed up by CPM3 routine) +; also modified to switch from the SD System assembler to the SLR one. +; V4.21 11/17/09 Removed 8086 jump far setting code +; V4.3 11/18/09 Implement movement of 8086 Monitor code (EPROM) to correct location in RAM space +; V4.31 11/19/09 Check 8086 Monitor ROM->ROM went OK. Added W command. +; V4.32 12/7/09 Turn off any SD Systems 8024 video screen enhancements (flashing, underline etc). +; V4.33 12/25/09 Correct High/Low byte Sector read for IDE board +; V4.34 2/23/10 "O" command, 8086 Far jump to 500H (IF RAM @ FFFF0H), W command boots 8086 from reset at FFFF0H. +; V4.35 3/25/10 "O" command just puts 8086 Far JMP to 500H (IF RAM @ FFFF0H). Done also at each reset. +; V4.4 7/29/10 Removed all SD Systems IO-8. Added S-100Computers I/O board drivers. +; V4.41 7/29/10 Initilization of V-Stamp chip done. Cleaned up Serial port names etc +; V4.42 7/31/10 Switched RTC over to S-100Computers board (Ports A4,A5) +; V4.50 2/7/11 Added Floppy Boot loader for ZFDC board. Still have the Versafloppy loader but no BIOS functions +; V4.51 2/13/11 Check IDE if Boot sector is valid +; V4.52 2/15/11 Pulse CF/IDE cards twice to reset (some) cards properly +; V4.53 2/16/11 Initilize IDE board with IDE RD/WR lines inactive on power-up. +; V4.54 2/28/11 Incoporated new fast multi-sector boot for CPM floppy loading with ZFDC board +; V4.55 2/28/11 "O" command now jumps to SWITCH_8086 (activates 8086) when done +; V4.55a 3/1/11 "O" cmd will just put 33 on Consol (temporary 8086 board test) +; V4.56 3/15/11 Re-did IDE drive hardware reset pulse to one (delayed) pulse, then wait for drive ready status. +; V4.57 6/3/11 Set up an equate for IDE drive reset pulse, Fixed Z command (Last version using MM58167 RTC chip) +; V4.6 11/27/11 Switched to Dallas Semiconductor/IBM-PC CMOS-RTC chip & MSDOS Support board for time & dates +; V4.7 3/26/12 Cleaned up IOBYTE options. Added 68000 CPU Slave activate option (B menu command) + +; V4.7A 16Oct12 TRL - Fixed console serial port, forced I/O to serial port +; V4.7B 18Oct12 TRL - Added boot code framwork for RomWBW testing +; V4.7C 19Oct12 TRL - Converted to TASM syntax +; V4.7C 10Nov12 DWG - Added to S100Bios as ../Source/master.asm + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +#INCLUDE "std.asm" ; Add standard .asm files +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;#INCLUDE "config_s100.asm" config_s100.asm is included by std.asm +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +BIGROM .EQU FALSE ; will put Monitor at 0E000h +;SERIAL .EQU TRUE ; Will use S100 Serial Board +;VERSA .EQU FALSE ; Will load Versi Floppy code +;SPEAK .EQU FALSE ; Will allow speach talker board +;RTC .EQU FALSE ; Will load RTC code + + +SCROLL .EQU 01H ;Set scrool direction UP. +BELL .EQU 07H +SPACE .EQU 20H +TAB .EQU 09H ;TAB ACROSS (8 SPACES FOR SD-BOARD) +CR .EQU 0DH +LF .EQU 0AH +FF .EQU 0CH +QUIT .EQU 11H ;Turns off any screen enhancements (flashing, underline etc). +NO_ENHANCEMENT .EQU 17H ;Turns off whatever is on +FAST .EQU 10H ;High speed scrool +ESC .EQU 1BH +DELETE .EQU 7FH +BACKS .EQU 08H +CLEAR .EQU 1AH ;TO CLEAR SCREEN +RST7 .EQU 38H ;RST 7 (LOCATION FOR TRAP) +IOBYTE1 .EQU 0EFH ;IOBYTE (SEE BELOW) +NN .EQU 0H ;[I] INITIAL VALUE +; + +STARTCPM .EQU 100H ;LOCATION WHERE CPM WILL BE PLACED FOR COLD BOOT +STARTDOS .EQU 100H ;LOCATION WHERE MSDOS WILL BE PLACED FOR COLD BOOT +FFILE_SIZE .EQU 9000h/512 ;SIZE OF 5MSDOS20.COM IN 512 BYTE SECTORS +; +; +;IOBYTE = SENSE SWITCHES AT PORT 0EFH +; +; BIT MAP OF PORT 0EFH:------- X X X X X X X X (11111111=NORMAL CONFIG) +; | | | | | | | |..For Z80 Monitor, 0=CONSOLE DATA TO PRINTER ALSO +; | | | | | | |....For 8086 Monitor, 0=Force Consol output to CGA/VGA Board +; | | | | | |......For 8086 Monitor, 0=Do not initilize extra ROMS +; | | | | |........Unused +; | | | |...........For CPM3, 0=Prevents LF's in CPM3 +; | | |.............For Z80 Monitor, 0=Consol I/O via ACIA Serial port +; | |...............For CPM3, 0=Force format of Mdisk ith CPM3 +; |.................For CPM3, 0=R/W protect Mdisk +; For 8086 Monitor, 0=Prevent doing a JMPF to 0000:0500H after 8086 reset +; +; + +;-------------- SD SYSTEMS VIDIO BOARD FOR CONSOLE INPUT & OUTPUT +#IF S100SDSVIDENABLE +CONSOL_STATUS .EQU 0H +CONSOL_IN .EQU 01H +CONSOL_OUT .EQU 01H +#ENDIF + + +;-------------- THIS IS MY PORT TO OUTPUT DATA TO HP 4050T LASAR PRINTER (IMSAI 8PIO Board) +PRINTER_STATUS .EQU 5 ;IN, HP PARELL PORT +PRINTER_OUT .EQU 5 ;OUT +PRINTER_STROBE .EQU 4 ;OUT +;DIAG_LEDS .EQU 5 ;OUT (Will use this port initially for diagnostic LED display) +DIAG_LEDS .EQU 0A8h ;OUT (Will use this port initially for diagnostic LED display) Use hex display + + +;-------------- S100 Computers Serial I/O BOARD PORT ASSIGNMENTS (A0-AC) +#IF S100IOENABLE + +#IF S100IOSCCBENABLE +BCTL .EQU 0A0H ;CHANNEL B CONTROL PORT ASSIGNMENTS OF THE ZILOG SCC CHIP ;<--- Adjust as necessary, +BDTA .EQU 0A2H ;CHANNEL B DATA +#ENDIF +#IF S100IOSCCAENABLE +ACTL .EQU 0A1H ;CHANNEL A CONTROL +ADTA .EQU 0A3H ;CHANNEL A DATA +#ENDIF +#IF S100IO8255ENABLE +PortA_8255 .EQU 0A8H ;A port of 8255 +PortB_8255 .EQU 0A9H ;B port of 8255 +PortC_8255 .EQU 0AAH ;C Port of 8255 +PortCtrl_8255 .EQU 0ABH ;8255 configuration port +AinBout8255cfg .EQU 10011000b ;Set 8255 ports:- A input, B output, +AoutBin8255cfg .EQU 10001010b ;Set 8255 ports:- A output to LED, B Input from Dip Switch +#ENDIF + +#IF S100IOUSBENABLE +;---------------PORT ASSIGNEMENT FOR DLP-USB Controller chip +USB_DATA .EQU 0ACH +USB_STATUS .EQU 0AAH ;Status port for USB port (Port C of 8255, bits 6,7) +USB_RXE .EQU 80H ;If Bit 7 = 0, data available to recieve by S-100 Computer +USB_TXE .EQU 40H ;If Bit 6 = 0 data CAN be written for transmission to PC +#ENDIF + +#ENDIF + +;-------------- S100Computers MSDOS Support Board PORT ASSIGNMENTS +#IF S100MSDENABLE +CMOS_PORT .EQU 70H ;Base Port for CMOS Chip on MSDOS Support Board +MASTER_PIC_PORT .EQU 20h ;Hardware port the 8259A (two ports 20H & 21H) +MasterICW1 .EQU 00010111B ;EDGE triggered, 4 bytes, single Master,ICW4 needed +MasterICW2 .EQU 8H ;Base address for 8259A Int Table (IBM-PC uses 8X4 = 20H) +MasterICW3 .EQU 0H ;No slave +MasterICW4 .EQU 00000011B ;No special mode, non buffer, Auto EOI, 8086. ;<<<<, +#ENDIF + + +;--------------- PORTS FOR FOR Z80/WD2793 ZFDC Board +#IF S100ZFDCENABLE +S100_DATA_A .EQU 10H ;IN, S100 Data port to GET data to from FDC Board +S100_DATA_B .EQU 10H ;OUT, S100 Data port to SEND data to FDC Board +S100_STATUS_A .EQU 11H ;Status port for A +S100_STATUS_B .EQU 11H ;Status port for B +RESET_ZFDC_PORT .EQU 13H ;Port to reset ZFDC Z80 CPU. + +STATUS_DELAY .EQU 5 ;Time-out for waiting for ZFDC Board handshake signal (~0.5 seconds @ 10MHz) +DIRECTION_BIT .EQU 7 ;Bits for the ZFDC flags 0 = IN, 1 = OUT +DATA_IN_RDY .EQU 0 ;Bit for data available from ZFDC board +DATA_OUT_RDY .EQU 1 ;Bit for data can be sent to ZFDC board +STD8IBM .EQU 1 ;IBM 8" SDSS Disk +NO_ERRORS_FLAG .EQU 0 ;No Errors flag for previous cmd, sent back to S-100 BIOS + +;Commands to the ZFDC Board:- +CMD_RESET_ZFDC .EQU 3H ;Reset the WD2793 chip and Board software +CMD_SET_FORMAT .EQU 4H ;This will select a specified drive and assign a disk format table to that drive +CMD_SET_DRIVE .EQU 5H ;This will select a specified drive (0,1,2,3) +CMD_SET_TRACK .EQU 7H ;This will set head r.EQUest to a specified track +CMD_SET_SIDE .EQU 8H ;This will set side r.EQUest to a specified side +CMD_SET_SECTOR .EQU 9H ;This will set sector r.EQUest to a specified sector +CMD_SET_HOME .EQU 0AH ;This will set head r.EQUest to Track 0 of CURRENT drive +CMD_STEP_IN .EQU 0BH ;Step head in one track of CURRENT drive +CMD_SEEK_TRACK .EQU 0EH ;Seek to track to (IY+DRIVE_TRACK) with the track verify bit set on CURRENT drive/format +CMD_READ_SECTOR .EQU 10H ;Read data from the CURRENT sector (on current track,side,drive). +CMD_HANDSHAKE .EQU 21H ;Handshake command only sent during board initilization/testing +CMD_RD_MULTI_SECTOR .EQU 29H ;Read data from multiple sectors starting at the CURRENT sector (on current track,side,drive). +#ENDIF + +;-------------- PORT(S) TO SWITCH MASTER/SLAVE(S) +Z80PORT .EQU 0D0H ;4 PORTS ON Z80 BOARD FOR MEMORY MANAGEMENT (& INT Controller on IA Z80 CPU Board) +Z80MMUL .EQU Z80PORT+2 ; MMU port for lower 16k block +Z80MMUH .EQU Z80PORT+3 ; MMU port for upper 16k block + + +SW86 .EQU 0EDH ;INPUT FROM THIS PORT SWITCHES IN THE 8088,8086, or 80286 board +SW68K .EQU 0ECH ;INPUT FROM THIS PORT SWITCHES IN THE 68000 CPU Board + + +;-------------- VERSAFLOPPY-II FLOPPY DISK CONTROLLER COMMANDS ETC. +#IF S100VFIIENABLE +X .EQU 50H ;BASE PORT FOR 1791 +RSET .EQU X+0 ;CONTROLLER RESET ADDRESS +SELECT .EQU X+3 ;DRIVE SELECT PORT +STATUS .EQU X+4 ;STATUS PORT +TRACK .EQU X+5 ;TRACK PORT +SECTOR .EQU X+6 ;SECTOR PORT +DATA .EQU X+7 ;DATA PORT +CMD .EQU X+4 ;COMMAND PORT +#ENDIF + +CIOBYTE .EQU 03H +CDISK1 .EQU 04H +ZERO_L .EQU 08H ;Some of my CPM Loader's needs these to be zero! +ZERO_H .EQU 09H ;(The Non Banked version of CPM3). Need to later see why +_TADDR .EQU 40H +_UNIT .EQU 42H ;NEW @UNIT BYTE +_SCTR .EQU 43H ;SECTOR (compatible with my old CPM2.2 Versafloppy BIOS) +_TRK .EQU 44H ;TRACK +_NREC .EQU 45H ;# OF SECTORS +_ERMASK .EQU 46H ;ERROR MASK +_ERSTAT .EQU 47H ;ERROR FLAG STORE +_IDSV .EQU 48H ;6 BYTES (USED FOR TRACK ID COMMAND) +_CMDSV .EQU 4EH ;COMMAND SAVE +_SPSV .EQU 4FH ;SP SAVE +TEMP2 .EQU 51H ;2 BYTE TEMP RECORD +_SIDE .EQU 51H ;SIDE STORE FOR MSDOS DISK +_COUNT .EQU 53H ;SECTORS/TRACK for BOOT (Currently unused) +_UNITCK .EQU 55H ;OLD @UNIT BYTE +_RSEEK .EQU 56H ;NBR OF RESEEKS +_RTRY .EQU 57H ;NBR OF RTRYS +ADRIVE .EQU 58H ;STORE OF A: DRIVE DENSITY ETC TYPE +BDRIVE .EQU 59H ;STORE OF B: DRIVE TYPE + +_FDCTYPE .EQU 5BH ;0FFH = ZFDC FDC Board Boot, else Versafloppy II FDC Boot, + +_SEC_SIZE .EQU 5CH ;Byte count of a sector fot loader +_SSTACK .EQU 80H ;SYSTEM STACK + +COLD .EQU 80H ;COLD START ADDRESS FOR CPM FLOPPY (ONLY) BOOT LOADER + +RDACMD .EQU 0C0H ;READ ADDRESS CODE +RDCMD .EQU 088H ;READ SECTOR CODE +WRCMD .EQU 0A8H ;WRITE SECTOR CODE +WRTCMD .EQU 0F4H ;WRITE TRACK CODE +RSCMD .EQU 008H ;RESTORE COMMAND (Note 3 Ms seek) +SKNCMD .EQU 018H ;SEEK NO VERIFY +FSKCMD .EQU 01CH ;FLOPPY SEEK COMAND +RSVCMD .EQU 00CH ;RESTORE WITH VERIFY COMMAND +MSKCMD .EQU 01FH ;MINI FLOPPY SEEK COMMAND + +SRMASK .EQU 0FEH ;SECTOR READ ERROR BITS MASK + +STDSDT .EQU 26 ;STANDARD 8" 26 SECTORS/TRACK +STDDDT .EQU 50 ;STANDARD DD 8" 50 SECTORS/TRACK +NBYTES .EQU 128 ;BYTES/SECTOR +NTRKS .EQU 77 ;TRACKS/DISK + + +;-------------- S100Computers IDE HARD DISK CONTROLLER COMMANDS ETC. +#IF S100DIDEENABLE +IDEAport .EQU 030H ;lower 8 bits of IDE interface +IDEBport .EQU 031H ;upper 8 bits of IDE interface +IDECport .EQU 032H ;control lines for IDE interface +IDECtrl .EQU 033H ;8255 configuration port +IDEDrivePort .EQU 034H ;To select the 1st or 2nd CF card/drive (Not used with this monitor) + +IDE_Reset_Delay .EQU 020H ;Time delay for reset/initilization (~60 uS, with 10MHz Z80, 2 I/O wait states) + +CPM_ADDRESS .EQU 100H ;Will place the CPMLDR.COM Loader here with + ;CPMLDR.COM will ALWAYS be on TRK 0,SEC2, (LBA Mode) +SEC_COUNT .EQU 12 ;CPMLDR.COM r.EQUires (currently) 10, 512 byte sectors + ;Add extra just in case +; +RDcfg8255 .EQU 10010010B ;Set 8255 IDECport out, IDEAport/B input +WRcfg8255 .EQU 10000000B ;Set all three 8255 ports output +; +IDEa0line .EQU 01H ;direct from 8255 to IDE interface +IDEa1line .EQU 02H ;direct from 8255 to IDE interface +IDEa2line .EQU 04H ;direct from 8255 to IDE interface +IDEcs0line .EQU 08H ;inverter between 8255 and IDE interface +IDEcs1line .EQU 10H ;inverter between 8255 and IDE interface +IDEwrline .EQU 20H ;inverter between 8255 and IDE interface +IDErdline .EQU 40H ;inverter between 8255 and IDE interface +IDEreset .EQU 80H ;inverter between 8255 and IDE interface +; +;Symbolic constants for the IDE Drive registers, which makes the +;code more readable than always specifying the address pins +; +REGdata .EQU 08H ;IDEcs0line +REGerr .EQU 09H ;IDEcs0line + IDEa0line +REGcnt .EQU 0AH ;IDEcs0line + IDEa1line +REGsector .EQU 0BH ;IDEcs0line + IDEa1line + IDEa0line +REGcyLSB .EQU 0CH ;IDEcs0line + IDEa2line +REGcyMSB .EQU 0DH ;IDEcs0line + IDEa2line + IDEa0line +REGshd .EQU 0EH ;IDEcs0line + IDEa2line + IDEa1line ;(0EH) +REGCMD .EQU 0FH ;IDEcs0line + IDEa2line + IDEa1line + IDEa0line ;(0FH) +REGstatus .EQU 0FH ;IDEcs0line + IDEa2line + IDEa1line + IDEa0line +REGcontrol .EQU 16H ;IDEcs1line + IDEa2line + IDEa1line +REGastatus .EQU 17H ;IDEcs1line + IDEa2line + IDEa1line + IDEa0line + +;IDE CMD Constants. These should never change. +CMDrecal .EQU 10H +CMDread .EQU 20H +CMDwrite .EQU 30H +CMDinit .EQU 91H +CMDid .EQU 0ECH +CMDdownspin .EQU 0E0H +CMDupspin .EQU 0E1H +; +; IDE Status Register: +; bit 7: Busy 1=busy, 0=not busy +; bit 6: Ready 1=ready for CMD, 0=not ready yet +; bit 5: DF 1=fault occured insIDE drive +; bit 4: DSC 1=seek complete +; bit 3: DRQ 1=data r.EQUest ready, 0=not ready to xfer yet +; bit 2: CORR 1=correctable error occured +; bit 1: IDX vendor specific +; bit 0: ERR 1=error occured +; +;---------------------------------------------------------------------------- +; +;CONNECTIONS TO Z80-MONB.Z80 :- +; +#ENDIF + +#IF BIGROM +BASE .EQU 0E000H ;Start or EPROM Location (Assume a 278C64 (8k) ) +#ELSE +BASE .EQU 0F000H ;Start or EPROM Location (Assume a 2732 (4K) or half of a 278C64 (8k) ) +#ENDIF ; endif 8kROM + + .ORG BASE ;<--------<<<<<< LOCATION OF START OF MONITOR (First part) +VERSA .EQU BASE+800H ;<--------<<<<<< LOCATION OF FLOPPY BIOS (For old Software) + ; NOTE MUST INSURE NO OVERFLOW OF THE FIRST + ; PART OR THIS MONITOR INTO THIS BIOS AREA + +;PROGRAM CODE BEGINS HERE +;FIRST A JUMP TABLE FOR ALL JUMPS INTO THE MONITOR. NOTE THESE CANNOT BE +;CHANGED. WHERE POSSIBLE ZAPPLE FORMAT IS USED. + +ZAPPLE: JP BEGIN ;INITILIZATION +ZCI: JP CI ;CONSOL INPUT +ZRI: JP SERIAL_IN ;READER INPUT = Modem Input for Now +ZCO: JP CO ;CONSOL OUTPUT +ZPOO: JP SERIAL_OUT ;PUNCH OUTPUT = Modem Output for Now +ZLO: JP LO ;LIST OUTPUT +ZCSTS: JP CSTS ;CONSOL STATUS +ZMEMCK: JP MEMSIZ ;GET HIGHEST RAM RETURNS IT IN [HL] +ZTRAP: JP TRAP ;ERROR TRAP ADDRESS +ZSTART: JP START ;JUMP TO MONITOR DO NOT RESET HARDWARE +ZTALK: JP SPEAKOUT ;SEND AN ASCII CHARACTER TO TALKER (One at a time) +ZTALKS: JP SPEAKER_CTS ;STATUS FOR SPEECH CTS Line (V-Stamp CTS low when ready) +ZDELAY: JP DELAY ;SOFTWARE DELAY LENGTH IN [A] +ZLSTAT: JP LSTAT ;LIST STATUS +ZONLIST: JP ONLIST ;INITILIZE LIST DEVICE +ZOFFLIST: JP OFLIST ;TURN OFF LIST DEVICE +ZTIME: JP PRINT_TIME ;PUT TIME ON CRT @ CURSOR POSITION +ZDATE: JP PRINT_DATE ;PRINT DATE ON CRT @ CURSOR POSITION +ZSPEAK_: JP SPEAK_ ;SEND ASCII STRING TO TALKER [HL] UP TO '$' +ZSERIAL_OUT: JP SERIAL_OUT ;OUT TO ZILOG SCC SERIAL PORT +ZSERIAL_IN: JP SERIAL_IN ;INPUT FROM ZILOG SCC SERIAL PORT +ZSERIAL_STAT: JP SERIAL_STAT ;STATUS FROM ZILOG SCC SERIAL PORT +ZLOADER: JP LOADER ;LOAD IN CPM IMAGE ON TRACKS 0 & 1 (VIA FLOPPY BOOT LOADER ON DISK SECTOR 1) +ZPMSG0: JP TOM ;DISPLAY STRING ON CONSOL [HL]=START ADD. [B]=LENGTH +ZPMSG_: JP PRINT_STRING ;DISPLAY STRING ON CONSOL [HL]=START ADD. '$'=END +ZHLSP: JP HLSP ;DISPLAY [HL] ON CONSOL THEN ONE SPACE +ZBITS: JP BITS1 ;DISPLAY 8 BITS OF [A] ON CONSOL +ZLBYTE: JP LBYTE ;DISPLAY [A] ON CONSOL +ZHEXSP: JP HEXSP ;PUT 16 BIT PARAMETERS ON STACK FROM CONSOL, [C]=PARAMETER # +ZCRLF: JP CRLF ;SEND CRLF TO CONSOL +ZHILO: JP HILO ;RANGE CHECK (INC [HL], IF HL=DE THEN SET CARRY) +ZCONV: JP CONV ;CONVERT HEX IN [A] TO ASCII IN [A] +ZDOS JP MSDOS ;LOAD MSDOS FROM 5" DRIVE D: +ZPCHK: JP PCHK ;INPUT FROM CONSOL & TEST FOR DELIMITERS RET {Z} IF + ;SPACE OR , RET {C} IF A CR ELSE NON ZERO NON CARRY +VFLOPPY JP VBOOT ;BOOT UP CPM-80 FROM VERSAFLOPPY II FDC +ZHARD: JP HBOOTCPM ;BOOT UP CPM-80 FROM HARD DISK +ZPRDY: JP PRDY ;PUNCH READY CHECK +ZRSTAT: JP RSTAT ;READER STATUS +ZCCHK: JP CCHK ;CHECK FOR ^S & ESC AT KEYBOARD +ZFLOPPY JP ZBOOT ;BOOT UP CPM-80 FROM ZFDC FDC +; +; NOTE TABLE MUST BE WITHIN 0-FFH BOUNDRY +; +;COMMAND BRANCH TABLE + +TBL: + .DW FLUSH ; "@" SEND FF to LaserJet printer + .DW MEMMAP ; "A" DISPLAY A MAP OF MEMORY + .DW SWITCH_68K ; "B" SWITCH CONTROL TO 68000 CPU + .DW ZBOOT ; "C" BOOT IN CP/M FROM 8" DISK WITH WITH ZFDC FDC + .DW DISP ; "D" DISPLAY MEMORY (IN HEX & ASCII) + .DW ECHO ; "E" ECHO CHAR IN TO CHAR OUT + .DW FILL ; "F" FILL MEMORY WITH A CONSTANT + .DW GOTO ; "G" GO TO [ADDRESS] + .DW SHOW_DATE ; "H" SHOW CURRENT DATE + .DW SHOW_TIME ; "I" SHOW CURRENT TIME + .DW RAMTEST ; "J" NON-DESTRUCTIVE MEMORY TEST + .DW KCMD ; "K" DISPLAY THE LIST OF MONITOR COMMANDS + .DW VBOOT ; "L" BOOT IN CP/M FROM 8" DISK WITH VERSAFLOPPY II FDC + .DW MOVE ; "M" MOVE BLOCK OF MEMORY (START,FINISH,DESTINATION) + .DW XMEMMAP ; "N" Display extended memory Segment:Address + .DW UP8086 ; "O" SWITCH CONTROL TO 8088, 8086 or 80286. + .DW HBOOTCPM ; "P" BOOT IN CPM FROM IDE HARD DISK + .DW QUERY ; "Q" QUERY PORT (IN OR OUT) + .DW INPORTS ; "R" Read ALL Input Ports + .DW SUBS ; "S" SUBSTITUTE &/OR EXAMINE MEMORY + .DW TYPE ; "T" TYPE ASCII PRESENT IN MEMORY + .DW BEGIN ; "U" SPARE + .DW VERIFY ; "V" COMPARE MEMORY + .DW SWITCH_8086 ; "W" INPUT Port ED (switched in 8086/80286) + .DW START ; "X" BOOT IN MSDOS FROM HARD DISK (Not done yet) + .DW BOOT_RomWBW ; "Y" Boot RomWBW + .DW SIZE ; "Z" FIND HIGHEST R/W RAM + +; +;--------------------------------------------------------------------------- +; +BEGIN: + +#IF S100I4SCREAM + ld a,1 + ld c,GBUSR + out (c),a + ld a,S100I4MODE1 + ld c,GBUM + out (c),a + ld a,S100I4MODE2 + ld c,GBUM + out (c),a + ld a,S100I4CMD ; dtr,break,reset,rts + ld C,GBUC ; set up command port + out (c),a + ld c,GBUS +i4scrmlp: + in a,(c) + and i4TBMT + jr z,i4scrmlp + ld c,GBUD + ld a,'!' + out (c),a + jr i4scrmlp + +#ENDIF + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +#IF S100IOENABLE + ; We are using the serial port's extra I/O port as a diagnostic port, so we need to + ; set them up here at the start of the code. + ; Port A as output to a pair of Hex Displays. + ; Port B as input from a 8 position dip switch. + LD A,AoutBin8255cfg ;A out to Hex LED, B In Dip , C(bits 0-3) output, (bits 4-7)input + OUT (PortCtrl_8255),A ;Config 8255 chip, Mode 0 +#ENDIF + +#IF S100SDSVIDENABLE + LD A,'#' ;For quick hardware diagnostic test + OUT (CONSOL_OUT),A +#ENDIF + +#IF S100IOENABLE + LD A,0FFH ;Clear Printer strobe, comes up 0 on a reset + OUT (PRINTER_STROBE),A ;also it turn all LED's off as a diagnostic + LD A,00000000B ;FLAG PROGRESS VISUALLY FOR DIAGNOSTIC (ALL LED' ON) + OUT (DIAG_LEDS),A ;LED's will go off one at a time +#ENDIF + +#IF S100VFIIENABLE + LD A,0FFH + OUT (SELECT),A ;DESELECT ANY FLOPPYS ON VERSAFLOPPY FDC (If Present) +#ENDIF + +#IF S100IOENABLE + LD A,10000000B ;FLAG PROGRESS VISUALLY FOR DIAGNOSTIC (1 LED off) + OUT (DIAG_LEDS),A +#ENDIF + + LD A,0FFH +#IF S100VFIIENABLE + OUT (RSET),A ;RESET VERSAFLOPPY II FLOPPY DISK CONTROLLER (If Present) +#ENDIF +#IF S100ZFDCENABLE + OUT (RESET_ZFDC_PORT),A ;RESET ZFDC FLOPPY DISK CONTROLLER (If Present) +#ENDIF + + XOR A ;SET INTERUPT TO PAGE 0H +#IF S100ISCPUENABLE + OUT (Z80PORT+1),A ;KILL THE INTERSYSTEMS Z80 CPU BOARD INT CONTROLLER (If present) +#ENDIF + LD I,A + +#IF S100MSDENABLE + ;We need to clear the 8259A otherewise teh 8086 monitor sometimes hangs + LD A,MasterICW1 ;Initilize the 8259A PIC Controller (;EDGE triggered, 4 bytes, single Master,ICW4 needed) + OUT (MASTER_PIC_PORT),A + LD A,MasterICW2 ;Ints starts at 20H in RAM (IBM-PC uses 8X4 = 20H) + OUT (MASTER_PIC_PORT+1),A + LD A,MasterICW4 ;No slaves above, so 8259 does not expect ICW3 + out (MASTER_PIC_PORT+1),A + + LD A,11111111b ;Allow no interrupts to 8259A with Z80. + out (MASTER_PIC_PORT+1),A +#ENDIF + + LD A,0H ;SETUP MEMORY MANAGEMENT TO OVERLAP WITH + OUT (Z80PORT+2),A ;CURRENT RAM in 64K Space + LD A,04H + OUT (Z80PORT+3),A + +#IF S100IOENABLE + LD A,11000000B ;FLAG PROGRESS VISUALLY FOR DIAGNOSTIC (2 LED's off) + OUT (DIAG_LEDS),A +#ENDIF + +ZAXXLE: LD SP,AHEAD-4 ;SETUP A FAKE STACK + JP MEMSZ1 ;RETURNS WITH TOP OF RAM IN [HL] + .DW AHEAD ;Ret will pick up this address +AHEAD: LD SP,HL ;[HL] CONTAINS TOP OF RAM - WORKAREA + + PUSH HL + POP IX ;Store stack pointer for below in [IX] + +#IF S100IOENABLE + CALL INIT_S100_IO ;Initilize the Zilog 8530 & 8255 on the S100Computers I/O Board +#ENDIF + + +#IF S100I3ENABLE + LD A,0 + CALL i3_config + LD A,1 + CALL i3_config + LD A,2 + CALL i3_config + LD A,3 + CALL i3_config + LD A,4 + CALL i3_config + LD A,5 + CALL i3_config + LD A,6 + CALL i3_config + LD A,7 + CALL i3_config +scream: + LD A,0 + LD C,'*' + CALL i3_output + LD A,1 + LD C,'*' + CALL i3_output + LD A,2 + LD C,'*' + CALL i3_output + LD A,3 + LD C,'*' + CALL i3_output + LD A,4 + LD C,'*' + CALL i3_output + LD A,5 + LD C,'*' + CALL i3_output + LD A,6 + LD C,'*' + CALL i3_output + LD A,7 + LD C,'*' + CALL i3_output + JP scream +#ENDIF + +#IF S100I4ENABLE + LD A,1 + CALL i4_config + LD A,2 + CALL i4_config + LD A,3 + CALL i4_config +scream: + LD A,1 + LD D,'*' + CALL i4_output + LD A,2 + LD D,'*' + CALL i4_output + LD A,3 + LD D,'*' + CALL i4_output + JP scream +#ENDIF + + + LD HL,MSG0 ;Have a Stack, so we can use CALL + CALL PRINT_STRING + +#IF S100IOENABLE + LD A,11100000B ;FLAG PROGRESS (Have a Stack with 3 LED's off) + OUT (DIAG_LEDS),A +#ENDIF + CALL PRINT_TIME ;PRINT TIME ON CRT (IF RTC BOARD PRESENT) + JP C,NO_CLOCK + LD HL,GAP_MSG + CALL PRINT_STRING + CALL PRINT_DATE ;PRINT DATE ON CRT, then CRLF +NO_CLOCK: + CALL CRLF + +#IF S100IOENABLE + LD A,11110000B ;FLAG PROGRESS (I/O board initilized, 4 LED's Off) + OUT (DIAG_LEDS),A +#ENDIF + + LD HL,SP_MSG ;Print Current Stack Location + CALL PRINT_STRING + + + PUSH IX ;SP is stored from above in [IX] + POP HL + CALL HLSP ;Print HL/SP + CALL CRLF ;Then CRLF + CALL CSTS ;CHECK IF GARBAGE AT KEYBOARD + CALL NZ,CI ;If so flush it + +#IF S100IOENABLE + LD A,11111000B ;FLAG PROGRESS (Ready to go, 5 LED's off) + OUT (DIAG_LEDS),A +#ENDIF +#IF S100IOVSENABLE + LD HL,CR_SMSG ;lets V-Stamp chip get baud rate + CALL SPEAK_ +#ENDIF ; S100IOVSENABLE + + +#IF S100DIDEENABLE + CALL INITILIZE_IDE_BOARD ;initilize first IDE drive (if present) +#ENDIF + +#IF S100IOENABLE + LD A,11111100B ;FLAG PROGRESS (Initilization done, 6 LED's off) + OUT (DIAG_LEDS),A +#ENDIF + +;-------THIS IS THE START ON THE MAIN MONITOR LOOP-------------------------------- + +START: LD DE,START + PUSH DE ;EXTRA UNBALANCED POP & [DE] WOULD END UP IN [PC] + CALL CRLF + LD C,BELL ;A BELL HERE WILL SIGNAL WHEN JOBS ARE DONE + CALL CO + LD C,'-' + CALL CO + LD C,'>' + CALL CO + +STARO: CALL TI ;Main loop. Monitor will stay here until cmd. + AND 7FH + JR Z,STARO + SUB '@' ;Commands @ to Z only + RET M + CP 1BH ;A-Z only + RET NC + ADD A,A + LD HL,TBL + ADD A,L + LD L,A + LD A,(HL) + INC HL + LD H,(HL) + LD L,A + LD C,02H + JP (HL) ;JUMP TO COMMAND TABLE +; +;----- GO CARRY OUT COMMAND AND POP BACK TO START---------- +; NOTE STRING IS HERE IN CASE A 2716 IS USED BY MISTAKE (Monitor will at least signon) + +MSG0: +#IF S100SDSVIDENABLE + .DB SCROLL,QUIT,NO_ENHANCEMENT,FAST,BELL,CR,LF,LF +#ENDIF + .TEXT "Configurable Z80 ROM MONITOR V4.7C (RomWBW Version of 9 January 2013) $" +SMSG: .TEXT "Hello The Z80 ROM MONITOR Ver 4.7B Is Now Resident $" + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +#IF S100I3ENABLE +#INCLUDE "s100-i3.asm" +#ENDIF + +#IF S100I4ENABLE +#INCLUDE "s100-i4.asm" +#ENDIF + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;SEND MESSAGE TO CONSOL MESSAGE IN [HL],LENGTH IN [B] + +TOM: + LD C,(HL) + INC HL + CALL CO + DJNZ TOM + RET +; +PRINT_STRING: + LD A,(HL) ;A ROUTINE TO PRINT OUT A STRING @ [HL] + INC HL ;UP TO THE FIRST '$'. + CP '$' + RET Z + LD C,A + CALL CO + JR PRINT_STRING + +;ABORT IF ESC AT CONSOL, PAUSE IF ^S AT CONSOL + +CCHK: CALL CSTS ;FIRST IS THERE ANYTHING THERE + RET Z + CALL CI + CP 'S'-40H + JR NZ,CCHK1 +CCHK2: CALL CSTS ;WAIT HERE UNTIL ANOTHER INPUT IS GIVEN + JR Z,CCHK2 +CCHK1: CP ESC + RET NZ ;RETURN EXECPT IF ESC + +;RESTORE SYSTEM AFTER ERROR + +ERROR: + CALL MEMSIZ ;GET RAM AVAILABLE - WORKSPACE IN [HL] + LD SP,HL ;SET STACK UP IN WORKSPACE AREA + LD C,'*' + CALL CO + JP START + +;PRINT HIGHEST MEMORY FROM BOTTOM + +SIZE: + CALL MEMSIZ ;RETURNS WITH [HL]= RAM AVAILABLE-WORKSPACE + +LFADR: CALL CRLF + +;PRINT [HL] AND A SPACE +HLSP: PUSH HL + PUSH BC + CALL LADR + LD C,SPACE + CALL CO + POP BC + POP HL + RET + +;PRINT A SPACE + +SF488: LD C,SPACE + JP CO + +;CONVERT HEX TO ASCII + +CONV: AND 0FH + ADD A,90H + DAA + ADC A,40H + DAA + LD C,A + RET + +;GET TWO PARAMETERS AND PUT THEM IN [HL] & [DE] THEN CRLF + +EXLF: CALL HEXSP + POP DE + POP HL + +;SEND TO CONSOL CR/LF + +CRLF: PUSH BC + LD C,LF + CALL CO + LD C,CR + CALL CO + POP BC + RET + +;PUT THREE PARAMETERS IN [BC] [DE] [HL] THEN CR/LF + +EXPR3: INC C ;ALREADY HAD [C]=2 FROM START + CALL HEXSP + CALL CRLF + POP BC + POP DE + POP HL + RET + +;GET ONE PARAMETER + +EXPR1: LD C,01H +HEXSP: LD HL,0000 +EX0: CALL TI +EX1: LD B,A + CALL NIBBLE + JR C,EX2X + ADD HL,HL + ADD HL,HL + ADD HL,HL + ADD HL,HL + OR L + LD L,A + JR EX0 +EX2X: EX (SP),HL + PUSH HL + LD A,B + CALL QCHK + JR NC,SF560 + DEC C + RET Z +SF560: JP NZ,ERROR + DEC C + JR NZ,HEXSP + RET +EXF: LD C,01H + LD HL,0000H + JR EX1 + +;RANGE TEST ROUTINE CARRY SET = RANGE EXCEEDED + +HILOX: CALL CCHK + CALL HILO + RET NC + POP DE ;DROP ONE LEVEL BACK TO START + RET +HILO: INC HL ;RANGE CHECK SET CARRY IF [DE]=[HL] + LD A,H + OR L + SCF + RET Z + LD A,E + SUB L + LD A,D + SBC A,H + RET + +;PRINT [HL] ON CONSOL + +LADR: + LD A,H + CALL LBYTE + LD A,L +LBYTE: + PUSH AF + RRCA + RRCA + RRCA + RRCA + CALL SF598 + POP AF +SF598: + CALL CONV + JP CO + +;THIS IS A CALLED ROUTINE USED TO CALCULATE TOP OF RAM IS USED BY +;THE ERROR TO RESET THE STACK. Returns top of RAM in [HL] + +MEMSIZ: + PUSH BC ;SAVE [BC] +MEMSZ1: + LD HL,0FFFFH ;START FROM THE TOP DOWN +MEMSZ2: + LD A,(HL) + CPL + LD (HL),A + CP (HL) + CPL ;PUT BACK WHAT WAS THERE + LD (HL),A + JP Z,GOTTOP + DEC H ;TRY 100H BYTES LOWER + JR MEMSZ2 ;KEEP LOOKING FOR RAM +GOTTOP: + POP BC ;RESTORE [BC] + RET + +NIBBLE: + SUB 30H + RET C + CP 17H + CCF + RET C + CP LF + CCF + RET NC + SUB 07H + CP LF + RET + +COPCK: + LD C,'-' + CALL CO + +PCHK: CALL TI + +;TEST FOR DELIMITERS + +QCHK: + CP SPACE + RET Z + CP ',' + RET Z + CP CR + SCF + RET Z + CCF + RET + +;KEYBOARD HANDELING ROUTINE (WILL NOT ECHO CR/LF) +;IT CONVERTS LOWER CASE TO UPPER CASE FOR LOOKUP COMMANDS +;ALSO ^C WILL FORCE A JUMP TO BOOT IN CP/M +;ALL OTHERE CHARACTERS ARE ECHOED ON CONSOL + +TI: + CALL CI + CP CR + RET Z + CP 'C'-40H ;^C TO BOOT IN CP/M + JP Z,FBOOT + PUSH BC + LD C,A + CALL CO + LD A,C + POP BC + CP 40H ;LC->UC + RET C + CP 7BH + RET NC +SF754: + AND 5FH + RET + +BITS1: PUSH DE ;DISPLAY 8 BITS OF [A] + PUSH BC + LD E,A + CALL BITS + POP BC + POP DE + RET + +BITS: LD B,08H ;DISPLAY 8 BITS OF [E] + CALL SF488 +SF76E: SLA E + LD A,18H + ADC A,A + LD C,A + CALL CO + DJNZ SF76E + RET +; +;<<<<<<<<<<<<<<<<<<<<<< MAIN CONSOL OUTPUT ROUTINE >>>>>>>>>>>>>>>>>>>>>>>>> +; If console board is NOT installed, their is issues with default status BITS +; returning bad info keeping Serial Board form working. For now we will +; just force serial I/O + +CO: +; IN A,(IOBYTE1) ;NOTE CHARACTER IS IN [C] +; BIT 0,A ;CHECK IF OUTPUT TO PRINTER IS ALSO REQ +; JP Z,LOX + +#IF S100SDSVIDENABLE +SDCONO: + IN A,(CONSOL_STATUS) ;SD SYSTEMS VIDIO BOARD PORT + AND 4H + JR Z,SDCONO + LD A,C + CP 07H ;IS IT A BELL + JR Z,BELL1 + CP 0H ;SD BOARD CANNOT TAKE A NULL! + RET Z + + OUT (CONSOL_OUT),A + IN A,(IOBYTE1) + BIT 5,A ;SEE IF SERIAL PORT OUTPUT IS REQ + JR NZ,SDCON5 ;MAKE SURE TO RETURN CHARACTER SENT IN [A] +#ENDIF + + CALL SERIAL_OUT ;Send data in [C] to Serial Port +SDCON5: LD A,C + RET ;RETURN CHARACTER SENT IN [A] + +;LOX: +; CALL SDCONO ;OUTPUT TO BOTH PRINTER & CONSOLE +; CALL LO +; RET + +#IF S100SDSVIDENABLE +BELL1: + LD A,06H ;SEND A BELL + OUT (CONSOL_OUT),A + LD A,0FH + CALL DELAY + LD A,07H + OUT (CONSOL_OUT),A + JR SDCON5 +#ENDIF + +DELAY: + DEC A ;GENERAL COUNT DOWN TIME DELAY + RET Z ;LENGTH SET IN [A] + PUSH AF + LD A,05H +MORE: DEC A + PUSH AF + XOR A +MORE2: DEC A + JR NZ,MORE2 + POP AF + JR NZ,MORE + POP AF + JR DELAY + +;<<<<<<<<<<<<<<<<<<< MAIN CONSOL STATUS ROUTINE >>>>>>>>>>>>>>>>>>>>>> +; +; If console board is NOT installed, their is issues with default status BITS +; returning bad info keeping Serial Board form working. For now we will +; just force serial I/O and have commented out routines for CONSOLE I/O + +CSTS: + +#IF S100SDSVIDENABLE + IN A,(CONSOL_STATUS) + AND 02H + JP Z,TRYSER ;See if input from Serial Port is req + XOR A + DEC A ;RETURN WITH 0FFH IN [A] IF SOMETHING + RET +#ENDIF + +TRYSER: + +; IN A,(IOBYTE1) +; BIT 5,A ;SEE IF SERIAL PORT INPUT IS REQ +; JP Z,SERIAL_STAT ;Check if anything at Modem IN status routine + JP SERIAL_STAT ;Check if anything at Modem IN status routine +; XOR A ;IF IOBYTE bit 1 then skip modem input +; RET ;RETURN WITH 0 IN A IF NOTHING THERE + + +;<<<<<<<<<<<<<<<<<<<< MAIN CONSOL INPUT ROUTINE >>>>>>>>>>>>>>>>>>>> + +CI: + +#IF S100SDSVIDENABLE + IN A,(CONSOL_STATUS) ;NEED CONSTAT TO CLEAN UP SHIFT KEYS ETC + AND 02H + JR Z,CHKSERIAL + JP CHKSERIAL ; Force it for now + IN A,(CONSOL_IN) + AND 7FH + RET +#ENDIF + +CHKSERIAL: +; IN A,(IOBYTE1) +; BIT 5,A ;SEE IF SERIAL PORT INPUT IS REQ +; JR NZ,CI ;NO, then do normal CI + CALL SERIAL_STAT ;See if anything at Modem input + JP Z,CI ; No + JP SERIAL_IN ; Yes, lets get it + + +;>>>>>>>>>>>>>>>>>>>> MAIN PRINTER OUTPUT ROUTINE <<<<<<<<<<<<<<<<<<<<< + +LO: + LD B,0FFH +LO2: + CALL LSTAT + JR NZ,LO1 + DJNZ LO2 + XOR A + LD A,C + RET ;RET Z if Printer problem (Not switched on) +LO1: + LD A,0FFH ;Setup strobe high to low then high + OUT (PRINTER_STROBE),A + LD A,C + OUT (PRINTER_OUT),A ;Now Data + XOR A ;STROBE FOR CENTRONICS + OUT (PRINTER_STROBE),A + LD A,0FFH ;Raise strobe again + OUT (PRINTER_STROBE),A + OR A + RET ;Ret NZ if OK + +FLUSH: + LD C,FF ;Send a Form Feed to laserJet Printer + CALL LO ;This forces a partial page to be printed + RET + +;>>>>>>>>>>>>>>>>>>>>>> PRINTER STATUS ROUTINE <<<<<<<<<<<<<<<<<<<<<<<< + +LSTAT: + +#IF S100IOENABLE + IN A,(PRINTER_STATUS) + AND 00001111B ;XXXX0110 IS READY (BIT 3=PAPER BIT 2=FAULT + CP 00000110B ;BIT 1=SELECT BIT 0=BUSY + JR Z,LSTAT1 + XOR A + RET +LSTAT1: + XOR A ;PUT 0FFH IN [A] IF READY & NO ZERO FLAG + DEC A +#ENDIF + + RET + + +;-------------- BOOT RomWBW via loader ---------------- + +#IF S100WBWENABLE +BOOT_RomWBW: + + CALL ZCRLF + LD HL,RomWBW_Msg ;Print RomWBW loader sign on + CALL PRINT_STRING + JP ZSTART ; all done for now + +RomWBW_Msg: .TEXT "RomWBW Loader $" +#ENDIF + + + +;-------------- BOOT UP CPM FROM HARD DISK ON S100COMPUTERS IDE BOARD ---------------- + +;BOOT UP THE 8255/IDE Board HARD DISK/Flash Memory Card +;NOTE CODE IS ALL HERE IN CASE A 2716 IS USED + +HBOOTCPM: + POP HL ;CLEAN UP STACK + +#IF S100IOVSENABLE + LD HL,SPEAKCPM_MSG ;Announce on speaker + CALL SPEAK_ +#ENDIF + +#IF S100DIDEENABLE + CALL INITILIZE_IDE_BOARD ;Initilze the 8255 and drive (again just in case) + + LD D,11100000B ;Data for IDE SDH reg (512bytes, LBA mode,single drive) + LD E,REGshd ;00001110,(0EH) CS0,A2,A1, + CALL IDEwr8D ;Write byte to select the MASTER device + + LD B,0FFH ;Delay time to allow a Hard Disk to get up to speed +WaitInit: + LD E,REGstatus ;Get status after initilization + CALL IDErd8D ;Check Status (info in [D]) + BIT 7,D + JR Z,SECREAD ;Zero, so all is OK to write to drive + ;Delay to allow drive to get up to speed + PUSH BC + LD BC,0FFFFH +DXLAY2: + LD D,2 ;May need to adjust delay time to allow cold drive to +DXLAY1: + DEC D ;to speed + JR NZ,DXLAY1 + DEC BC + LD A,C + OR B + JR NZ,DXLAY2 + POP BC + DJNZ WaitInit ;If after 0FFH, 0FEH, 0FDH... 0, then drive initilization problem + + +IDError: + LD HL,DRIVE_NR_ERR ;Drive not ready + JP ABORT_ERR_MSG + +SECREAD: ;Note CPMLDR will ALWAYS be on TRK 0,SEC 1,Head 0 + +#IF S100IOENABLE + LD A,11111111B ;FLAG PROGRESS VISUALLY FOR DIAGNOSTIC + OUT (DIAG_LEDS),A +#ENDIF + + CALL IDEwaitnotbusy ;Make sure drive is ready + JR C,IDError ;NC if ready + + LD D,1 ;Load track 0,sec 1, head 0 + LD E,REGsector ;Send info to drive + CALL IDEwr8D + + LD D,0 ;Send Low TRK# + LD E,REGcyLSB + CALL IDEwr8D + + LD D,0 ;Send High TRK# + LD E,REGcyMSB + CALL IDEwr8D + + LD D,SEC_COUNT ;Count of CPM sectors we wish to read + LD E,REGcnt + CALL IDEwr8D + + LD D,CMDread ;Send read CMD + LD E,REGCMD + CALL IDEwr8D ;Send sec read CMD to drive. + CALL IDEwdrq ;Wait until it's got the data + + LD HL,CPM_ADDRESS ;DMA address where the CPMLDR resides in RAM + LD B,0 ;256X2 bytes + LD C,SEC_COUNT ;Count of sectors X 512 +MoreRD16: + LD A,REGdata ;REG regsiter address + OUT (IDECport),A + + OR IDErdline ;08H+40H, Pulse RD line + OUT (IDECport),A + + IN A,(IDEAport) ;read the LOWER byte + LD (HL),A + INC HL + IN A,(IDEBport) ;read the UPPER byte + LD (HL),A + INC HL + + LD A,REGdata ;Deassert RD line + OUT (IDECport),A + DJNZ MoreRD16 + DEC C + JR NZ,MoreRD16 + + LD E,REGstatus ;Check the R/W status when done + CALL IDErd8D + BIT 0,D + JR NZ,IDEerr1 ;Z if no errors + LD HL,STARTCPM + LD A,(HL) + CP 31H ;EXPECT TO HAVE 31H @80H IE. LD SP,80H + JP Z,STARTCPM ;AS THE FIRST INSTRUCTION. IF OK JP to 100H in RAM + JP ERR_LD1 ;Boot Sector Data incorrect + +IDEerr1: + LD HL,IDE_RW_ERROR ;Drive R/W Error + JP ABORT_ERR_MSG +#ENDIF + +; -------------------- SUPPORT ROUTINES ------------------------ + +INITILIZE_IDE_BOARD: ;Drive Select in [A]. Note leaves selected drive as [A] + +#IF S100DIDEENABLE + LD A,RDcfg8255 ;Config 8255 chip (10010010B), read mode on return + OUT (IDECtrl),A ;Config 8255 chip, READ mode + + ;Hard reset the disk drive + ;For some reason some CF cards need to the RESET line + ;pulsed very carefully. You may need to play around + LD A,IDEreset ;with the pulse length. Symptoms are: incorrect data comming + OUT (IDECport),A ;back from a sector read (often due to the wrong sector being read) + ;I have a (negative)pulse of 60 uSec. (10Mz Z80, two IO wait states). + + LD C,IDE_Reset_Delay ;~60 uS seems to work for the 5 different CF cards I have +ResetDelay: + DEC C + JP NZ,ResetDelay ;Delay (reset pulse width) + XOR A + OUT (IDECport),A ;No IDE control lines asserted (just bit 7 of port C) + + CALL DELAY_15 ;Need to delay a little before checking busy status + +IDEwaitnotbusy: ;Drive READY if 01000000 + LD B,0FFH + LD C,080H ;Delay, must be above 80H for 4MHz Z80. Leave longer for slower drives +MoreWait: + LD E,REGstatus ;Wait for RDY bit to be set + CALL IDErd8D + LD A,D + AND 11000000B + XOR 01000000B + JR Z,DoneNotBusy + DJNZ MoreWait + DEC C + JR NZ,MoreWait +#ENDIF + SCF ;Set carry to indicate an error + RET + +DoneNotBusy: + + OR A ;Clear carry it indicate no error + RET + + + ;Wait for the drive to be ready to transfer data. +IDEwdrq: ;Returns the drive's status in Acc +#IF S100DIDEENABLE + LD B,0FFH + LD C,0FFH ;Delay, must be above 80H for 4MHz Z80. Leave longer for slower drives +MoreDRQ: + LD E,REGstatus ;wait for DRQ bit to be set + CALL IDErd8D + LD A,D + AND 10001000B + CP 00001000B + JR Z,DoneDRQ + DJNZ MoreDRQ + DEC C + JR NZ,MoreDRQ + + SCF ;Set carry to indicate error + RET +DoneDRQ: +#ENDIF + OR A ;Clear carry + RET +; +;------------------------------------------------------------------ +; Low Level 8 bit R/W to the drive controller. These are the routines that talk +; directly to the drive controller registers, via the 8255 chip. +; Note the 16 bit I/O to the drive (which is only for SEC Read here) is done directly +; in the routine MoreRD16 for speed reasons. + +IDErd8D: ;READ 8 bits from IDE register in [E], return info in [D] +#IF S100DIDEENABLE + LD A,E + OUT (IDECport),A ;drive address onto control lines + + OR IDErdline ;RD pulse pin (40H) + OUT (IDECport),A ;assert read pin + + IN A,(IDEAport) + LD D,A ;return with data in [D] + + LD A,E ;<---Ken Robbins suggestion + OUT (IDECport),A ;Deassert RD pin + + XOR A + OUT (IDECport),A ;Zero all port C lines +#ENDIF + RET + + +IDEwr8D: ;WRITE Data in [D] to IDE register in [E] +#IF S100DIDEENABLE + LD A,WRcfg8255 ;Set 8255 to write mode + OUT (IDECtrl),A + + LD A,D ;Get data put it in 8255 A port + OUT (IDEAport),A + + LD A,E ;select IDE register + OUT (IDECport),A + + OR IDEwrline ;lower WR line + OUT (IDECport),A + + LD A,E ;<-- Kens Robbins suggestion, raise WR line + OUT (IDECport),A + + XOR A ;Deselect all lines including WR line + OUT (IDECport),A + + LD A,RDcfg8255 ;Config 8255 chip, read mode on return + OUT (IDECtrl),A +#ENDIF + RET + +;------------------------------------------------------------------------------------- + +;MEMORY MAP PROGRAM CF.DR.DOBBS VOL 31 P40. +;IT WILL SHOW ON CONSOL TOTAL MEMORY SUMMARY OF RAM,PROM, AND NO MEMORY +; +MEMMAP: + CALL ZCRLF + LD HL,0 + LD B,1 +MAP1: + LD E,'R' ;PRINT R FOR RAM + LD A,(HL) + CPL + LD (HL),A + CP (HL) + CPL + LD (HL),A + JR NZ,MAP2 + CP (HL) + JR Z,PRINT +MAP2: + LD E,'P' ; Print P for prom +MAP3: + LD A,0FFH + CP (HL) + JR NZ,PRINT + INC L + XOR A + CP L + JR NZ,MAP3 + LD E,'.' ; Print . for no memory +PRINT: + LD L,0 + DEC B + JR NZ,NLINE + LD B,16 + CALL ZCRLF + CALL HXOT4 +NLINE: + LD A,SPACE + CALL OTA + LD A,E + CALL OTA + INC H + JR NZ,MAP1 + CALL ZCRLF + CALL ZCRLF + JP ZSTART + +;16 HEX OUTPUT ROUTINE + +HXOT4: + LD C,H + CALL HXO2 + LD C,L +HXO2: + LD A,C + RRA + RRA + RRA + RRA + CALL HXO3 + LD A,C +HXO3: + AND 0FH + CP 10 + JR C,HADJ + ADD A,7 +HADJ: + ADD A,30H +OTA: + PUSH BC + LD C,A + CALL ZCO ;SEND TO CONSOL + POP BC + RET + +;-------------DISPLAY MEMORY IN HEX + +DISP: CALL EXLF ;GET PARAMETERS IN [HL],[DE] + LD A,L ;ROUND OFF ADDRESSES TO XX00H + AND 0F0H + LD L,A + LD A,E ;FINAL ADDRESS LOWER HALF + AND 0F0H + ADD A,10H ;FINISH TO END 0F LINE +SF172: + CALL LFADR +SF175: + CALL BLANK + LD A,(HL) + CALL ZLBYTE + CALL HILOX + LD A,L + AND 0FH + JR NZ,SF175 + LD C,TAB ;INSERT A TAB BETWEEN DATA + CALL ZCO + LD B,4H ;ALSO 4 SPACES +TA11: + LD C,SPACE + CALL ZCO + DJNZ TA11 + LD B,16 ;NOW PRINT ASCII (16 CHARACTERS) + PUSH DE ;TEMPORLY SAVE [DE] + LD DE,0010H + SBC HL,DE + POP DE +T11: + LD A,(HL) + AND 7FH + CP ' ' ;FILTER OUT CONTROL CHARACTERS' + JR NC,T33 +T22: + LD A,'.' +T33: + CP 07CH + JR NC,T22 + LD C,A ;SET UP TO SEND + CALL ZCO + INC HL + DJNZ T11 ;REPEAT FOR WHOLE LINE + JR SF172 + +BLANK: + LD C,' ' + JP ZCO + +;-----------------INSPECT AND / OR MODIFY MEMORY + +SUBS: + LD C,1 + CALL ZHEXSP + POP HL +SF2E3: + LD A,(HL) + CALL ZLBYTE + LD C,'-' + CALL ZCO + CALL ZPCHK + RET C + JR Z,SF2FC + CP 5FH + JR Z,SF305 + PUSH HL + CALL EXF + POP DE + POP HL + LD (HL),E + LD A,B + CP CR + RET Z +SF2FC: + INC HL +SF2FD: + LD A,L + AND 07H + CALL Z,LFADR + JR SF2E3 +SF305: + DEC HL + JR SF2FD + +;----------------FILL A BLOCK OF MEMORY WITH A VALUE + +FILL: + CALL EXPR3 +SF1A5: + LD (HL),C + CALL HILOX + JR NC,SF1A5 + POP DE + JP ZSTART + +;---------------GO TO A RAM LOCATION + +GOTO: LD C,1 ;SIMPLE GOTO FIRST GET PARMS. + CALL HEXSP + CALL CRLF + POP HL ;GET PARAMETER PUSHED BY EXF + JP (HL) + +;--------------GET OR OUTPUT TO A PORT + +QUERY: + CALL ZPCHK + CP 'O' ;OUTPUT TO PORT + JR Z,SF77A + CP 'I' ;INPUT FROM PORT + JP Z,QQQ1 + LD C,'*' + JP ZCO ;WILL ABORT IF NOT 'I' OR 'O' +QQQ1: + LD C,1 + CALL ZHEXSP + POP BC + IN A,(C) + JP ZBITS +; +SF77A: + CALL ZHEXSP + POP DE + POP BC + OUT (C),E + RET + + +;--------------MEMORY TEST + +RAMTEST: + CALL EXLF +SF200: + LD A,(HL) + LD B,A + CPL + LD (HL),A + XOR (HL) + JR Z,SF215 + PUSH DE + LD D,B + LD E,A ;TEMP STORE BITS + CALL ZHLSP + CALL BLANK + LD A,E + CALL ZBITS + CALL ZCRLF + LD B,D + POP DE +SF215: + LD (HL),B + CALL HILOX + JR SF200 + +;---------------MOVE A BLOCK OF MEMORY TO ANOTHER LOCATION + +MOVE: + CALL EXPR3 +SF21E: + LD A,(HL) + LD (BC),A + INC BC + CALL HILOX + JR SF21E + +;---------------VERIFY ONE BLOCK OF MEMORY WITH ANOTHER + +VERIFY: + CALL EXPR3 +VERIO: + LD A,(BC) + CP (HL) + JR Z,SF78E + PUSH BC + CALL CERR + POP BC +SF78E: + INC BC + CALL HILOX + JR VERIO + RET +; +CERR: + LD B,A + CALL ZHLSP + LD A,(HL) + CALL ZLBYTE + CALL BLANK + LD A,B + CALL ZLBYTE + JP ZCRLF + +ECHO: + CALL CI ;Routine to check keyboard etc. + CP 'C'-40H ;Loop until ^C + RET Z + CP 'Z'-40H + RET Z + LD C,A + CALL CO + JR ECHO + + +;Display Extended memory map for 1MG RAM using IA-2 Z80 Board window registers + +XMEMMAP: + LD HL,MSG17 ;Get segment (0-F) + CALL PRINT_STRING + LD C,1 + CALL ZHEXSP ;Get 2 or 4 hex digits (count in C). + POP HL + LD A,L ;Get single byte value + AND 0FH + EXX + LD D,A ;Store in D' for 000X:YYYY display below + SLA A + SLA A + SLA A + SLA A + OUT (Z80PORT+2),A ;Re-map to first 16K in segment:64K Space + LD E,A ;store shifted nibble in E' + LD HL,0 ;Will store 0-FFFF for total RAM display (not actual access) + EXX + LD D,0 ;Total display line count (256 characters, 16 lines X 16 characters) + + CALL ZCRLF + LD HL,0 + LD B,1 +XMAP1: + LD A,H + AND 00111111B ;Wrap 16K window + LD H,A + LD E,'R' ;PRINT R FOR RAM + LD A,(HL) + CPL + LD (HL),A + CP (HL) + CPL + LD (HL),A ;Save it back + JR NZ,XMAP2 + CP (HL) + JR Z,XPRINT +XMAP2: + LD E,'p' +XMAP3: + LD A,0FFH + CP (HL) + JR NZ,XPRINT + INC L + XOR A + CP L + JR NZ,XMAP3 + LD E,'.' +XPRINT: + LD L,0 + DEC B + JR NZ,XNLINE + LD B,16 + CALL ZCRLF + CALL SET_WINDOW + LD A,SPACE + JR XN11 +XNLINE: + LD A,SPACE + CALL OTA + LD A,E +XN11: + CALL OTA + INC H + INC D ;Are we done yet + JR NZ,XMAP1 + CALL ZCRLF + XOR A + OUT (Z80PORT+2),A ;Set RAM window back to the way it was + JP ZSTART + +SET_WINDOW: ;Setup the unique IA-II Z80 board window to address > 64k + EXX + LD C,D ;Print seg value + CALL HXO2 + LD C,':' + CALL CO + CALL HXOT4 ;Print HL' (not origional HL) + + LD A,H ;get current H being displayed (Already pointed to first 16K window) +NOTW0: + CP 40H + JR NZ,NOTW1 + LD A,E + ADD A,04H ;Window for 4,5,6,7, set to H from above + JR DOWIN + +NOTW1: + CP 80H + JR NZ,NOTW2 + LD A,E + ADD A,08H ;Window for 8,9,A,B set to H from above + JR DOWIN + +NOTW2: + CP 0C0H + JR NZ,NOTW3 ;Must be values in between + LD A,E + ADD A,0CH ;Window for 4,5,6,7, set to H from above +DOWIN: + OUT (Z80PORT+2),A ;Re-map to first 16K in segment:64K Space +NOTW3: LD A,H + ADD A,10H + LD H,A + EXX ;Get back normal register set + RET + + +;Place an 8086 a Far Jump at F000:FFF0H (FFFF0H) to 500H in RAM for the 8086/80286 +;If there is a ROM there nothing will change and the 8086 reset/boot will jump +;from F000:FFF0 to the start or the ROM monitor at F000:FC00H. If however +;no ROM is present the 8086 will find the RAM code below and jump to 500H in RAM +;Whatever is at that location will then run - usually CPM86. + +UP8086: + LD A,0FCH ;Point to 8086 Reset location + OUT (Z80PORT+2),A ;Re-map to 0000H to FC000H + LD HL,3FF0H + LD (HL),0EAH + INC HL + LD (HL),0H + INC HL + LD (HL),05H + INC HL + LD (HL),0H + INC HL + LD (HL),0H + INC HL + LD (HL),0F4H ;Put an 8086 HLT here just in case + +; LD (HL),0B0H ;Continously put "3" on Consol via port 01 +; INC HL ;Basic test for 8086 on reset +; LD (HL),33H +; INC HL +; LD (HL),0E6H +; INC HL +; LD (HL),01H +; INC HL +; LD (HL),0EBH +; INC HL +; LD (HL),0FAH + + XOR A + OUT (Z80PORT+2),A ;Re-map back to 0H + JP SWITCH_8086 ;Switch over control to the 8086 + +;----------------READ ASCII FROM MEMORY + +TYPE: + CALL EXLF +SF30B: + CALL LFADR + LD B,56 +SF310: + LD A,(HL) + AND 7FH + CP SPACE + JR NC,SF319 +SF317: + LD A,2EH +SF319: + CP 7CH + JR NC,SF317 + LD C,A + CALL ZCO + CALL HILOX + DJNZ SF310 + JR SF30B + + +;-------------Display all active I/O input-ports in the system +; +INPORTS: + CALL ZCRLF + LD B,0 ;Now loop through all ports (0-FF) + LD D,6 ;Display 6 ports across + LD E,0FFH ;Will contain port number +LOOPIO: + LD C,E + LD A,E + ; Special Case here! + CP SW86 ;Inputing here will switch out the Z80 to 8086/80286 + JR Z,SKIP + CP SW68K ;Also this one (68K) + JR Z,SKIP +; + IN A,(C) ;Remember [ZASMB does not work with this opcode,SLR is OK] + CP 0FFH ;No need for 0FF's + JR Z,SKIP + LD H,A ;store port data in H for below + LD A,E ;Need to print port # first + CALL LBYTE ;Print port number + LD C,'-' + CALL ZCO + LD C,'>' + CALL ZCO + LD A,H ;get back port data + CALL LBYTE ;print it + LD C,TAB + CALL ZCO + DEC D ;6 ports per line + JR NZ,SKIP + LD D,6 + CALL ZCRLF +SKIP: + DEC E ;Next Port + DJNZ LOOPIO + CALL ZCRLF + RET + + +; +;--------------S100Computers Serial I/O Board Initilization +;Note both Zilog SCC serial ports (A & B) will be set to 38,400 Baud initially. + +#IF S100IOENABLE + +INIT_S100_IO: + +#IF S100IO8255ENABLE + ;First the 8255 +; LD A,AinBout8255cfg ;A input, B output, C(bits 0-3) output, (bits 4-7)input + LD A,AoutBin8255cfg ;A Out to Hex LED, B In Dip Switch, C(bits 0-3) output, (bits 4-7)input + OUT (PortCtrl_8255),A ;Config 8255 chip, Mode 0 +#ENDIF + +#IF S100IOSCCAENABLE + ;Then the SCC + LD A,ACTL ;Program Channel A + LD C,A + + ; WARNING, 0x0e (14) is not the complete table below + ; it looks like this can be extended to init the int (same below) + LD B,0EH ;Byte count for OTIR below + + LD HL,SCCINIT + OTIR +#ENDIF + +; +#IF S100IOSCCBENABLE + LD A,BCTL ;Program Channel B + LD C,A + LD B,0EH ;Byte count for OTIR below + LD HL,SCCINIT + OTIR +#ENDIF + +#ENDIF ; S100IOENABLE + + RET +; +; ALL SSC's are set for 19,200 BAUD, can be changed below +; + +#IF S100IOSCCAENABLE | S100IOSCCBENABLE +SCCINIT: + .DB 04H ;Point to WR4 + .DB 44H ;X16 clock,1 Stop,NP +; + .DB 03H ;Point to WR3 + .DB 0C1H ;Enable reciever, Auto Enable, Recieve 8 bits +; .DB 0E1H ;Enable reciever, No Auto Enable, Recieve 8 bits (for CTS bit) +; + .DB 05H ;Point to WR5 + .DB 0EAH ;Enable, Transmit 8 bits, Set RTS,DTR, Enable +; + .DB 0BH ;Point to WR11 + .DB 56H ;Recieve/transmit clock = BRG +; + .DB 0CH ;Point to WR12 +; .DB 40H ;Low Byte 2400 Baud +; .DB 1EH ;Low Byte 4800 Baud +; .DB 0EH ;Low Byte 9600 Baud +; .DB 06H ;Low byte 19,200 Baud <<<<<<<<<<< + .DB 02H ;Low byte 38,400 Baud +; .DB 00H ;Low byte 76,800 Baud +; + .DB 0DH ;Point to WR13 + .DB 00H ;High byte for Baud +; + .DB 0EH ;Point to WR14 + .DB 01H ;Use 4.9152 MHz Clock. Note SD Systems uses a 2.4576 MHz clock, enable BRG +; + .DB 0FH ;Point to WR15 + .DB 00H ;Generate Int with CTS going high + + NOP ; ?? why?? + NOP + NOP +#ENDIF + +;---------------------------------------------------------------------------- + .ORG VERSA ;<--------- THIS LOCATION MUST NOT BE CHANGED (F800H) + ;My old CPM V1.4 systems are counting on it being here +; +; VERSAFLOPPY II DOS SYSTEM LINKAGES (USED BY SDOS & 2.2 CP/M) +; These are residule JP's for old CPM BIOS'es. Only LOADER is now functional. + +FBOOT: JP BOOT ;COLD START ENTRY +WBOOT: JP BIOS_JP_ERR ;WARM START ENTRY +CSE: JP ZCSTS ;CONSOLE STATUS +CIE: JP ZCI ;CONSOLE IN +COE: JP ZCO ;CONSOLE OUT +LIST: JP ZLO ;TO MONITOR FOR PRINTER +PUNCH: JP ZPOO ;TO MONITOR FOR PUNCH +READR: JP ZRI ;TO MONITOR FOR READER +HME: JP BIOS_JP_ERR ;HOME , MOVE TO TRACK 0 +SDSKE: JP BIOS_JP_ERR ;SELDSK +S_TRKE: JP BIOS_JP_ERR ;SET_TRK +SSECE: JP BIOS_JP_ERR ;SETSEC +SDMAE: JP BIOS_JP_ERR ;SETDMA +RDE: JP BIOS_JP_ERR ;READF +WRE: JP BIOS_JP_ERR ;WRITEF +LISTS: JP LSTAT ;LIST STATUS +SECTR: JP BIOS_JP_ERR ;SECTRAN FOR 2.2 SECTOR TRANSLATION TABLE + +DTYPE: JP BIOS_JP_ERR ;UNITSL SET UP @UNIT BYTE (DISK DENSITY) +SVE: JP BIOS_JP_ERR ;SAVER SAVE N RECORDS +LDE: JP LOADER ;LOADER LOAD N SECTORS FROM TRACK 0 (& TRACK 1) + +BIOS_JP_ERR: + LD HL,BIOS_ERR ;"BIOS JMP longer implemented in ROM @ F800H." + JP ABORT_ERR_MSG + + + + +;BOOT LOADS A SECTOR TO 80H AND THEN JUMPS TO 80H +;NOTE. Two FDC Boards are supported here:- +; +; VFDC_BOOT Boots CPM from the Versafloppy-II disk controller board +; ZFDC_BOOT Boots CPM from the ZFDC controller board + +VBOOT: + XOR A ;0 = Flag as Boot from Versafloppy II FDC + JR BOOT_COLD + +ZBOOT: + XOR A + DEC A ;0FFH = Flag as Boot from ZFDC FDC + +BOOT_COLD: + LD (_FDCTYPE),A ;0 for VF, 0FFH for ZFDC + +BOOT: + +#IF S100IO8255ENABLE + LD A,11111111B ;FLAG PROGRESS VISUALLY FOR DIAGNOSTIC + OUT (DIAG_LEDS),A +#ENDIF + +#IF S100IOVSENABLE + LD HL,SPEAKCPM_MSG ;Announce on speaker + CALL SPEAK_ +#ENDIF + + XOR A + LD (CDISK1),A ;MAKE CURRENT DISK A: + LD (CIOBYTE),A ;CLEANUP IOBYTE + LD (_UNIT),A ;8LOAD.Z80 (The first sector loader module) will count on this being 0H + ;for the Versafloppy-II boots + LD (ZERO_L),A ;These need to be zero's here for the CPM Loader/Versafloppy-II of my old + LD (ZERO_H),A ;NON-BANKED CPM3 or CPM2.2 disks. Need to later find out why! + LD HL,128 ;Assume 128 byte sectors for 8" disk + LD (_SEC_SIZE),HL + +BOOTW1: LD SP,_SSTACK + LD A,(_FDCTYPE) ;Are we using a Versafloppy II or ZFDC FDC board + OR A + JP NZ,ZFDC_BOOT ;<<<<<<<<< Go to ZFDC Board BOOT >>>>>>>>>>>>> + +VFDC_BOOT: +#IF S100VFIIENABLE + LD HL,BOOT_MSG0 ;<<<<<<<<< BOOT FROM VERSAFLOPPY-II >>>>>>>>>>>> + CALL PRINT_STRING ;"Loading CPM from VF FDC" + LD HL,VF_MSG + CALL PRINT_STRING + + LD A,0D0H ;FORCE CHIP INTERUPT + OUT (CMD),A + + LD A,STDSDT ;SETUP FOR SD + LD (_COUNT),A ;STORE AS 26 SECTORS/TRACK + LD A,0FEH + OUT (SELECT),A ;Select Drive A: (Always) + + XOR A + LD (_TRK),A + INC A + LD (_SCTR),A + + CALL READY_CHK ;Critical to make sure chip is ready first! + LD A,RSCMD ;RESTORE COMMAND (Note 3 Ms seek) + OUT (CMD),A + CALL READY_CHK ;Critical to make sure chip is ready first! + + LD HL,COLD + LD (_TADDR),HL + + CALL VF_READ_SECTOR ;Read the Boot Sector +BOOT_SEC_READ: + JP NZ,ERR_LD +BOOT_SEC_CHECK: + LD HL,COLD + LD A,(HL) + CP 31H ;EXPECT TO HAVE 31H @80H IE. LD SP,80H + JP Z,COLD ;AS THE FIRST INSTRUCTION. IF OK JP 80H + JP ERR_LD1 ;Boot Sector Data incorrect + + +VF_READ_SECTOR: ;READ SECTOR COMMAND + LD B,3 ;Will Try 3 times +READ1: PUSH BC + CALL DRINIT ;Setup sector paramaters + LD A,E + CP 80H ;128 or 512 byte sectors ? + LD B,128 + DI + LD A,RDCMD + OUT (CMD),A ;Note wait states are now switched on + + JR M2 +M2: + JR MM2 +MM2: + JR Z,RD_128 + LD B,0 ;256 X 2 + INIR ;[C]-> [HL++],[B--] +RD_128: + INIR + + EI + CALL WAITF ;Wait states are now off + IN A,(STATUS) + AND SRMASK ;Check sector was read OK + POP BC + RET Z + DEC B + JR NZ,READ1 + XOR A + DEC A + RET ;Return NZ if failure after 3 reads + + +DRINIT: + CALL SEEK ;DRIVE INITIALIZATION + LD HL,(_TADDR) ;SETUP DMA ADDRESS AND BYTE COUNT + LD A,(_SCTR) + OUT (SECTOR),A + + LD DE,(_SEC_SIZE) ;This will be 128 or 512 sectors + LD C,DATA ;8067H in BC + +SWEB: + IN A,(SELECT) ;ENABLE WAIT STATES + AND 7FH + OUT (SELECT),A + RET + + +; SEEK TRACK +SEEK: LD A,(_TRK) + LD C,A + IN A,(TRACK) + CP C + RET Z ;IF SAME TRACK NO NEED TO SEEK + + LD A,(_TRK) + OUT (DATA),A + CALL READY_CHK ;Critical to make sure chip is ready first! + LD A,FSKCMD ;Send Seeek Command to WD1791 + OUT (CMD),A + CALL DELAY_15 ;Delay ~15ms + CALL READY_CHK + IN A,(TRACK) + LD C,A + LD A,(_TRK) + CP C + RET Z + LD HL,SEEK_ERROR_MSG + JP ABORT_ERR_MSG + + +READY_CHK: + LD BC,0 +READY_CHK1: + IN A,(STATUS) + AND 1 + RET Z + DEC BC + LD A,C + OR B + JP NZ,READY_CHK1 ;Wait until 1791/5 is ready + JP WAIT3 + +WAITF: LD E,0 + PUSH BC + LD C,2 +WAIT2: IN A,(STATUS) + AND 1 + JR Z,DWAIT + DJNZ WAIT2 + DEC E + JR NZ,WAIT2 + DEC C + JR NZ,WAIT2 + POP BC +WAIT3: IN A,(SELECT) ;IF BY THIS TIME NOT READY FORCE + OR 80H ;A HARDWARE RESET + OUT (RSET),A + LD HL,VF_HUNG + JP ABORT_ERR_MSG + + +; DISABLE WAIT STATES +DWAIT: POP BC ;TO BALANCE THE ABOVE PUSH IN WAIT +DDWAIT: IN A,(SELECT) + OR 80H + OUT (SELECT),A + RET + +#ENDIF + +DELAY_15: ;DELAY ~15 MS + LD A,40 +DELAY1: LD B,0 +M0: DJNZ M0 + DEC A + JR NZ,DELAY1 + RET + +DELAY_150: ;DELAY ~150 MS + LD C,10 +DELAY320A: + CALL DELAY_15 + DEC C + JP NZ,DELAY320A + RET + + + +LOADER: LD A,(_FDCTYPE) ;Are we using a Versafloppy II or ZFDC FDC board + OR A + JP NZ,ZFDC_LOADER ;Go to ZFDC Board Loader + + + ; LOAD A NUMBER OF SECTORS +VF_LOADER: +#IF S100VFIIENABLE + CALL VF_READ_SECTOR + JP NZ,ERR_LD + LD C,'.' ;Show progress + CALL CO + CALL INCP + JR NZ,VF_LOADER +#ENDIF + RET + +; INC SECTOR AND TRACK +INCP: + LD HL,(_TADDR) + LD DE,(_SEC_SIZE) ;128 or 512 byte sectors +INCP2: + ADD HL,DE + LD (_TADDR),HL + LD HL,_NREC + DEC (HL) + RET Z ;Return when we have done all sectors (~51) + LD HL,_SCTR + INC (HL) + LD A,(_COUNT) ;IS ONE TRACK DONE YET (Sec/track+1) + INC A + CP (HL) + RET NZ ;IF FULL Z, THEN GO TO NEXT TRACK + LD (HL),1 ;SET SECTOR COUNT BACK TO 1 + INC HL ;ASSUMES @TRK=SECTOR+1 IE 44H + INC (HL) + OR A ;MAKE SURE TO RETURN NZ + RET + + +ERR_NR: + LD HL,DRIVE_NR_ERR ;"DRIVE NOT READY + JP ABORT_ERR_MSG +ERR_LD: + LD HL,BOOT_LD_ERR ;"ERROR READING BOOT/LOADER SECTORS" + JP ABORT_ERR_MSG +ERR_LD1: + LD HL,BOOT_LD1_ERR ;"DATA ERROR IN BOOT SECTOR" + +ABORT_ERR_MSG: + CALL PRINT_STRING + JP ZAPPLE ;BACK TO START OF MONITOR. + + +;---------------------- ZFDC FDC BOOT & LOADER ---------------------------------- + +ZFDC_BOOT: ;Cold Boot with ZFDC FDC Board +#IF S100ZFDCENABLE + LD HL,BOOT_MSG0 ;<<<<<<<<< BOOT FROM ZFDC BOARD >>>>>>>>>>>>>> + CALL PRINT_STRING ;"Loading CPM from ZFDC FDC" + LD HL,ZFDC_MSG + CALL PRINT_STRING + + OUT (RESET_ZFDC_PORT),A ;Do a hardware reset. Does not matter what is in [A] + + LD A,STATUS_DELAY ;~0.5 second at 10 MHz + LD BC,0 ;Delay to allow board to setup hardware +WAIT_D: + DEC B + JR NZ,WAIT_D ;Delay for ~0.5 seconds + DEC B ;Reset B to 0FFH + DEC C + JR NZ,WAIT_D + DEC A + JR NZ,WAIT_D + + IN A,(S100_DATA_B) ;Check the board is there + CP CMD_HANDSHAKE ;Make sure we get HANDSHAKE byte back + JP NZ,ERR_NR ;If error, just abort + + LD A,CMD_HANDSHAKE ;Send another byte just to be sure. + OUT (S100_DATA_B),A ;This clears up ints on ZFDC board + CALL WAIT_FOR_ACK ;Wait to make sure all is well. + OR A + JP NZ,ERR_NR ;If error, just abort + + LD C,CMD_SET_FORMAT ;Send Set Disk Format to 8" SSSD DISK + CALL S100OUT + LD C,0 ;Floppy Drive 0, (ZFDC Board expects a 0H, 1H, 2H or 3H) + CALL S100OUT + LD C,STD8IBM ;ZFDC Board expects a Disk Format Table Number (0,1,2...13H) + CALL S100OUT + CALL WAIT_FOR_ACK ;Return Z (and NO_ERRORS_FLAG in [A]), or NZ with error # in [A] + JP NZ,ERR_NR ;If error, just abort + + LD C,CMD_SET_DRIVE ;Send a "Set Drive CMD" to ZFDC board + CALL S100OUT + LD C,0 ;Floppy Drive #, (ZFDC Board expects a 0H, 1H, 2H or 3H) + CALL S100OUT + CALL WAIT_FOR_ACK ;Return Z (and NO_ERRORS_FLAG in [A]), or NZ with error # in [A] + JP NZ,ERR_NR ;If error, just abort + + ;Drive selected and ready to read sectors. Note this code + ;is written to eb compatible with the boot loader for the + ;Versafloppy-II disk controller as well. + + LD A,STDSDT ;SETUP FOR SD + LD (_COUNT),A ;STORE AS 26 SECTORS/TRACK + + XOR A ;Setup Boot Sector read track + LD (_TRK),A + INC A + LD (_SCTR),A + LD (_NREC),A ;read only 1 sector initially + + LD HL,COLD + LD (_TADDR),HL + + CALL ZFDC_MULTI_READ_SECTOR ;Actully we will only read one sector here + JP BOOT_SEC_READ ;JMP to same section as for Versafloppy boot + + +ZFDC_MULTI_READ_SECTOR: + LD C,CMD_SET_TRACK ;Set Track + CALL S100OUT + LD A,(_TRK) + LD C,A + CALL S100OUT ;Send Selected track HEX number + CALL WAIT_FOR_ACK ;Return Z (and NO_ERRORS_FLAG in [A]), or NZ with error # in [A] + JP NZ,ERR_NR ;If error, just abort + + LD C,CMD_SET_SECTOR ;Set Sector # to side A (or for DS disks also side B) + CALL S100OUT + LD A,(_SCTR) + LD C,A + CALL S100OUT ;Send Selected sector HEX number + CALL WAIT_FOR_ACK ;Return Z (and NO_ERRORS_FLAG in [A]), or NZ with error # in [A] + JP NZ,ERR_NR ;If error, just abort + + LD C,CMD_SEEK_TRACK ;Later can let board do this + CALL S100OUT + CALL WAIT_FOR_ACK ;Return Z (and NO_ERRORS_FLAG in [A]), or NZ with error # in [A] + JP NZ,ERR_NR ;If error, just abort + + LD C,CMD_RD_MULTI_SECTOR ;Routine assumes r.EQUired Drive Table,Drive,Side,Track, and sector are already sent to board + CALL S100OUT ;(Note [HL]-> Sector DMA address) + LD A,(_NREC) ;How many sectors + LD C,A + CALL S100OUT + CALL WAIT_FOR_ACK ;Wait for NO_ERRORS_FLAG to come back + JP NZ,ERR_NR ;If error, just abort + + LD HL,(_TADDR) ;Set DMA address + +MULTI_RD_SEC: + LD DE,(_SEC_SIZE) ;For CPM this will be 128 Byte sector(s) +RD_SEC: + CALL S100IN ;Note potential to lockup here & below (but unlightly) + LD (HL),A + INC HL + DEC DE + LD A,E + OR D + JR NZ,RD_SEC + + LD A,(_NREC) ;How many sectors of data worth + DEC A + LD (_NREC),A + JR NZ,MULTI_RD_SEC ;Are there more + + CALL WAIT_FOR_ACK ;Return Z (and NO_ERRORS_FLAG in [A]), or NZ with error # in [A] + RET + + +S100OUT: + IN A,(S100_STATUS_B) ;Send data to ZFDC output (arrive with character to be sent in C) + BIT DIRECTION_BIT,A ;Is ZFDC in output mode, if not wait + JR NZ,S100OUT + BIT DATA_OUT_RDY,A ;Has previous (if any) character been read. + JR Z,S100OUT ;Z if not yet ready + LD A,C + OUT (S100_DATA_B),A + RET + +S100STAT: + IN A,(S100_STATUS_B) ;Check if ZFDC has any data for S-100 system + BIT DATA_IN_RDY,A ;Anything there ? + RET Z ;Return 0 if nothing + XOR A + DEC A ;Return NZ, & 0FFH in A if something there + RET + +S100IN: + IN A,(S100_STATUS_B) ;Check if ZFDC has any data for S-100 system + BIT DIRECTION_BIT,A ;Is ZFDC in input mode, if not wait + JR Z,S100IN ;If low then ZFDC board is still in input mode, wait + BIT DATA_IN_RDY,A + JR Z,S100IN + IN A,(S100_DATA_A) ;return with character in A + RET + +WAIT_FOR_ACK: ;Delay to wait for ZFDC to return data. There is a timeout of about 2 sec. + PUSH BC ;This can be increased if you are displaying debugging info on the ZFDC + PUSH DE ;HEX LED display. + LD BC,0 + LD E,STATUS_DELAY ;Timeout, (about 2 seconds) +WAIT_1: + IN A,(S100_STATUS_B) ;Check if ZFDC has any data for S-100 system + BIT DIRECTION_BIT,A ;Is ZFDC in input mode + JR Z,WAIT_2 ;if low then ZFDC is still in input mode + CALL S100STAT ;Wait until ZFDC Board sends something + JR Z,WAIT_2 + CALL S100IN ;Get returned Error # (Note this releases the SEND_DATA routine on the ZFDC board) + CP NO_ERRORS_FLAG ;Was SEND_OK/NO_ERRORS_FLAG sent back from ZFDC Board + POP DE ;Balance up stack + POP BC + RET ;Return NZ if problem, Z if no problem +WAIT_2: DEC B + JR NZ,WAIT_1 ;Try for ~2 seconds + DEC B ;Reset B to 0FFH + DEC C + JR NZ,WAIT_1 + DEC B ;Reset B to 0FFH + DEC C + DEC E + JR NZ,WAIT_1 + XOR A + DEC A + POP DE ;Balance up stack + POP BC + RET ;Return NZ flag set if timeout AND 0FFH in [A] + +#ENDIF + +; LOAD A NUMBER OF SECTORS ;Note this loader utilizes the fast multi-sec read in V2.8 of later + +ZFDC_LOADER: ;CPM Loader with ZFDC FDC Board +#IF S100ZFDCENABLE + CALL ZFDC_MULTI_READ_SECTOR ;Note the Boot sector has by now setup the sector count etc. in low RAM +#ENDIF + RET + + +;---------------------------------------------------------------------------- +; Module to boot MSDOS from 5" DDDS disk (Note this module has not been updated yet) +; +MSDOS: + +#IF S100IOVSENABLE + LD HL,SPEAKDOS_MSG ;Announce on speaker + CALL SPEAK_ +#ENDIF + + CALL CRLF + + JP ERR_NR ;Not done Yet + +; LD A,4 ;MSDOS.SYS STARTS AT SECTOR 4 SIDE B +; LD (_SCTR),A +; LD A,0 +; LD (_TRK),A ;START ON TRACK 0 +; LD A,1 +; LD (_SIDE),A ;START ON SIDE B +; LD A,FFILE_SIZE ;SIZE OF DOS IN 512 BYTE SECTORS +; LD (_NREC),A +; +; LD A,01110100B ;0,DD,5",SIDE 1, 0100=D: +; CALL MDSEL +; JP NZ,ERR_NR ;ROUTINE TO SAY DRIVE NOT READY +; LD A,RSVCMD ;SEND RESTORE COMMAND +; CALL DCMDI +; JR Z,DGETID +;DOS1: +; LD HL,RESTORE_ERR ;RESTORE FAILED +; JP ABORT_ERR_MSG +; +;DGETID: +; CALL DIDRD +; JR NZ,DOS1 +; +;GETSEC: +; LD HL,STARTDOS +;DGET1: +; LD C,'.' ;to indicate on CRT sectors read +; CALL CO +; LD A,(_SCTR) +; OUT (SECTOR),A +; LD B,0 ;256 BYTES +; LD C,DATA ;DATA PORT +; DI ;just in case +; CALL SWEB ;SET WAIT ENABLE BIT +; LD A,RDCMD +; OUT (CMD),A +; INIR +; INIR ;512 BYTES TOTAL +; LD B,0 +;DWAITF: +; IN A,(STATUS) +; AND 1 +; DJNZ DWAITF +; +; CALL DDWAIT +; +; IN A,(STATUS) ;CHECK STATUS +; AND 0FEH +; JP NZ,ERR_LD ;ROUTINE TO SAY SECTOR READ ERROR +; +; LD A,(_NREC) +; DEC A +; LD (_NREC),A +; JP Z,STARTDOS +; +; LD A,(_SCTR) +; INC A +; LD (_SCTR),A +; CP 0AH ;end of track yet? +; JR NZ,DGET1 +; +; LD A,(_SIDE) +; CP 1 ;if on track 1 go to side 1 else side 0 +; JR Z,TRK1A +; LD A,1 ;FLAG CURRENT SIDE IS NOW B +; LD (_SIDE),A +; LD A,01110100B ;SWITCH TO SIDE B +; JR TRK1B +;TRK1A: +; LD A,(_TRK) +; INC A +; LD (_TRK),A +; LD A,0 +; LD (_SIDE),A ;FLAG CURRENT SIDE IS NOW A +; LD A,01100100B ;SWITCH TO SIDE A +;TRK1B: +; CALL MDSEL +; JP NZ,ERR_NR ;ROUTINE TO SAY DRIVE NOT READY +; +;DSEC: +; LD A,1 +; LD (_SCTR),A +; +; LD A,(_TRK) +; OUT (DATA),A +; LD A,MSKCMD ;SEEK TO TRACK WITH VERIFY +; CALL DCMDI +; JP Z,DDRS3 +;DSEC1: +; LD HL,MSGH4 ;SEEK ERROR MESSAGE +; JP ABORT_ERR_MSG +; +;xxxz: HALT + +;DDRS3: +; PUSH HL +; CALL DIDRD +; POP HL +; JR NZ,DSEC1 +; JP DGET1 +; +;DIDRD: +; LD HL,_IDSV +; LD BC,600H+DATA +; CALL SWEB +; LD A,RDACMD ;SEND READ ID COMMAND +; OUT (CMD),A +; INIR +;DWAITS: +; IN A,(STATUS) +; AND 1 +; JR NZ,DWAITS +; CALL DDWAIT ;DISABEL WAIT STATE GENERATOR +; LD A,(_IDSV) ;++++++++++++++ +; LD B,A +; LD A,(_TRK) +; CP B ;RETURN WITH Z IF AT RIGHT TRACK +; RET + +;MDSEL: +; CPL +; OUT (SELECT),A +;DRDYCK: +; IN A,(STATUS) +; AND 80H +; JP NZ,DRDYCK +; RET +; +;SEND TYPE 1 COMMANDS (RESTORE,SEEK,STEP) +; +;DCMDI: +; LD (_CMDSV),A ;TEMPORLY STORE COMMAND +; LD A,80H +; LD (_ERMASK),A +;DCMDI1: +; IN A,(STATUS) ;IS 1793 READY +; AND 01H +; JP NZ,DCMDI1 +; LD A,(_CMDSV) +; OUT (CMD),A +; CALL DELAY_15 ;DELAY R.EQUIRED FOR A VALID STATUS +;DEEND: +; IN A,(STATUS) ;END OF DISK COMMANDS ROUTINE +; AND 01H +; JP NZ,DEEND ;IS 1793 STILL BUSY +; IN A,(STATUS) +; LD D,A +; LD A,(_ERMASK) +; AND D ;CHECK FOR ERRORS +; RET + +;------THIS IS THE MAIN ROUTINE TO GET THE TIME DATA FROM THE CMOS-RTC Chip on the MSDOS Support Board + +SHOW_TIME: +#IF S100MSDENABLE + LD HL,TIME_MSG + CALL PRINT_STRING ;Print message up to '$' + CALL PRINT_TIME +#ENDIF + RET + + +SHOW_DATE: +#IF S100MSDENABLE + LD HL,DATE_MSG + CALL PRINT_STRING ;Print message up to '$' + CALL PRINT_DATE +#ENDIF + RET + +PRINT_TIME: +#IF S100MSDENABLE + CALL UPD_IN_PR ;CHECK FOR UPDATE IN PROCESS + JP NC,RTC_2A ;GO AROUND IF OK + JP RTC_ERROR ;IF ERROR + +RTC_2A: LD E,-2 ;-2 goes to 0 for PORT_INC_2 + CALL PORT_INC_2 ;SET ADDRESS OF SECONDS + IN A,(CMOS_PORT+1) ;Get BCD value returned + LD D,A ;SAVE IN D + CALL PORT_INC_2 ;SET ADDRESS OF MINUTES + IN A,(CMOS_PORT+1) ;Get BCD value returned + LD C,A ;SAVE IN C + CALL PORT_INC_2 ;SET ADDRESS OF HOURS + IN A,(CMOS_PORT+1) ;Get BCD value returned + LD B,A ;SAVE + LD E,0 ;SET E TO ZERO + CALL DisplayTime + XOR A ;Clear Carry + RET ;BACK TO MONITOR + +RTC_ERROR: ;Indicate RTC Board is not present or Error + SCF ;SET CARRY FOR ERROR +#ENDIF + RET + +;Display time +; Arrive with B = HOURS IN BCD +; C = Minutes in BCD +; D = Seconds in BCD +DisplayTime: +#IF S100MSDENABLE + PUSH DE + PUSH BC + LD A,B + CALL PRINT_BCD ;Hours. Convert BCD to ASCII + LD C,':' + CALL ZCO + POP BC + LD A,C + CALL PRINT_BCD ;Minutes. Convert BCD to ASCII + LD C,':' + CALL ZCO + POP DE + LD A,D + CALL PRINT_BCD ;Seconds. Convert BCD to ASCII +#ENDIF + RET + +PRINT_DATE: +#IF S100MSDENABLE + CALL UPD_IN_PR + JP NC,RTC_4A + JP RTC_ERROR ;IF ERROR + +RTC_4A: + LD E,6 + CALL PORT_INC ;POINT TO DAY + IN A,(CMOS_PORT+1) + LD B,A ;SAVE IN A + CALL PORT_INC ;POINT TO MONTH + IN A,(CMOS_PORT+1) + LD D,A ;SAVE IN D + CALL PORT_INC ;POINT TO YEAR + IN A,(CMOS_PORT+1) + LD C,A ;SAVE IN C + LD E,31H ;POINT TO CENTURY BYTE SAVE AREA + CALL PORT_INC ; + IN A,(CMOS_PORT+1) ;GET VALUE + LD E,B ;GET DAY BACK + LD B,A + CALL DisplayDate + XOR A ;Clear Carry +#ENDIF + RET ;FINISHED + + +;Display date +; Return B = CENTURY IN BCD +; C = Year in BCD +; D = Month in BCD +; E = Day in BCD +DisplayDate: +#IF S100MSDENABLE + PUSH DE + PUSH DE + PUSH BC + PUSH BC + + POP BC + LD A,B + CALL PRINT_BCD ;Century (19/20). Convert BCD to ASCII + POP BC + LD A,C + CALL PRINT_BCD ;Year. Convert BCD to ASCII + LD C,'/' + CALL ZCO + POP DE + LD A,D + CALL PRINT_BCD ;Month. Convert BCD to ASCII + LD C,'/' + CALL ZCO + POP DE + LD A,E + CALL PRINT_BCD ;Day. Convert BCD to ASCII +#ENDIF + RET + + +UPD_IN_PR: ;Check we are ready to read clock +#IF S100MSDENABLE + PUSH BC + LD BC,600 ;SET LOOP COUNT +UPDATE: + LD A,0AH ;ADDRESS OF [A] REGISTER + OUT (CMOS_PORT),A + NOP + NOP + NOP + IN A,(CMOS_PORT+1) ;READ IN REGISTER [A] + AND 80H ;IF 8XH--> UIP BIT IS ON (CANNOT READ TIME) + JP Z,UPD_IN_PREND ;Are we ready/done + DEC BC + LD A,C + OR B + JP NZ,UPDATE ;Try again + XOR A ; + SCF ;SET CARRY FOR ERROR + POP BC + RET +UPD_IN_PREND: + XOR A ;Clear Carry + POP BC +#ENDIF + RET ;RETURN + +PORT_INC: +#IF S100MSDENABLE + LD A,E + INC A ;INCREMENT ADDRESS + LD E,A + OUT (CMOS_PORT),A +#ENDIF + RET + + +PORT_INC_2: +#IF S100MSDENABLE + LD A,E + ADD A,2 ;INCREMENT ADDRESS + LD E,A + OUT (CMOS_PORT),A +#ENDIF + RET + +PRINT_BCD: ;Print BCD in [A] + PUSH AF + PUSH AF + RRA + RRA + RRA + RRA + AND 0FH + ADD A,30H + LD C,A ;Write high byte mins to CRT + CALL ZCO + POP AF + AND 0FH + ADD A,30H + LD C,A + CALL ZCO + POP AF + RET + +;>>>>>>>>>>>>>>>>>>>>>>>>> SPEECH OUTPUT ROUTINES <<<<<<<<<<<<<<<<<< +; +;SPEAK OUTPUT (WILL BE USED TO COMMUNICATE WITH TALKER) +; Note the S100Computers I/O board V-Stamp speech chip will use the initial baud rate +; of of the SCC to communicate with it. This is determines after each reset/slave clear. +SPEAKER_CTS: ;Cannot get this to work. SCC does not change bit 5 of RR1 + ;when E1 sent to WR3 (No Auto ENABLE. See SCCINIT: +#IF S100IOVSENABLE + + IN A,(BCTL) ;A0H + BIT 5,A + LD A,0FFH + RET NZ ;Ret NZ if CTS is High + XOR A +#ENDIF + RET ;Ret Z if CTS is Low + +SPEAKOUT: +#IF S100IOVSENABLE + XOR A ;Will try 256 times, then timeout +SPXXX: + PUSH AF + IN A,(BCTL) ;(A0), Is SCC TX Buffer empty + AND 04H + JR NZ,SENDS ;NZ if ready to recieve character + POP AF + DEC A + JR NZ,SPXXX + RET +SENDS: + POP AF + LD A,C + OUT (BDTA),A ;(A2), Send it +#ENDIF + RET +; +;SPEAKTOMM THIS IS A ROUTINE TO SEND A STRING TO TALKER [HL] AT STRING +SPEAK_: + LD A,(HL) + CP '$' + JR Z,SPEAK1 + LD C,A + CALL SPEAKOUT + INC HL + JR SPEAK_ +SPEAK1: + LD C,0DH ;MUST END WITH A CR + JP SPEAKOUT +;;;;;;#ENDIF + + +;>>>>>>>>>>>>>>>>>> MODEM/SERIAL I/O <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +; Note the S100Computers I/O board will have the SSC set initially to 19,200 Baud +; THIS USES CHANNELL 'A' +SERIAL_OUT: +#IF S100IOSCCAENABLE + XOR A ;Will try 256 times, then timeout +MODXXX: PUSH AF + IN A,(ACTL) ;MODEM/SERIAL OUT + AND 04H ;Are we ready for a character + JR NZ,SENDM ;NZ if ready to recieve character + POP AF + DEC A + JR NZ,MODXXX + RET +SENDM: + POP AF + LD A,C + OUT (ADTA),A ;Send it +#ENDIF + RET + +SERIAL_IN: +#IF S100IOSCCAENABLE + XOR A ;Will try 256 times, then timeout +SERIAL_INX: + PUSH AF + CALL SERIAL_STAT ;MODEM/SERIAL IN + JR NZ,GETMOD + POP AF + DEC A + JR NZ,SERIAL_INX + RET +GETMOD: + POP AF + IN A,(ADTA) +#ELSE + LD A,'?' +#ENDIF + RET + +SERIAL_STAT: +#IF S100IOSCCAENABLE + IN A,(ACTL) + AND 01H + RET Z ;Ret Z if nothing +#ELSE + LD A,0FFH +; XOR A ; <--- This is not correct, returns a Z condtion, need a NZ +#ENDIF + RET ;Ret FF/NZ if something + + + +;PRINT MAIN MONITOR MENU ON CRT + +KCMD: + LD HL,MSG0 ;Signon Msg again (K Command) + CALL PRINT_STRING + +#IF S100IOVSENABLE + LD HL,SMSG ;SPEECH MESSAGE + CALL SPEAK_ +#ENDIF + + LD HL,MENUMSG ;Then Menu Message + JP PRINT_STRING + +; +;THIS ROUTINE JUMPS OVER TO THE 8088, 8086 or 80286. Port SW86 raises S-100 PIN #55 +;THIS WILL CAUSE THE 8086/80286 BOARD TO BECOME ACTIVE AND TAKE OVER THE BUS. THE +;Z80 WILL BE IN A PERMANANT HOLD STATE UNTIL PIN #55 IS AGAIN LOWERED. + +SWITCH_8086: + LD HL,MSG14 + CALL PRINT_STRING + IN A,(SW86) ;THIS SWITCHES CPU'S with no block Move + NOP ;Z80 WILL BE HELD HERE + NOP + NOP + NOP + JP BEGIN ;WILL DROP BACK TO REBOOT MONITOR + + +;THIS ROUTINE JUMPS OVER TO THE 68000 CPU Board. Port SW68K raises S-100 PIN #56 +;THIS WILL CAUSE THE 68000 CPU BOARD TO BECOME ACTIVE AND TAKE OVER THE BUS. THE +;Z80 WILL BE IN A PERMANANT HOLD STATE UNTIL PIN #56 IS AGAIN LOWERED. + +SWITCH_68K: + LD HL,MSG68K + CALL PRINT_STRING + IN A,(SW68K) ;THIS SWITCHES CPU'S + NOP ;Z80 WILL BE HELD HERE + NOP + NOP + NOP + JP BEGIN ;WILL DROP BACK TO REBOOT MONITOR + +; +; +; +;THESE ARE ROUTINES NOT YET IMPLEMENTED +; +RI: ;READER +POO: ;PUNCH +PRDY: ;PUNCH STATUS (Sent to Serial port right now) +RSTAT: ;READER STATUS (Input from Serial port right now) +ONLIST: ;ON LIST +OFLIST: RET ;OFF LIST +TRAP: HALT +; +; +DRIVE_NR_ERR: .DB BELL,CR,LF + .TEXT "Drive not Ready." + .DB CR,LF,LF + .TEXT "$" +RESTORE_ERR: .DB BELL,CR,LF + .TEXT "Restore Failed." + .DB CR,LF,LF + .TEXT "$" +BOOT_LD_ERR: .DB BELL,CR,LF + .TEXT "Read Error." + .DB CR,LF,LF + .TEXT "$" +SEEK_ERROR_MSG: .DB BELL,CR,LF + .TEXT "Seek Error." + .DB CR,LF,LF + .TEXT "$" + +BOOT_LD1_ERR: .DB BELL,CR,LF + .TEXT "BOOT error." + .DB CR,LF,LF + .TEXT "$" +VF_HUNG: .TEXT "VF Controller Hung" + .DB CR,LF,LF + .TEXT "$" +BIOS_ERR: .TEXT "BIOS JMP not in ROM" + .DB CR,LF,LF + .TEXT "$" +BOOT_MSG0: .DB CR,LF + .TEXT "Loading CPM from $" + +#IF S100VFIIENABLE +VF_MSG: .TEXT "VF FDC." + .DB CR,LF + .TEXT "$" +#ENDIF + +#IF S100ZFDCENABLE +ZFDC_MSG: .TEXT "ZFDC FDC." + .DB CR,LF + .TEXT "$" +#ENDIF + +MENUMSG: .DB CR,LF + .TEXT "A=Memmap B=68000 C=CP/M(Z) D=Disp E=Echo F=Fill G=Goto" + .DB CR,LF + .TEXT "H=Date I=Time J=Test K=Menu L=CPM(V) M=Move N=SeqMap" + .DB CR,LF + .TEXT "O=8086 P=CPM(IDE) Q=Port R=Ports S=Subs T=Type" + .DB CR,LF + .TEXT "V=Verify W=Port EDH X=DOS(H) Y=RomWBW Z=Top @=Flush Printer" + .DB CR,LF,LF + .TEXT "$" +; +MSG14: .DB BELL,CR,LF + .TEXT "8086/80286 Active" + .DB CR,LF,LF + .TEXT "$" + +MSG68K: .DB BELL,CR,LF + .TEXT "68K Active" + .DB CR,LF,LF + .TEXT "$" + +MSG17: .DB CR,LF + .TEXT "Segment (0-F):$" + +#IF S100MSDENABLE +TIME_MSG: .DB CR,LF + .TEXT "Time:- $" +DATE_MSG: .DB CR,LF + .TEXT "Date:- $" +#ENDIF + +GAP_MSG: .TEXT " $" + +#IF S100DIDEENABLE +IDE_RW_ERROR: .DB CR,LF + .TEXT "IDE Drive R/W Error" + .DB CR,LF + .TEXT "$" +#ENDIF + +SP_MSG .DB CR,LF + .TEXT "SP=$" + + +SPEAKCPM_MSG: .TEXT "LOADING CPM $" + +#IF S1008086ENABLE +SPEAKDOS_MSG: .TEXT "LOADING DOS $" +#ENDIF + +CR_SMSG: .DB CR,CR,CR,CR + .TEXT "$" +; + NOP + HALT + + + .END +;END diff --git a/XSource/Makefile b/XSource/Makefile index d90b4610..b6579da1 100644 --- a/XSource/Makefile +++ b/XSource/Makefile @@ -95,14 +95,6 @@ # Uncomment and update values below to hardcode settings: # - -# 1/19/2013 dwg - tested zeta, - -CONFIG := S100 -ROMSIZE := 512 -CPU := 80 -SYS := CPM - #CONFIG := zeta #ROMSIZE := 512 #CPU := 180 @@ -115,13 +107,18 @@ SYS := CPM #SYS := CPM #ROMNAME := n8_2312 -#CONFIG := N8VEM +#CONFIG := n8vem #ROMSIZE := 512 #CPU := 180 #SYS := CPM -#ROMNAME := N8VEM - +#ROMNAME := n8vem +CONFIG := s100 +ROMSIZE := 512 +CPU := 80 +SYS := CPM +ROMNAME := s100 +CPUROM := master-cfg ifndef ROMNAME ROMNAME := $(CONFIG) @@ -157,6 +154,7 @@ ASMIMG := $(TASM) $(ASMOPT80) -b -fE5 NULL := SPACE := ${NULL} ${NULL} + %.bin: %.asm $(ASM80) $< $@ @@ -175,9 +173,17 @@ $(error Usage: make CONFIG= ROMSIZE=[512|1024] CPU=[80|180] SYS=[CPM|ZSY endif endif +# The STDS macro names all the sub-includes so they all can be copied +# in from the Source folder. $(STDS) is the first dependency of the "all" +# target, therefore assuring that these files are here in time for their +# use in any assembly that includes the top level file, "std.asm". STDS = std-n8.inc std-n8vem.inc std-s100.inc std-s2i.inc std-zeta.inc -all: $(STDS) tasm80.tab tasm85.tab $(OUTDIR)/$(ROMNAME).rom $(OUTDIR)/$(ROMNAME).sys $(OUTDIR)/$(ROMNAME).com +#ifdef $(CPUROM) +CONDIT = $(OUTDIR)/$(CPUROM).rom +#endif + +all: $(STDS) tasm80.tab tasm85.tab $(OUTDIR)/$(ROMNAME).rom $(OUTDIR)/$(ROMNAME).sys $(OUTDIR)/$(ROMNAME).com $(CONDIT) rm -f *.asm rm -f *.bin rm -f *.inc *.tab *.tmp @@ -211,7 +217,13 @@ bootrom.bin : bootrom.asm std.asm build.inc ver.inc memmgr.asm config_$(CONFIG). bootapp.bin: bootapp.asm std.asm build.inc ver.inc $(TASM) $(ASMOPT80) $< $@ - + +#ifdef CPUROM +$(OUTDIR)/$(CPUROM).rom: $(CPUROM).asm std.asm build.inc config_$(CONFIG).asm + cp config_$(CONFIG).asm config.asm + $(ASMIMG) $(CPUROM).asm $(OUTDIR)/$(CPUROM).rom +#endif + pgzero.bin: pgzero.asm std.asm build.inc ver.inc $(TASM) $(ASMOPT80) $< $@ @@ -250,6 +262,13 @@ $(OUTDIR)/$(ROMNAME).com: bootapp.bin syscfg.bin loader.bin hbios.bin dbgmon.bin $(OUTDIR)/$(ROMNAME).sys: prefix.bin os.bin cat prefix.bin os.bin >>$@ +$(OUTDIR)/$(CPUROM).bin: $(CPUROM).asm std.asm + $(ASMIMG) $(CPUROM).asm $@ + +std.asm: $(SRC)std.asm + cp $< $@ + $(CVT) $@ + ansi.asm: $(SRC)ansi.asm cp $< $@ $(CVT) $@ @@ -322,6 +341,12 @@ loader.asm: $(SRC)loader.asm util.asm cp $(SRC)loader.asm $@ $(CVT) $@ +#ifdef $(CPUROM) +$(CPUROM).asm: $(SRC)/$(CPUROM).asm + cp $< $@ + $(CVT) $@ +#endif + memmgr.asm: $(SRC)memmgr.asm cp $< $@ $(CVT) $@ @@ -366,6 +391,10 @@ romfill.asm: $(SRC)romfill.asm cp $< $@ $(CVT) $@ +s100-i3.asm: $(SRC)s100-i3.asm + cp $< $@ + $(CVT) $@ + sd.asm: $(SRC)sd.asm cp $< $@ $(CVT) $@ @@ -374,8 +403,11 @@ sd_data.asm: $(SRC)sd_data.asm cp $< $@ $(CVT) $@ -std.asm: $(SRC)std.asm - cp $< $@ +# By adding all the sub-includes as dependencies for std.asm, this assures that +# whichever one we are using will be present during the assembly of any modules +# that include std.asm. +std.asm: $(SRC)std.asm std-n8.inc std-n8vem.inc std-s100.inc std-s2i.inc std-zeta.inc + cp $(SRC)std.asm $@ $(CVT) $@ std-n8.inc: $(SRC)std-n8.inc diff --git a/cpurom/Makefile b/cpurom/Makefile new file mode 100644 index 00000000..9442748f --- /dev/null +++ b/cpurom/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/cpurom/cleanxp.bat b/cpurom/cleanxp.bat new file mode 100644 index 00000000..b6be7814 --- /dev/null +++ b/cpurom/cleanxp.bat @@ -0,0 +1 @@ +wmake -f makefile.xp clean diff --git a/cpurom/doc/agm1264f.pdf b/cpurom/doc/agm1264f.pdf new file mode 100644 index 00000000..60eec3d9 Binary files /dev/null and b/cpurom/doc/agm1264f.pdf differ diff --git a/cpurom/doc/bdoscalls.webarchive b/cpurom/doc/bdoscalls.webarchive new file mode 100644 index 00000000..30b4faad Binary files /dev/null and b/cpurom/doc/bdoscalls.webarchive differ diff --git a/cpurom/doc/bios.webarchive b/cpurom/doc/bios.webarchive new file mode 100644 index 00000000..ede74cc5 Binary files /dev/null and b/cpurom/doc/bios.webarchive differ diff --git a/cpurom/doc/fcb.webarchive b/cpurom/doc/fcb.webarchive new file mode 100644 index 00000000..d8468620 Binary files /dev/null and b/cpurom/doc/fcb.webarchive differ diff --git a/cpurom/doc/jrch2b.doc b/cpurom/doc/jrch2b.doc new file mode 100644 index 00000000..6231b4db --- /dev/null +++ b/cpurom/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/cpurom/doc/make.pdf b/cpurom/doc/make.pdf new file mode 100644 index 00000000..3e18161c Binary files /dev/null and b/cpurom/doc/make.pdf differ diff --git a/cpurom/doc/sdcc-z80-mode.png b/cpurom/doc/sdcc-z80-mode.png new file mode 100644 index 00000000..064b32b1 Binary files /dev/null and b/cpurom/doc/sdcc-z80-mode.png differ diff --git a/cpurom/doc/watcom-tools.pdf b/cpurom/doc/watcom-tools.pdf new file mode 100644 index 00000000..6d3f38c9 Binary files /dev/null and b/cpurom/doc/watcom-tools.pdf differ diff --git a/cpurom/exp/common.mak b/cpurom/exp/common.mak new file mode 100644 index 00000000..7430e334 --- /dev/null +++ b/cpurom/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/cpurom/exp/makefile.mac b/cpurom/exp/makefile.mac new file mode 100644 index 00000000..506bc8c0 --- /dev/null +++ b/cpurom/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/cpurom/exp/makefile.win b/cpurom/exp/makefile.win new file mode 100644 index 00000000..c324b33d --- /dev/null +++ b/cpurom/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/cpurom/inc/agm1264f.h b/cpurom/inc/agm1264f.h new file mode 100644 index 00000000..b32019f9 --- /dev/null +++ b/cpurom/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/cpurom/inc/cpmbdos.h b/cpurom/inc/cpmbdos.h new file mode 100644 index 00000000..6bb522db --- /dev/null +++ b/cpurom/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/cpurom/inc/cprintf.h b/cpurom/inc/cprintf.h new file mode 100644 index 00000000..925275e3 --- /dev/null +++ b/cpurom/inc/cprintf.h @@ -0,0 +1,7 @@ +/* cprintf.h */ + +int cprintf(const char * fmt, ...); + +#define printf cprintf + + diff --git a/cpurom/inc/diskio.h b/cpurom/inc/diskio.h new file mode 100644 index 00000000..9a198457 --- /dev/null +++ b/cpurom/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/cpurom/inc/ds1302.h b/cpurom/inc/ds1302.h new file mode 100644 index 00000000..4898ec5a --- /dev/null +++ b/cpurom/inc/ds1302.h @@ -0,0 +1,7 @@ +/* + * + * ds1302 Dallas Real Time Clock module + * + */ + + diff --git a/cpurom/inc/i8255.h b/cpurom/inc/i8255.h new file mode 100644 index 00000000..11761e9c --- /dev/null +++ b/cpurom/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/cpurom/inc/jrctypes.h b/cpurom/inc/jrctypes.h new file mode 100644 index 00000000..c97ed7eb --- /dev/null +++ b/cpurom/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/cpurom/inc/ns16550.h b/cpurom/inc/ns16550.h new file mode 100644 index 00000000..6e81ada9 --- /dev/null +++ b/cpurom/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/cpurom/inc/ns16550.inc b/cpurom/inc/ns16550.inc new file mode 100644 index 00000000..f405d38a --- /dev/null +++ b/cpurom/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/cpurom/inc/portab.h b/cpurom/inc/portab.h new file mode 100644 index 00000000..6a814a13 --- /dev/null +++ b/cpurom/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/cpurom/inc/sbcv2.h b/cpurom/inc/sbcv2.h new file mode 100644 index 00000000..83951d3d --- /dev/null +++ b/cpurom/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/cpurom/inc/scsi2ide.h b/cpurom/inc/scsi2ide.h new file mode 100644 index 00000000..023b8a99 --- /dev/null +++ b/cpurom/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/cpurom/inc/scsi2ide.inc b/cpurom/inc/scsi2ide.inc new file mode 100644 index 00000000..64b938ca --- /dev/null +++ b/cpurom/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/cpurom/inc/z53c80.h b/cpurom/inc/z53c80.h new file mode 100644 index 00000000..9a7039ed --- /dev/null +++ b/cpurom/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/cpurom/makeclean.bat b/cpurom/makeclean.bat new file mode 100644 index 00000000..64ef22dd --- /dev/null +++ b/cpurom/makeclean.bat @@ -0,0 +1,3 @@ +wmake -f makefile.xp clean +rem wmake -f makefile.xp +dir rom diff --git a/cpurom/makecpurom.bat b/cpurom/makecpurom.bat new file mode 100644 index 00000000..5798c184 --- /dev/null +++ b/cpurom/makecpurom.bat @@ -0,0 +1,3 @@ +wmake -f makefile.xp clean +wmake -f makefile.xp etools rom\scsiscrm.rom +dir rom diff --git a/cpurom/makefile.xp b/cpurom/makefile.xp new file mode 100644 index 00000000..498a5396 --- /dev/null +++ b/cpurom/makefile.xp @@ -0,0 +1,646 @@ +######################################################## +# Makefile for Doug's Unified BIOS 1/28/2013 # +# 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)\Program Files\sdcc +#SDAS = $(SPREFIX)\bin\sdasz80 +SDAS = sdasz80 +SDASFLG = -plosff -Iinc +#SDCC = $(SPREFIX)\bin\sdcc +SDCC = sdcc +SDCCFLG = -c -mz80 -D__SDCC__=1 -I inc +SDCCLIB = $(SPREFIX)\lib\z80 +#SDLD = $(SPREFIX)\bin\sdldz80 +SDLD = 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 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)n8.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 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) $(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)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) $(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 *.exe + $(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/cpurom/makexp.bat b/cpurom/makexp.bat new file mode 100644 index 00000000..4040c97f --- /dev/null +++ b/cpurom/makexp.bat @@ -0,0 +1,3 @@ +wmake -f makefile.xp clean +wmake -f makefile.xp +dir rom diff --git a/cpurom/ref/JRC0521.ZIP b/cpurom/ref/JRC0521.ZIP new file mode 100644 index 00000000..55eb7806 Binary files /dev/null and b/cpurom/ref/JRC0521.ZIP differ diff --git a/cpurom/ref/bdosb01.asm b/cpurom/ref/bdosb01.asm new file mode 100644 index 00000000..b5883d94 --- /dev/null +++ b/cpurom/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/cpurom/ref/n8-romim.ref b/cpurom/ref/n8-romim.ref new file mode 100644 index 00000000..33dfdad8 Binary files /dev/null and b/cpurom/ref/n8-romim.ref differ diff --git a/cpurom/src/baseline.c b/cpurom/src/baseline.c new file mode 100644 index 00000000..34b1b2c3 --- /dev/null +++ b/cpurom/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/cpurom/src/bdosb01.s b/cpurom/src/bdosb01.s new file mode 100644 index 00000000..1cb003b2 --- /dev/null +++ b/cpurom/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/cpurom/src/cbios.s b/cpurom/src/cbios.s new file mode 100644 index 00000000..a909bd64 --- /dev/null +++ b/cpurom/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/cpurom/src/cbiosn8.s b/cpurom/src/cbiosn8.s new file mode 100644 index 00000000..709f9826 --- /dev/null +++ b/cpurom/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/cpurom/src/ccpb03.s b/cpurom/src/ccpb03.s new file mode 100644 index 00000000..3eedda69 --- /dev/null +++ b/cpurom/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/cpurom/src/copyfile.c b/cpurom/src/copyfile.c new file mode 100644 index 00000000..e4b7716d --- /dev/null +++ b/cpurom/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/cpurom/src/cpm0.s b/cpurom/src/cpm0.s new file mode 100644 index 00000000..59186c76 --- /dev/null +++ b/cpurom/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/cpurom/src/cpmbdos.s b/cpurom/src/cpmbdos.s new file mode 100644 index 00000000..a7c6592f --- /dev/null +++ b/cpurom/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/cpurom/src/cprintf.c b/cpurom/src/cprintf.c new file mode 100644 index 00000000..7f94e9bb --- /dev/null +++ b/cpurom/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/cpurom/src/crt0.s b/cpurom/src/crt0.s new file mode 100644 index 00000000..cd5212df --- /dev/null +++ b/cpurom/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/cpurom/src/crt0jplp.s b/cpurom/src/crt0jplp.s new file mode 100644 index 00000000..41005105 --- /dev/null +++ b/cpurom/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/cpurom/src/crt0scrm.s b/cpurom/src/crt0scrm.s new file mode 100644 index 00000000..b787bde5 --- /dev/null +++ b/cpurom/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/cpurom/src/dbgmon.s b/cpurom/src/dbgmon.s new file mode 100644 index 00000000..b39b1a84 --- /dev/null +++ b/cpurom/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/cpurom/src/dwgh2b.c b/cpurom/src/dwgh2b.c new file mode 100644 index 00000000..cc70ad9a --- /dev/null +++ b/cpurom/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. +*********************************************************************** + 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;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 +#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/cpurom/tmp/stuff/baseline.arf b/cpurom/tmp/stuff/baseline.arf new file mode 100644 index 00000000..e78d4aa5 --- /dev/null +++ b/cpurom/tmp/stuff/baseline.arf @@ -0,0 +1,15 @@ +-mjx +-i baseline.ihx +-k /Developer/sdcc/share/sdcc/lib/z80 +-l z80 +-b _CCPB03 = 0xD000 +-b _BDOSB01 = 0xD800 +-b _CBIOS = 0xE600 +-b _DBGMON = 0x8000 +obj/crt0.rel +obj/baseline.rel +obj/dbgmon.rel +obj/ccpb03.rel +obj/bdosb01.rel +obj/cbios.rel +-e diff --git a/cpurom/tmp/stuff/baseline.lk b/cpurom/tmp/stuff/baseline.lk new file mode 100644 index 00000000..e78d4aa5 --- /dev/null +++ b/cpurom/tmp/stuff/baseline.lk @@ -0,0 +1,15 @@ +-mjx +-i baseline.ihx +-k /Developer/sdcc/share/sdcc/lib/z80 +-l z80 +-b _CCPB03 = 0xD000 +-b _BDOSB01 = 0xD800 +-b _CBIOS = 0xE600 +-b _DBGMON = 0x8000 +obj/crt0.rel +obj/baseline.rel +obj/dbgmon.rel +obj/ccpb03.rel +obj/bdosb01.rel +obj/cbios.rel +-e diff --git a/cpurom/tmp/stuff/baseline.lnk b/cpurom/tmp/stuff/baseline.lnk new file mode 100644 index 00000000..e78d4aa5 --- /dev/null +++ b/cpurom/tmp/stuff/baseline.lnk @@ -0,0 +1,15 @@ +-mjx +-i baseline.ihx +-k /Developer/sdcc/share/sdcc/lib/z80 +-l z80 +-b _CCPB03 = 0xD000 +-b _BDOSB01 = 0xD800 +-b _CBIOS = 0xE600 +-b _DBGMON = 0x8000 +obj/crt0.rel +obj/baseline.rel +obj/dbgmon.rel +obj/ccpb03.rel +obj/bdosb01.rel +obj/cbios.rel +-e diff --git a/cpurom/tmp/stuff/n8.arf b/cpurom/tmp/stuff/n8.arf new file mode 100644 index 00000000..e280f65a --- /dev/null +++ b/cpurom/tmp/stuff/n8.arf @@ -0,0 +1,13 @@ +-mjx +-i n8.ihx +-k /usr/local/share/sdcc/lib/z80 +-l z80 +-b _CCPB03 = 0x0900 +-b _BDOSB01 = 0x1100 +-b _CBIOS = 0x1f00 +obj/loadern8.rel +obj/dbgmon.rel +obj/ccpb03.rel +obj/bdosb01.rel +obj/cbiosn8.rel +-e diff --git a/cpurom/tmp/stuff/n8.lk b/cpurom/tmp/stuff/n8.lk new file mode 100644 index 00000000..e280f65a --- /dev/null +++ b/cpurom/tmp/stuff/n8.lk @@ -0,0 +1,13 @@ +-mjx +-i n8.ihx +-k /usr/local/share/sdcc/lib/z80 +-l z80 +-b _CCPB03 = 0x0900 +-b _BDOSB01 = 0x1100 +-b _CBIOS = 0x1f00 +obj/loadern8.rel +obj/dbgmon.rel +obj/ccpb03.rel +obj/bdosb01.rel +obj/cbiosn8.rel +-e diff --git a/cpurom/tmp/stuff/n8.lnk b/cpurom/tmp/stuff/n8.lnk new file mode 100644 index 00000000..e280f65a --- /dev/null +++ b/cpurom/tmp/stuff/n8.lnk @@ -0,0 +1,13 @@ +-mjx +-i n8.ihx +-k /usr/local/share/sdcc/lib/z80 +-l z80 +-b _CCPB03 = 0x0900 +-b _BDOSB01 = 0x1100 +-b _CBIOS = 0x1f00 +obj/loadern8.rel +obj/dbgmon.rel +obj/ccpb03.rel +obj/bdosb01.rel +obj/cbiosn8.rel +-e diff --git a/cpurom/tmp/stuff/scsi2ide.arf b/cpurom/tmp/stuff/scsi2ide.arf new file mode 100644 index 00000000..8ddee2c4 --- /dev/null +++ b/cpurom/tmp/stuff/scsi2ide.arf @@ -0,0 +1,9 @@ +-mjx +-i scsi2ide.ihx +-k /Developer/sdcc/share/sdcc/lib/z80 +-l z80 +-b _DBGMON = 0x8000 +obj/crt0.rel +obj/scsi2ide.rel +obj/dbgmon.rel +-e diff --git a/cpurom/tmp/stuff/scsi2ide.lk b/cpurom/tmp/stuff/scsi2ide.lk new file mode 100644 index 00000000..8ddee2c4 --- /dev/null +++ b/cpurom/tmp/stuff/scsi2ide.lk @@ -0,0 +1,9 @@ +-mjx +-i scsi2ide.ihx +-k /Developer/sdcc/share/sdcc/lib/z80 +-l z80 +-b _DBGMON = 0x8000 +obj/crt0.rel +obj/scsi2ide.rel +obj/dbgmon.rel +-e diff --git a/cpurom/tmp/stuff/scsi2ide.lnk b/cpurom/tmp/stuff/scsi2ide.lnk new file mode 100644 index 00000000..8ddee2c4 --- /dev/null +++ b/cpurom/tmp/stuff/scsi2ide.lnk @@ -0,0 +1,9 @@ +-mjx +-i scsi2ide.ihx +-k /Developer/sdcc/share/sdcc/lib/z80 +-l z80 +-b _DBGMON = 0x8000 +obj/crt0.rel +obj/scsi2ide.rel +obj/dbgmon.rel +-e