FORP=0TO1 P%=&EA00 O%=mcode% [OPT P*3+4 .BIOS_BOOT :JP ColdBoot .BIOS_WBOOT :JP WarmBoot .BIOS_CONST :JP ConsoleStatus .BIOS_CONIN :JP ConsoleIn .BIOS_CONOUT :JP ConsoleOut .BIOS_LIST :JP List .BIOS_PUNCH :JP PunchOut .BIOS_READER :JP ReaderIn .BIOS_HOME :JP DiskHome .BIOS_SELDSK :JP SelectDisk .BIOS_SETTRK :JP SetTrack .BIOS_SETSEC :JP SetSector .BIOS_SETDMA :JP SetDMA .BIOS_READ :JP DiskRead .BIOS_WRITE :JP DiskWrite .BIOS_LISTST :JP ListStatus .BIOS_SECTRAN:JP SectorTranslate : .PatchArea RET : DEFM "Greetings from " DEFM "Clean End - Ian Mark Neil Simon " DEFM "Dirty End - Dave Ian John Toby" DEFM "Boss Man - Howard " : .LEA93 ; Reset input stream LD A,&83 ; Specify CON=UC1 RDR=TTY PUN=TTY LST=LPT .LEA95 LD (&0003),A ; Reset IOBYTE LD L,&02 LD A,&02 CALL OSBYTE ; Input stream=kbd, serial enabled JP LEBBD : .ConsoleStatus CALL LEB02:DEFB &81 DEFW LEB81:DEFW LEB50:DEFW LEAF6:DEFW LEB24 : .ConsoleIn CALL LEB02:DEFB &01 DEFW LEB98:DEFW LEB54:DEFW ReaderIn:DEFW LFFE0 : .ConsoleOut CALL LEB02:DEFB &01 DEFW Out_TTY:DEFW Out_CRT:DEFW Out_BAT:DEFW Out_UC1 : .Out_BAT .List CALL LEB02:DEFB &03 DEFW Out_TTY:DEFW Out_CRT:DEFW LEBA6:DEFW LEBA9 : .ListStatus CALL LEB02:DEFB &03 DEFW LEBA1:DEFW LAB93:DEFW LEBC4:DEFW LEBC4 : .PunchOut CALL LEB02:DEFB &05 DEFW Out_TTY:DEFW Out_CRT:DEFW LEB23:DEFW LEB23 : .ReaderIn CALL LEB02:DEFB &07 DEFW LEB98:DEFW LEB54:DEFW LEB21:DEFW LEB21 : CALL LEB02:DEFB &07 DEFW LEB8A:DEFW LEB50:DEFW LEB95:DEFW LEB95 : .LEB02 POP HL LD A,(HL) INC HL BIT 7,A LD B,A RES 7,B JR NZ,LEB10 XOR A LD (LF167),A .LEB10 LD A,(&0003) .LEB13 RLCA DJNZ LEB13 AND &06 LD D,&00 LD E,A ADD HL,DE LD E,(HL) INC HL LD D,(HL) EX DE,HL JP (HL) : .LEB21 LD A,&1A RET : .LEB24 LD HL,LF167 XOR A OR (HL) JR Z,LEB2E DEC (HL) XOR A RET : .LEB2E LD HL,&FF00 LD A,&B1 CALL OSBYTE .LEB36 CALL LEB8C RET NZ LD A,&D8 LD HL,&FF00 CALL OSBYTE LD A,L AND A JR NZ,LEB95 LD HL,LF167 LD (HL),&0C RET : .Out_UC1 LD A,C ; Sends striaght to PR_OUT JP &FF9E ; Selectably WRCH or TERMOUT : .LEB50 LD L,&00 JR LEB36 : .LEB54 LD L,&02 .LEB56 LD A,&02 CALL OSBYTE CALL OSRDCH PUSH AF LD A,L AND A JR NZ,LEB65 LD L,&02 .LEB65 LD A,&02 CALL OSBYTE POP AF RET : .Out_CRT LD HL,&00F4 ; Select output=??? .LEB6F ; Enter here with HL=*FX3 value LD A,&03 CALL OSBYTE ; Select output stream PUSH HL ; Save previous output stream XOR A CALL &FFC8 ; Switch off terminal mode PUSH AF ; Remember previous state LD A,C CALL OSWRCH ; Output the character POP AF CALL &FFC8 ; Restore previous terminal state POP HL ; Get previous output stream LD H,&00 LD A,&03 JP OSBYTE ; Restore previous output and return : .LEB8A LD L,&01 .LEB8C LD A,&98 CALL OSBYTE JR NC,LEB95 XOR A RET : .LEB95 XOR A DEC A RET : .LEB98 LD L,&01 JR LEB56 : .Out_TTY ; One of the CONOUT routines LD HL,&00F7 ; Select output=???? JR LEB6F ; Jump to output the character : .LEBA1 LD HL,&FFFD JR LEBC7 : .LEBA6 CALL LEBD2 LD A,C AND A LD HL,&001A JR NZ,LEB6F LD A,&06 LD L,&FF CALL OSBYTE LD HL,&001A CALL LEB6F .LEBBD LD A,&06 LD L,&00 JP OSBYTE ; Clear printer ignore char : .LEBC4 LD HL,&FFFC .LEBC7 LD A,&80 CALL OSBYTE LD A,L AND A RET Z XOR A DEC A RET : .LEBD2 LD A,(&0003) AND &C3 CP &82 RET Z CALL LEC80 RET NZ LD A,&86 CALL OSBYTE LD (LF168),HL LD A,&87 CALL OSBYTE LD A,H LD HL,&1F36 AND A JR Z,LEBFD CP &03 JR Z,LEBFB LD HL,&0000 JR LEBFD .LEBFB LD H,&18 .LEBFD PUSH HL CALL LEC6C CALL LEC8E DEFM "Printer off line":DEFB 0 CALL LEC80 POP HL PUSH HL CALL LEC6C CALL LEC8E DEFM "SPACE starts Printer Sink":DEFB 0 .LEC3A CALL LEBC4 JR NZ,LEC5A CALL ConsoleStatus AND A JR Z,LEC3A CALL ConsoleIn CP &20 JR NZ,LEC3A LD L,&03 LD A,&15 CALL OSBYTE LD L,&00 LD A,&05 CALL OSBYTE .LEC5A POP HL CALL LEC6C LD B,&19 .LEC60 PUSH BC LD C,&20 CALL ConsoleOut POP BC DJNZ LEC60 LD HL,(LF168) .LEC6C PUSH BC PUSH HL LD C,&1F CALL ConsoleOut POP HL PUSH HL LD C,L CALL ConsoleOut POP HL LD C,H CALL ConsoleOut .LEC7E POP BC RET : .LEC80 LD DE,&AFC8 .LEC83 CALL LEBC4 RET NZ DEC DE LD A,E .LEC89 OR D JR NZ,LEC83 XOR A RET : .LEC8E ; Print inline message until &00 byte EX (SP),HL ; Get address from stack PUSH DE ; Save everything else PUSH BC PUSH AF .LEC92 LD A,(HL) ; Get a byte INC HL ; Move to next address AND A JR Z,LEC9E ; Zero byte, end of message PUSH HL CALL LECA3 ; Print the character POP HL JR LEC92 ; Loop back for next .LEC9E POP AF POP BC POP DE EX (SP),HL RET : .LECA3 ; CON_ASCII CP &0D ; Print a character, JR NZ,LECAC ; converting to CALL LECAC LD A,&0A .LECAC LD C,A JP ConsoleOut : .LECB0 ; Complain about disk being booted from CALL LEC8E ; Print message: DEFB 13:DEFM "Not a CP/M system disc in A":DEFB 0 CALL ConsoleIn ; Wait for a key : .WarmBoot ; RESET jumps to here LD SP,&F4E0 ; Use internal MOS stack EI ; Enable INTs ! ColdBoot doesn't explictly do this CALL &FFA7 ; Reload CCP and BDOS CALL LED32 ; Calculate CCP/BDOS checksum LD HL,LED43 CP (HL) ; Is is same as at previous ColdBoot? JR NZ,LECB0 ; No, jump to complain and reload CALL LED44 ; Initialise things, error handler, esc state, ; zero page jumps : ; A consequence of the way the WarmBoot CCP/BDOS validity check works is ; that between any two ColdBoots, only the same CCP/BDOS will be recognised ; as being valid on reloading. This prevents you being able to, for ; instance, soft reboot from a different CCP/BDOS. A ColdBoot is required to ; load a different CCP/BDOS in and have it's checksum used. ; .LECE6 ; Enter CCP LD A,(&0004) ; Get current drive/user LD C,A AND &0F ; Get drive CP &02 ; Is it a supported drive? JR C,LECF4 ; Drive 0/1 supported - enter CCP LD A,C ; Force drive to 0 AND &F0 LD C,A .LECF4 JP &D400 ; Enter CCP with C=drive/user .ColdBoot ; Entered on startup after booting from Reset LD SP,&F4E0 ; Use internal MOS stack CALL LED32 ; Get 8bit checksum of BDOS code in memory LD (LED43),A ; Store this checksum XOR A LD (&0004),A ; Clear Current Drive+User CALL LED44 ; Initialise things, error handler, esc state, ; zero page jumps CALL PatchArea ; Call any patch code CALL LEA93 ; Initialise input stream and printer ignore state CALL LEC8E ; Print startup message: .LED10 DEFB 13:DEFM "Acorn CP/M 2.2 - Bios 1.20":DEFB 13:DEFB 0 CALL LF08E ; Look for any boot file JR LECE6 ; Enter CCP with valid current drive number : .LED32 ; Perform 8bit summation of CCP/BDOS XOR A ; Clear accumulator .LED33 LD HL,&DC06 ; Point to start of BDOS .LED36 ADD A,(HL) ; Add the byte INC HL ; Point to next byte EX DE,HL ; Swap to perform subtraction .LED39 SCF LD HL,&E9FF SBC HL,DE ; Have we got past &E9FF yet? EX DE,HL ; Swap back JR NZ,LED36 ; Loop back until all done RET : .LED43 DEFB &00 ; BDOS checksum : .LED44 XOR A LD (LF1E5),A LD (LF1E6),A LD (LF1E8),A .LED4E LD (&F1E7),A CALL &FFBF ; Ensure RSTERR at &0038 is set up LD HL,(&FF84) ; Get default error handler LD (&FFFA),HL ; Set error handler to it LD A,&E5 LD HL,&0001 ; ESC key returns ASCII CALL OSBYTE LD A,&C3 LD (&0000),A ; Put JP opcode into LD (&0005),A ; RESET and BDOS LD HL,WBOOT ; Put RESET and BDOS LD (&0001),HL ; into address fields LD HL,&DC06 LD (&0006),HL LD BC,&0080 ; Set DMA to defaut &0080 : .SetDMA ; BC=Disk Memory Address LD (LF1F0),BC ; Store current DMA RET : .DiskHome LD BC,&0000 LD A,(LF1E7) OR A JR NZ,SetTrack LD (LF1E6),A : .SetTrack ; BC=track LD A,C ; Ignore high byte LD (LF1DF),A ; Store current track RET : .SectorTranslate LD H,B LD L,C RET : .SelectDisk ; C=drive number, Eb0=not first occurance since reset LD HL,&0000 ; HL=0 for no drive available LD A,C ; Look at supplied drive number CP &02 ; Only two drives supported RET NC ; Exit with drives 2+ LD BC,DPH_Base LD (LF1DE),A ; Store current drive LD L,A ADD HL,HL ; Multiply by 16 to index into DPB table ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,BC ; RET : .SetSector ; BC=sector LD A,C ; Ignore high byte LD (LF1E0),A ; Store current sector RET : .DiskRead LD (LF1DC),SP LD SP,&F4CC XOR A LD (LF1E8),A LD A,&01 LD (LF1EE),A LD (LF1ED),A LD A,&02 LD (LF1EF),A JP LEE2F : .DiskWrite LD (LF1DC),SP LD SP,&F4CC XOR A LD (LF1EE),A LD A,C LD (LF1EF),A CP &02 JR NZ,LEDF0 LD A,&10 LD (LF1E8),A LD A,(LF1DE) LD (LF1E9),A LD A,(&F1DF) LD (LF1EA),A LD A,(LF1E0) LD (LF1EB),A .LEDF0 LD A,(LF1E8) OR A JR Z,LEE27 DEC A LD (LF1E8),A LD A,(LF1DE) LD HL,LF1E9 CP (HL) JR NZ,LEE27 LD A,(&F1DF) LD HL,LF1EA CP (HL) JR NZ,LEE27 LD A,(LF1E0) LD HL,LF1EB CP (HL) JR NZ,LEE27 INC (HL) LD A,(HL) CP &14 JR C,LEE21 LD (HL),&00 LD HL,LF1EA INC (HL) .LEE21 XOR A LD (LF1ED),A JR LEE2F .LEE27 XOR A LD (LF1E8),A INC A LD (LF1ED),A .LEE2F XOR A LD (&F1EC),A LD A,(LF1E0) OR A RRA OR A RRA LD (LF1E4),A LD HL,LF1E6 LD A,(HL) LD (HL),&01 OR A JR Z,LEE68 LD A,(LF1DE) LD HL,LF1E1 CP (HL) JR NZ,LEE61 LD A,(&F1DF) LD HL,&F1E2 CP (HL) JR NZ,LEE61 LD A,(LF1E4) LD HL,&F1E3 CP (HL) JR Z,LEE85 .LEE61 LD A,(&F1E7) OR A CALL NZ,LEF04 .LEE68 LD A,(LF1DE) LD (LF1E1),A LD A,(&F1DF) LD (&F1E2),A LD A,(LF1E4) LD (&F1E3),A LD A,(LF1ED) OR A CALL NZ,LEEC7 XOR A LD (&F1E7),A .LEE85 LD A,(LF1E0) ; Get current sector AND &03 ; Keep bottom two bit - 0, 1, 2, 3 LD L,A LD H,&00 ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL LD DE,LF272 ADD HL,DE ; HL=Deblock area + 128*block{b0-b1} LD DE,(&F1F0) ; Get DMA address LD BC,&0080 ; Prepare to copy 128 bytes - one record LD A,(LF1EE) ; Read/write flag? OR A JR NZ,LEEAB LD A,&01 LD (&F1E7),A EX DE,HL ; Swap source and dest .LEEAB LDIR ; Copy data to/from deblock area LD A,(LF1EF) CP &01 LD A,(&F1EC) LD SP,(LF1DC) ; Restore stack RET NZ OR A RET NZ XOR A LD (&F1E7),A CALL LEF04 LD A,(&F1EC) RET : .LEEC7 CALL LF02D CALL LF077 LD A,&53 JR Z,LEF1E LD A,(LF1E5) AND A JR Z,LEEE9 LD A,(LEFC0) LD HL,LF1E1 CP (HL) JR NZ,LEEE9 LD A,(LEFC7) LD HL,&F1E2 CP (HL) JR Z,LEEFF .LEEE9 LD HL,LEFC0 LD A,(LF1E1) LD (HL),A LD A,(&F1E2) LD (LEFC7),A CALL LEF49 RET NZ LD A,&FF LD (LF1E5),A .LEEFF LD A,&01 JP LEFFF : .LEF04 CALL LF02D LD A,&4B CALL LEF1E JR NZ,LEF17 CALL LF077 RET Z LD A,&00 JP LEFFF : .LEF17 PUSH AF XOR A LD (LF1E5),A POP AF RET : .LEF1E LD (LEFBB),A LD A,(LF1E1) LD (LEFB5),A LD A,(&F1E2) CP &50 JR C,LEF3A LD C,A LD A,(LEFB5) ADD A,&02 LD (LEFB5),A LD A,&9F SUB A,C .LEF3A LD (LEFBC),A LD A,(&F1E3) CALL LEFAC LD (LEFBD),A LD HL,LEFB5 .LEF49 PUSH HL CALL LF063 POP HL .LEF4E CALL &FFA4 AND A JR Z,LEFA7 CP &12 JR NZ,LEFA5 PUSH HL CALL LEC8E DEFB 13:DEFM "Bdos Err On ":DEFB 0 .LEF6A LD A,(LF1E1) AND &01 ADD A,&41 LD C,A CALL ConsoleOut CALL LEC8E DEFM ": R/O (Disc is Write Protected)":DEFB 0 CALL ConsoleIn POP HL CP &52 JR Z,LEF4E CP &72 JR Z,LEF4E RST &00 .LEFA5 LD A,&01 .LEFA7 AND A .LEFA8 LD (&F1EC),A RET : .LEFAC LD C,A LD B,&00 LD HL,LEFEB ADD HL,BC LD A,(HL) RET : .LEFB5 NOP .LEFB6 LD (HL),D JP P,&0000 INC BC .LEFBB LD D,E .LEFBC NOP .LEFBD NOP LD (&0000),HL NOP LD H,&FF RST &38 INC BC LD D,E .LEFC7 NOP NOP DEFB &2A .LEFCA NOP .DPH_Base DEFW &0000:DEFW &0000:DEFW &0000:DEFW &0000 ; DPH for drive 0 DEFW LF1F2:DEFW DPB_Acorn400k:DEFW &F16A:DEFW &F1AA : DEFW &0000:DEFW &0000:DEFW &0000:DEFW &0000 ; DPH for drive 1 DEFW LF1F2:DEFW DPB_Acorn400k:DEFW &F18A:DEFW &F1C3 : NOP INC B EX AF,AF' .LEFEE LD (BC),A DEFB &06 : .DPB_Acorn400k ; DPB for AcornCPM 400k disk DEFW &0014 ; SPT=20 Sectors Per Track DEFB &04 ; BSH=4 Block Shift DEFB &0F ; BLM=15 Block Mask DEFB &01 ; EXM=1 Extent Mask DEFW &00C3 ; DSM=195 Disk Sector Max DEFW &007F ; DRM=127 Maximum directory entry number DEFB &C0 ; AL0=&C0 Directory occupies DEFB &00 ; AL1=&00 first two blocks DEFW &0020 ; CKS=32 Size of directory checksum vector DEFW &0003 ; OFF=3 Reserved tracks before logical start of disk ; Total disk size is 128*(BLM+1)*(DSM+1)=392k : .LEFFF LD (LF02C),A LD A,(&F1E3) CALL LEFAC LD HL,&2500 INC A LD B,A LD DE,&0100 .LF010 ADD HL,DE DJNZ LF010 LD (LF022),HL LD HL,LF020 LD A,&FF CALL OSWORD XOR A RET : .LF020 DEC C LD BC,&0000 NOP NOP LD (HL),D JP P,&0000 NOP LD (BC),A .LF02C NOP .LF02D LD A,&01 LD HL,&F472 CALL OSWORD LD DE,(&F477) LD HL,(&F472) OR A SBC HL,DE RR B LD DE,&0180 OR A SBC HL,DE JR NC,LF05E LD DE,(&F479) LD HL,(&F474) RL B SBC HL,DE JR NZ,LF05E LD HL,(&F47B) LD A,(&F476) SBC A,L RET Z .LF05E XOR A LD (LF1E5),A RET : .LF063 LD A,(LF1E1) LD HL,LEFC0 CP (HL) RET NZ LD HL,&F472 LD DE,&F477 LD BC,&0005 LDIR RET : .LF077 LD A,(&F1E2) CP &03 JR Z,LF08B CP &04 JR NZ,LF089 LD A,(&F1E3) CP &03 JR C,LF08B .LF089 XOR A RET : .LF08B XOR A DEC A RET : .LF08E ; Look for a boot file LD C,&0D ; Reset disk system CALL &DC06 ; Call BDOS directly LD DE,LF146 ; Look for "BOOT.COM" LD C,&11 ; Search for first CALL &DC06 ; Call BDOS directly INC A JR Z,LF0BF ; Not found, try next one CALL LEC8E ; Print message: DEFM "Running BOOT.COM":DEFB 13:DEFB 0 LD HL,LF119 ; Point to "BOOT" command string .LF0B6 LD DE,&D407 ; Copy it into CCP command buffer LD BC,&000D LDIR RET : .LF0BF LD DE,LF139 ; Look for "BOOT.SUB" LD C,&11 CALL &DC06 ; Call BDOS directly INC A RET Z ; Not there, exit LD DE,LF12C ; Look for "SUBMIT.COM" LD C,&11 ; If BOOT.SUB is present, SUBMIT.COM must also be there CALL &DC06 ; Call BDOS directly INC A JR Z,LF0F1 ; Not there, report the problem CALL LEC8E ; Print message DEFM "Submitting BOOT.SUB":DEFB 13:DEFB 0 .LF0EC LD HL,LF11F ; Point to "SUBMIT BOOT" command string JR LF0B6 ; Jump back to copy it to CCP command buffer : .LF0F1 CALL LEC8E ; Print message: DEFM "BOOT.SUB present but no SUBMIT.COM":DEFB 13:DEFB 0 RET : .LF119 DEFB 4:DEFM "BOOT":DEFB 0 .LF11F DEFB 11:DEFM "SUBMIT BOOT":DEFB 0 .LF12C DEFB 0:DEFM "SUBMIT COM":DEFB 0 .LF139 DEFB 0:DEFM "BOOT SUB":DEFB 0 .LF146 DEFB 0:DEFM "BOOT COM":DEFB 0 DEFB 0 DEFB 0 .LF155 NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP .LF160 NOP NOP .LF162 NOP NOP NOP NOP NOP .LF167 :NOP ; Used in CONST .LF168 :DEFW &0000 .LF16A :DEFM &20 ; CSV for drive 0 .LF18A :DEFM &20 ; CSV for drive 1 .LF1AA :DEFM &19 ; ALV for drive 0 .LF1C3 :DEFM &19 ; ALV for drive 1 .LF1DC :DEFW &0000 ; Disk routines SP store .LF1DE :NOP ; Current drive .LF1DF :NOP ; Current track .LF1E0 :NOP ; Current sector .LF1E1 :NOP .LF1E2 :NOP .LF1E3 :NOP .LF1E4 :NOP .LF1E5 :NOP .LF1E6 :NOP ; Used in HOME .LF1E7 :NOP ; Used in HOME .LF1E8 :NOP .LF1E9 :NOP .LF1EA :NOP .LF1EB :NOP .LF1EC :NOP .LF1ED :NOP .LF1EE :NOP .LF1EF :NOP .LF1F0 :DEFW &0000 ; DMA .LF1F2 :DEFM &80 ; DIRBUF .LF272 :DEFM 4*128 ; Disk deblock area .LF472 \ f4cc - internal stack for Disk routines \ f4e0 - internal stack for Boot ]:NEXT