[sourcecode language="plain"] DEFINE NOT_HOMEROM ORG 0 INCLUDE "2068_DEFS.ASM" ; Home ROM addresses DEFC LED18 = $0E2F ;DEFC XFER_BYTES = $6722 DEFC MFD32 = $FD32 DEFC M6000 = $6000 DEFC MFD90 = $FD90 DEFC M255D = $255D DEFC DATTYPE = $00 DEFC FILENAME = $01 DEFC BLKLEN = $0B DEFC ARG1 = $0D DEFC ARG2 = $0F ;****************************************************************** ; Module: ; Routine: ; general routines used when the EXROM is switched in ;****************************************************************** XRST0: DI ;disable interrupts JR M0049 ;jump to bank transfer code DEFB $FF,$FF,$FF,$FF,$FF ;local RST 8 error handler. XRST8: LD HL,(CHADD) ;HL gets the address of the character ; in dispute LD (XPTR),HL ;put it into the "syntax error" character ; pointer POP HL ;get the caller's address LD L,(HL) ;/put the error code into LD (IY+OERRNR),L ;\ ERRNR LD SP,(ERRSP) ;get the error stack pointer ;jump to the home bank to handle the error LD HL,RESET ;/address for goto bank PUSH HL ;\ LD H,$FF ;/HOME bank ... LD L,$00 ;|... all chunks PUSH HL ;\ ;fall through to GOTO_BANK XRST20: PUSH AF ;save AF LD A,(VIDMOD) ;/ AND A ;|check the video mode NOP ;\ JR Z,M002C ;jump if normal video XRST28: POP AF ;restore AF CALL (($5200+GOTO_BANK+$97C0)~$FFFF) ;jump to RAM INT service when ; in extended video mode M002C: POP AF ;restore AF CALL ($5200+GOTO_BANK) ;jump to RAM service when ; in normal video mode XRST30: DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ;****************************************************************** ; Interrupt routine. called when the keyboard interrupt is ; received from the SCLD ;****************************************************************** XRST38: PUSH AF ;save AF DI ;disable interrupts LD A,(VIDMOD) ;/ AND A ;|check the video mode NOP ;\ JR Z,M0045 ;jump if normal video POP AF ;restore AF JP INT+$E9C0~$FFFF ;jump to RAM INT service when ; in extended video mode M0045: POP AF ;restore AF JP INT+$5200 ;jump to RAM INT service when ; in normal video mode ;****************************************************************** ; code executed on power-up if the SCLD has reset to in such a ; state so as to point to EXROM ;****************************************************************** M0049: LD A,$01 ;set HSR to point lower 8K to DOCK/EXROM OUT ($F4),A ; JR M005A ;****************************************************************** ; this section of code is transferred to HOME RAM by the code ; fragment at M005A during reset, then it is jumped to by the fragment ; ;execution of the following code will cause execution to transfer to the HOME bank ; at location $0054. XOR A ;/set HSR and EXROM/DOCK select to point to HOME bank OUT ($F4),A ;|HSR now selects all chunks to HOME/EXROM OUT ($FF),A ;\bank select now transfers us to HOME LD DE,$FFFF ; JP M0D31 ;****************************************************************** M005A: LD HL,$004F ;/ LD DE,$6000 ;|transfer the code fragment LD BC,$000B ;| from above to HOME ROM LDIR ;\ JP M6000 ;jump to it ;****************************************************************** ; Module: TAPE ; Routine: W_TAPE ; ; ;****************************************************************** W_TAPE: M0068: LD HL,$00E5 ; PUSH HL ; ;set the number of header half cycles based on A. if A>$7F, write a ; data block header else write a file header LD HL,$1F80 ;number of half-cycles for the ; header BIT 7,A ;/skip if header JR Z,M0076 ;\ LD HL,$0C98 ;number of half-cycles for the ; data header M0076: EX AF,AF' ;save the data byte INC DE ;/preadjust the counters for the following DEC IX ;\ processing DI ;don't interrupt the the tape output LD A,$02 ;/start sound with '0' and set border red LD B,A ;\(alternates with cyan) ;write the tape header M007E: DJNZ M007E ;delay loop for tone output OUT ($FE),A ;activate tape output bit XOR $0F ;flip the border color and tape output signal LD B,$A4 ;half-cycle time for 806.5Hz DEC L ;/jump if header not done JR NZ,M007E ;\ DEC B ;adjust B for processing time DEC H ;/jump if header not done JP P,M007E ;\ ;hokay, the header has now been written, so move on to writing the data ;write the single 2400Hz transition LD B,$2F ;first half-cycle of the 2400Hz transition M0090: DJNZ M0090 ;(adjusted for processing time) OUT ($FE),A ; LD A,$0D ;second half-cycle of the transition LD B,$37 M0098: DJNZ M0098 OUT ($FE),A LD BC,$3B0E ;B=half-cycle freq for 2400Hz, Tape output high, border = YELLOW EX AF,AF' ;get the type byte LD L,A ;save in L JP M00AD ;off to the races M00A4: LD A,D ;/jump if the byte counter is '0'; OR E ;|last byte to be written JR Z,M00B4 ;\ (send the checksum) LD L,(IX+$00) ;get the next byte M00AB: LD A,H ;get checksum XOR L ;XOR next byte to be sent M00AD: LD H,A ;save the checksum LD A,$01 ;Tape output low, border = BLUE SCF ;sentinal bit, byte to be sent will be zero only ; when all 8 bits have been shifted out JP M00CB ;start sending the byte M00B4: LD L,H ;get the checksum JR M00AB ;send it M00B7: LD A,C ;Tape output high, border = YELLOW BIT 7,B ;this will indicate that the 2nd half-cycle has ; been sent ;output the data bit in the CF M00BA: DJNZ M00BA ;wait a half-cycle JR NC,M00C2 ;jump if data bit is '0' LD B,$42 ;/wait a bit longer for a '1' M00C0: DJNZ M00C0 ;\ M00C2: OUT ($FE),A ;flip the bit LD B,$3E ;half-cycle for '0' JR NZ,M00B7 ;jump if next half-cycle is still to be sent DEC B ;B = $3D (make up for processing time) XOR A ;zero A (and reset carry flag) INC A ;A=1 M00CB: RL L ;get the next bit of the byte to send JP NZ,M00BA ;jump if bits are still left to be sent DEC DE ;decrement the byte count INC IX ;point to the next byte to send LD B,$31 ;half-cycle value for a '0' LD A,$7F ;precharge the A register IN A,($FE) ;read the keyboard RRA ;/return if key press detected RET NC ;\ LD A,D ;/continue if more bytes are waiting INC A ;|to be written JP NZ,M00A4 ;\(carry will be set on exit, indicating all is OK) LD B,$3B ;/wait for one last half-cycle M00E2: DJNZ M00E2 ;\ RET ;our job here is done ;****************************************************************** ; Module: TAPE ; Routine: W_BORD ;****************************************************************** W_BORD: PUSH AF ;save AF LD A,(BORDCR) ;get attribute AND $38 ;/ RRCA ;|form port compatible border RRCA ;|color value RRCA ;\ OUT ($FE),A ;set the border color LD A,$7F ;/ IN A,($FE) ;|check keyboard RRA ;\ EI ;enable interrupts JR C,M00FA ;jump if no key pressed RST $08 ;/error BREAK DEFB $0C ;\ M00FA: POP AF ;restore AF RET ;done ;****************************************************************** ; Module: TAPE ; Routine: R_TAPE ; ENTRY: IX points to the destination, DE is the block length to load ;****************************************************************** R_TAPE: M00FC: INC D ; EX AF,AF' ; DEC D ; DI ;don't interrupt us LD A,$0F ;/set tape out=high,border to WHITE OUT ($FE),A ;\ LD HL,$00E5 ; PUSH HL ; IN A,($FE) ;get tape input RRA ;tape bit is now in the $20 position AND $20 ;mask for the tape bit OR $02 ;set bit 1 LD C,A ;save the seed value for the call to R_EDGE CP A ;ensure we don't return before we call R_EDGE M0111: RET NZ ;return if tape bit is not high M0112: CALL R_EDGE ;check for transition on the tape input JR NC,M0111 ; a key was pressed, so abort ;there was a transition detected, so let's try to read the tape. ; wait for 1044 bit times: this is a significant fraction of the time needed ; for either of the headers LD HL,$0415 ;for 1044 bits M011A: DJNZ M011A ;wait for the length of time returned by R_EDGE ; at M0112 DEC HL ;/ LD A,H ;|jump if HL is not zero OR L ;| JR NZ,M011A ;\ CALL M0189 ;get a bit of data JR NC,M0111 ;error detected, so exit ;check for header M0126: LD B,$9C ; CALL M0189 ;get a bit of data JR NC,M0111 ;error detected, so exit LD A,$C6 ;/ CP B ;|jump if 806.5Hz detected? JR NC,M0112 ;\ INC H ; JR NZ,M0126 ;jump back if not enough cycles detected M0135: LD B,$C9 ; CALL R_EDGE ;check again for the edge of a bit JR NC,M0111 ;error detected, so exit LD A,B ; CP $D4 ; JR NC,M0135 ; CALL R_EDGE ;check for the edge of a bit RET NC ;error detected, so exit LD A,C ; XOR $03 ; LD C,A ; LD H,$00 ; LD B,$B0 ; JR M016E ; M014F: EX AF,AF' ; JR NZ,M0159 ; JR NC,M0163 ; LD (IX+$00),L ;save received byte at (IX) JR M0168 ; M0159: RL C ; XOR L ; RET NZ ; LD A,C ; RRA ; LD C,A ; INC DE ; JR M016A ; M0163: LD A,(IX+$00) ;get the last byte received XOR L ;check tha check sum RET NZ ;return if the checksum is in error M0168: INC IX ;bump the pointer M016A: DEC DE ;decrement the block length EX AF,AF' ; LD B,$B2 ; M016E: LD L,$01 ; M0170: CALL RD_BIT ;read a bit RET NC ;error detected, so return LD A,$CB ; CP B ; RL L ; LD B,$B0 ; JP NC,M0170 ; LD A,H ; XOR L ; LD H,A ; LD A,D ; OR E ; JR NZ,M014F ; LD A,H ; CP $01 ; RET ; ;****************************************************************** ; Module: TAPE ; Routine: RD_BIT ;****************************************************************** RD_BIT: M0189: CALL R_EDGE ;find the tape tone RET NC ;return if error detected, else ; move on to detect the next edge ;****************************************************************** ; Module: TAPE ; Routine: R_EDGE ; find the edge of a tape tone. ; ENTRY: B contains a value through which to wait ;****************************************************************** R_EDGE: M018D: LD A,$16 ;/ M018F: DEC A ;|wait a 70uS 4 JR NZ,M018F ;\ 7/12 AND A ;reset CF M0193: INC B ;bump the timer? 4 RET Z ;return if we have waited a long time? 10 LD A,$7F ;/ 7 IN A,($FE) ;|read the keyboard and the tape input bit RRA ;|(puts tape bit into $20 position and loads ;\LSB of key scan into the carry flag) RET NC ;return if key is pressed XOR C ;/this checks if there has been a transition ;| of the tape bit AND $20 ;\check the tape in bit JR Z,M0193 ;jump if this tape sample is the same as the ; last sample - wait for the transition LD A,C ;get previous tape input bit value CPL ;complement it LD C,A ;save it again AND $07 ;mask for the BORDER color OR $08 ;set the tape out bit (echo the sound on the ; tape) OUT ($FE),A ;output the new border color and tape bit SCF ;indicate all is OK RET ;weebiedun ;****************************************************************** ; Module: TAPE ; Routine: SLVM ; "Save, Load, Verify, Merge" ; this routine does the donkey work of parsing the command line for ; the tape functions. ; ENTRY: (TADDR) is used to differentiate between ; "LOAD", "SAVE", "VERIFY", or "MERGE" ;****************************************************************** SLVM: LD A,(TADDR) ;low byte of the syntax table pointer LD BC,PASAVE+1 ;address of PASAVE in the syntax table SUB C ;generate a value based on the instruction ; kinda cheesy, but seems to work. LD (TADDR),A ;(TADDR)= 0 for SAVE ; 1 for LOAD ; 2 for VERIFY ; 3 for MERGE ;get the file name. the string parameters will be on the top of the fp stack ; CALLBANKS TEM10,HOMEROM,$00 ;evaluate the next expression and return here if it is a string ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,TEM10 ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM BIT INTPT,(IY+$01) ;/jump if syntax checking JR Z,M0238 ;\ ;prepare to allocate a 17 byte header buffer if the value at TADDR is zero (SAVE) LD BC,$0011 ; LD A,(TADDR) ;/jump if SAVE (only one buffer needed) AND A ;| JR Z,M01DD ;\ ;allocate two header buffers worth of memory. this is needed for ; LOAD, VERIFY, and MERGE. one buffer for the stuff coming from tape, the other ; for the arguments coming from the command line. DE points to the start of the ; newly allocated memory LD C,$22 ; M01DD: ;M01DD: CALLBANKS ALLOCBC,HOMEROM,$00 ;allocate the header buffer ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,ALLOCBC ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM ;we will return here if the buffer could be allocated PUSH DE ;/copy the location of the header buffer POP IX ;\ to IX LD B,$0B ;/ LD A,' ' ;|fill up the program name with M01FB: LD (DE),A ;|spaces INC DE ;| DJNZ M01FB ;\ LD (IX+FILENAME),$FF ;indicate no name present ; check the name provided to the command ;get the string descriptor from the fp stack ; CALLBANKS PGPSTR,HOMEROM,$00 ;pop BC, DE, and A from fp stack PUSH IX EXX LD HL,PGPSTR ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM LD HL,-10 ;/test the length of the program name DEC BC ;|(a length of zero will cause an overflow ADD HL,BC ;\ hence an error) INC BC ;restore BC JR NC,M0231 ;jump if the name was less than 11 characters LD A,(TADDR) ;/jump if this command does not REQUIRE a name AND A ;| LOAD, MERGE, VERIFY JR NZ,M022A ;\ RST $08 ;/error F - invalid file name DEFB $0E ;\ M022A: LD A,B ;/jump if the length of the name is zero OR C ;|(no name to move, so don't) JR Z,M0238 ;\ LD BC,$000A ;length of a program name (transfer only the first 10 ; characters) M0231: PUSH IX ;save the header header buffer pointer POP HL ;get the header buffer pointer to HL INC HL ; EX DE,HL ;HL now points to the name, DE points to the header buffer LDIR ;move the name to the header buffer ; ;now to check the variants of save/load e.g. ; SAVE f LINE m, SAVE f DATA A(), SAVE f DATA A$(), SAVE f CODE m,n, SAVE f SCREEN$ ; M0238: ;M0238: CALLBANKS GETCURCH,HOMEROM,$00 ;call GETCURCH, get ; current character ; skipping spaces and ; control characters ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,GETCURCH ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM CP $E4 ;/jump if not "DATA" token JP NZ,M02F2 ;\ ; ;next, find the DATA item ; LD A,(TADDR) ;/determine if we are MERGE-ing CP $03 ;\ JP Z ,BADBAS ;declare a syntax error if so - ; can't MERGE DATA ;get the next character and then attempt to find it in the variables ; area will gobble the "(" of a numeric array or "$(" of a string array name ; CALLBANKD M0020,HOMEROM,$00,FIND_N,HOMEROM,$00 ;CALLBANKD: MACRO CALLADR1,DESTBANK1,HORIZSEL1,CALLADR2,DESTBANK2,HORIZSEL2 PUSH IX EXX LD HL,M0020 ; PUSH HL ; LD L,$00 ; LD H,HOMEROM ; PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK EXX LD HL,FIND_N ; PUSH HL ; LD L,$00 ; LD H,HOMEROM ; PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM SET 7,C ;force an array name JR NC,M0295 ;jump if we found the variable name LD HL,$0000 ;trash the pointer to the ; non-existant variable LD A,(TADDR) ;/jump if we were LOADing DEC A ;|(variable name not needed; the file JR Z,M02A9 ;\ header will supply it) RST $08 ;/error VARIABLE NOT FOUND DEFB $01 ;\ SLVBADBAS: M0295: JP NZ,BADBAS ;variable found was not an array variable or a string BIT 7,(IY+$01) ;/jump if syntax checking JR Z,M02B6 ;\ INC HL ;/ LD A,(HL) ;| LD (IX+BLKLEN),A ;|put the length of the variable INC HL ;| data structure in the header buffer LD A,(HL) ;| LD (IX+BLKLEN+1),A ;\ INC HL ;/save data type marker in buffer M02A9: LD (IX+ARG1+1),C ;\ LD A,$01 ;flag byte BIT 6,C ;/jump if dealing with numbers JR Z,M02B3 ;\ INC A ;/put flag (1 for strings, 2 for numbers) M02B3: LD (IX+DATTYPE),A ;\ in the buffer M02B6: EX DE,HL ; ; CALLBANKS M0020,HOMEROM,$00 ;get the next character ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,M0020 ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM CP ')' ;/jump if not close paren JR NZ,SLVBADBAS ;\ [must be there for SAVE f DATA xx()] ; CALLBANKS M0020,HOMEROM,$00 ;get the next character ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,M0020 ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM BIT 7,(IY+$01) ;/return if syntax checking - we are done RET Z ;\ EX DE,HL ; JP M04C9 ; M02F2: CP $AA ;/jump if not "SCREEN$" token JR NZ,M032E ;\ LD A,(TADDR) ;/syntax error if trying to MERGE CP $03 ;| can't MERGE SCREEN$ data JP Z ,BADBAS ;\ ; CALLBANKS M0020,HOMEROM,$00 ;get the next character ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,M0020 ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM BIT 7,(IY+$01) ;/return if syntax checing RET Z ;\ LD (IX+BLKLEN),00 ;/load screen length into buffer LD (IX+BLKLEN+1),$1B ;\ LD HL,$4000 ;/screen address LD (IX+ARG1),L ;| LD (IX+ARG1+1),H ;\ JP M0440 ; M032E: CP $AF ;/jump if not "CODE" token JP NZ,M0447 ;\ LD A,(TADDR) ;/ CP $03 ;|syntax error if trying to MERGE JP Z ,BADBAS ;\ ;get the next character and then check to see if we are at the end ; of a statement (":" or newline) ; CALLBANKD M0020,HOMEROM,$00,TERM?,HOMEROM,$00 ;CALLBANKD: MACRO CALLADR1,DESTBANK1,HORIZSEL1,CALLADR2,DESTBANK2,HORIZSEL2 PUSH IX EXX LD HL,M0020 ; PUSH HL ; LD L,$00 ; LD H,HOMEROM ; PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK EXX LD HL,TERM ; PUSH HL ; LD L,$00 ; LD H,HOMEROM ; PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM JR NZ,M0387 ;jump if not the end of a statement LD A,(TADDR) ;/ AND A ;|syntax error if trying to SAVE JP Z ,BADBAS ;\ ;stack a dummy argument ; CALLBANKS STKFP0,HOMEROM,$00 ;stack a zero on the fp staack ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,STKFP0 ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM JR M03BC ;proceed ;evaluate the next expression. it is numeric we will return here ; to then get the next character M0387: ;M0387: CALLBANKD TEM6,HOMEROM,$00,GETCURCH,HOMEROM,$00 ;CALLBANKD: MACRO CALLADR1,DESTBANK1,HORIZSEL1,CALLADR2,DESTBANK2,HORIZSEL2 PUSH IX EXX LD HL,TEM6 ; PUSH HL ; LD L,$00 ; LD H,HOMEROM ; PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK EXX LD HL,GETCURCH ; PUSH HL ; LD L,$00 ; LD H,HOMEROM ; PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM CP ',' ;/jump if comma JR Z,M03D5 ;\ LD A,(TADDR) ;/syntax error if trying to SAVE AND A ;| must have address and length JP Z ,BADBAS ;\ ;stack a second dummy argument M03BC: ;M03BC: CALLBANKS STKFP0,HOMEROM,$00 ;stack 0 to the fp stack ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,STKFP0 ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM JR M03FF ;(03FF) ;get the next character then evaluate the next expression. if numeric we ; will return here M03D5: ;M03D5: CALLBANKD M0020,HOMEROM,$00,TEM6,HOMEROM,$00 ;CALLBANKD: MACRO CALLADR1,DESTBANK1,HORIZSEL1,CALLADR2,DESTBANK2,HORIZSEL2 PUSH IX EXX LD HL,M0020 ; PUSH HL ; LD L,$00 ; LD H,HOMEROM ; PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK EXX LD HL,TEM6 ; PUSH HL ; LD L,$00 ; LD H,HOMEROM ; PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM M03FF: BIT 7,(IY+$01) ;/return if syntax checking - we are done RET Z ;\ ;put the top of the FP stack into BC ; CALLBANKS FIX_U,HOMEROM,$00 ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,FIX_U ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM LD (IX+BLKLEN),C ;/put the length of the code segment LD (IX+BLKLEN+1),B ;\ into the buffer ;put the top of the FP stack into BC ; CALLBANKS FIX_U,HOMEROM,$00 ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,FIX_U ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM LD (IX+ARG1),C ;/put the address of the code segment LD (IX+ARG1+1),B ;\ into the buffer LD H,B ;/put the code address into HL LD L,C ;\ M0440: LD (IX+DATTYPE),03 ;put the file type into the buffer - BINARY JP M04C9 ;jump to determine if we are SAVEing M0447: CP $CA ;/jump if "LINE" token JR Z,M0456 ;\ BIT 7,(IY+$01) ;/return if syntax checking RET Z ;\ LD (IX+ARG1+1),$80 ;/no line number specified JR M04A9 ;\ M0456: LD A,(TADDR) ;/ AND A ;|syntax error if NOT trying to SAVE JP NZ,BADBAS ;\ ;get the next character and then evaluate the next expression. ; return here if its numeric ; CALLBANKD M0020,HOMEROM,$00,TEM6,HOMEROM,$00 ;CALLBANKD: MACRO CALLADR1,DESTBANK1,HORIZSEL1,CALLADR2,DESTBANK2,HORIZSEL2 PUSH IX EXX LD HL,M0020 ; PUSH HL ; LD L,$00 ; LD H,HOMEROM ; PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK EXX LD HL,TEM6 ; PUSH HL ; LD L,$00 ; LD H,HOMEROM ; PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM BIT 7,(IY+$01) ;/return if syntax checking RET Z ;\ ;put the top of the FP stack into BC ; CALLBANKS FIX_U,HOMEROM,$00 ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,FIX_U ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM LD (IX+ARG1),C ;/put the line number into the buffer LD (IX+ARG1+1),B ;\ M04A9: LD (IX+$00),00 ;put file type into the buffer LD HL,(ELINE) ;/ LD DE,(PROG) ;|compute the length of the program SCF ;|and variables to the $80 byte SBC HL,DE ;\just after the variables LD (IX+BLKLEN),L ;/block length to the LD (IX+BLKLEN+1),H ;\buffer LD HL,(VARS) ;/compute the variables area length SBC HL,DE ;\ LD (IX+ARG2),L ;/length of the variables LD (IX+ARG2+1),H ;\to the buffer EX DE,HL ;DE=length, HL=(VARS) M04C9: LD A,(TADDR) ;/ AND A ;|jump if we are SAVEing JP Z,SAVE ;\ PUSH HL ;save the block length LD BC,$0011 ;/point to the buffer used to store ADD IX,BC ;\ the header coming in from the tape M04D6: PUSH IX ;save the header LD DE,$0011 ;length of the header XOR A ;reset the carry and zero the accumulator SCF ;set the carry flag ("LOAD" the tape) ;read the program header CALL R_TAPE ;read the tape POP IX ;restore the header pointer JR NC,M04D6 ;loop around for unsuccessful load ; (break or error) LD A,$FE ;select channel -2 ; CALLBANKS SELECT,HOMEROM,$00 ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,SELECT ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM LD (IY+$52),03 ;load the scroll count with 3 LD C,$80 ; LD A,(IX+DATTYPE) ;/compare the file type from the CP (IX+(-$11)) ;\tape with the file type from the command line JR NZ,M050D ;not the same, so check if it is a TS file LD C,$F6 ;-10 M050D: CP $04 ; JR NC,M04D6 ;we found a non TS file type, so back around ; ;we found some type of file so tell the user so ; LD DE,$3CA8 ; address of "Program: " message PUSH BC ;briefly save C ;print a message to the current channel. A contains the number of the message to ; be printed ; CALLBANKS PUTMES,HOMEROM,$00 ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,PUTMES ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM POP BC ;restore BC PUSH IX ;save buffer pointer POP DE ;get it to DE LD HL,-16 ;/subtract 16 from the buffer pointer ADD HL,DE ;\ DE points to the second buffer name LD B,$0A ;name length counter LD A,(HL) ;get the first letter of the file name INC A ;/jump if a name was given (<>$FF) JR NZ,M053D ;\ LD A,C ;load a with the length of the name ADD A,B ;add to the max length of a name LD C,A ;save the length of the name ; ;loop to write the file name ; M053D: INC DE ;/get a character from the buffer pointer LD A,(DE) ;\ (we preincrement to get past the data type on the first iteration) CP (HL) ;compare it to the received name INC HL ;move along JR NZ,M0544 ;jump if it does not match INC C ;if it does match, increment the match counter ;write the character in A M0544: ;M0544: CALLBANKS WRCH,HOMEROM,$00 ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,WRCH ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM DJNZ M053D ;back around for another name BIT 7,C ;/if the names matched, C will have rolled over JP NZ,M04D6 ;\ ;print a newline LD A,$0D ;newline ; CALLBANKS WRCH,HOMEROM,$00 ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,WRCH ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM POP HL ; LD A,(IX+DATTYPE) ;get the data type CP $03 ;/jump if it is "CODE" JR Z,M058F ;\ LD A,(TADDR) ;/ DEC A ;|jump to LOAD JP Z ,M05CC ;\ CP $02 ;/jump if character array JP Z ,M06E5 ;\ M058F: PUSH HL ; LD L,(IX+(-$06)) ;/get second buffer block length LD H,(IX+(-$05)) ;\ LD E,(IX+BLKLEN) ;/get this block length LD D,(IX+BLKLEN+1) ;\ LD A,H ;/ OR L ;|jump if HL = 0 JR Z,M05AD ;\ SBC HL,DE ; JR C,M05CA ; JR Z,M05AD ; LD A,(IX+DATTYPE) ;/ CP $03 ;|jump if this is "CODE" JR NZ,M05CA ;\ M05AD: POP HL ; LD A,H ;/ OR L ;|jump if zero JR NZ,M05B8 ;\ LD L,(IX+ARG1) LD H,(IX+ARG1+1) M05B8: PUSH HL POP IX LD A,(TADDR) ;/jump if VERIFY CP $02 ;\ SCF ;force load JR NZ,M05C4 ; AND A ;force VERIFY M05C4: LD A,$FF ;specify a data block R_TAPE1: CALL R_TAPE ;/return if no tape loading error RET C ;\ M05CA: RST $08 ;error TAPE LOADING ERROR DEFB $1A ; ;****************************************************************** ; Module: TAPE ; Routine: LOAD ; this routine does the nitty-gritty of actually loading and ; merging program text and merging data from tape - ugggg!! ;****************************************************************** LOAD: M05CC: LD E,(IX+BLKLEN) ;/get the data block length LD D,(IX+BLKLEN+1) ;\ PUSH HL ;save the length of the target data structure LD A,H ;/ OR L ;|jump if it is not zero JR NZ,M05DD ;\ INC DE ;/adjust to reserve space for a name and INC DE ;| length bytes INC DE ;\ EX DE,HL ;HL = requred block length, DE = 0 JR M05E9 ; ;handle an existing array with name the same name as the proposed array M05DD: LD L,(IX+(-$06)) ;/get the other block length LD H,(IX+(-$05)) ;\ EX DE,HL ;/ SCF ;|jump if the existing data block SBC HL,DE ;| is at least long enough to hold JR C,M0606 ;\ the new data M05E9: LD DE,$0005 ;/add 5 bytes to the block length ADD HL,DE ;|BC = number of additional bytes needed LD B,H ;| for this data block LD C,L ;\ ; CALLBANKS CHK_SZ,HOMEROM,$00 ;check for BC bytes available ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,CHK_SZ ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM ; ;if we got here then there is enough space for the data coming in ; M0606: POP HL ;restore the existing data block length LD A,(IX+DATTYPE) ;/ AND A ;|jump if this is a program JR Z,M0673 ;\ LD A,H ;/jump if the existing block length is zero OR L ;| to create the variable JR Z,M0638 ;\ ; ;destroy the present array with the name of the proposed data array ; DEC HL ;point to the array size LD B,(HL) ;/ DEC HL ;|get the array size into BC LD C,(HL) ;| DEC HL ;\ INC BC ;/add the length of the array name INC BC ;| and array length bytes INC BC ;\ LD (XPTR),IX ;save IX ; CALLBANKS DELREC,HOMEROM,$00 ;delete the existing array ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,DELREC ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM LD IX,(XPTR) ;restore IX ; ; ; M0638: LD HL,(ELINE) ;/point to the $80 byte in the variables area DEC HL ;\ LD C,(IX+BLKLEN) ;/get the required data block length LD B,(IX+BLKLEN+1) ;\ PUSH BC ;save the block length INC BC ;/ INC BC ;|need three more bytes for the array name and INC BC ;\length LD A,(IX+(-$03)) ;get the array ID for the incoming data PUSH AF ;save it ; CALLBANKS INSERT,HOMEROM,$00 ;make room at (HL) for the array ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,INSERT ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM INC HL ;/ POP AF ;|store the array name LD (HL),A ;\ POP DE ;/ INC HL ;| LD (HL),E ;|store the array length INC HL ;| LD (HL),D ;\ INC HL ;point to the "number of dimensions" PUSH HL ;/IX now points to the destination address for POP IX ;\ the array data SCF ;/"load..." LD A,$FF ;|"...a data block" JP R_TAPE1 ;\read the data block and exit via SLVM ; ;program loading ; M0673: EX DE,HL ;DE = end address LD HL,(ELINE) ;/point to the $80 byte at the end of the variables DEC HL ;\ area LD (XPTR),IX ;save the buffer header pointer LD C,(IX+BLKLEN) ;/ LD B,(IX+BLKLEN+1) ;|get the data block length and briefly save it PUSH BC ;\ ; CALLBANKS DEL_DE,HOMEROM,$00 ;delete the bytes between HL and DE ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,DEL_DE ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM POP BC ;pop the block length PUSH HL ;push the data buffer address PUSH BC ;push the block length ; ; reserve space for the incoming lines ; ; CALLBANKS INSERT,HOMEROM,$00 ;make room at (HL) for BC bytes ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,INSERT ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM LD IX,(XPTR) ;get the buffer header pointer back INC HL ;get the original address back LD C,(IX+ARG2) ;/get the variables address from the file LD B,(IX+ARG2+1) ;\ ADD HL,BC ;/point to the new variables area LD (VARS),HL ;\ and save it in the system vars area LD H,(IX+ARG1+1) ;get the putative line number LD A,H ;/ AND $C0 ;|jump if not a valid line number JR NZ,M06D5 ;\ LD L,(IX+ARG1) ;get the lower byte of the line number LD (NEWPPC),HL ;store the line number into the next line number LD (IY+ONSPPC),00 ;subline 0 M06D5: POP DE ;restore the block length POP IX ; SCF ;"load..." LD A,$FF ;"...a data block" LD HL,(PROG) ;get the address of the program text DEC HL ;point to the $80 byte LD (DATADD),HL ;data terminator character (no data) JP R_TAPE1 ;read the tape M06E5: LD C,(IX+BLKLEN) ;/get the required data block length LD B,(IX+BLKLEN+1) ;\ PUSH BC ;save the block length INC BC ;room for the $80 byte ; CALLBANKS ALLOCBC,HOMEROM,$00 ;expand the workspace BC bytes ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,ALLOCBC ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM LD (HL),$80 ;$80 byte for the end of the edit buffer EX DE,HL ;HL = the start of the newly freed space POP DE ;pop the block length PUSH HL ;save the pointer to the end of the reserved area PUSH HL ;...and again POP IX ;point to the end of the reserved area SCF ;/"load..." LD A,$FF ;|"...a data block" CALL R_TAPE1 ;\read the program lines in from tape POP HL ;point to the newly loaded data LD DE,(PROG) ;get the start of the program file M0717: LD A,(HL) ;/get the first byte of the newly loaded BASIC progrm AND $C0 ;|jump if not a valid line number JR NZ,M0749 ;\ M071C: LD A,(DE) ;get the first byte of the old BASIC program INC DE ;bump the old pointer CP (HL) ;compare to the new BASIC INC HL ;bump the new pointer JR NZ,M0724 ;old and new line numbers not the same so jump LD A,(DE) ;/compare the last half of the line numbers CP (HL) ;\ M0724: DEC DE ;/bump both BASIC pointers back DEC HL ;\ JR NC,M0744 ;jump if the new line number is less than or equal to the ; old line number to insert the new line into the program PUSH HL ;save the new pointer EX DE,HL ;HL=old pointer, DE=the new pointer ; CALLBANKS RECLEN,HOMEROM,$00 ;find the next variable or BASIC line ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,RECLEN ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM POP HL ;restore the new pointer JR M071C ;back around to test the new line M0744: CALL M0799 ; JR M0717 ; M0749: LD A,(HL) ;get the character from the new code LD C,A ;/ CP $80 ;|return if we have reached the end of the code RET Z ;\ ; ;was not BASIC code, so try to find the entity in the variables area ; HL DE BC STK PUSH HL ;save the pointer to the new code new old new LD HL,(VARS) ;get the pointer to the variables area vars old new M0752: LD A,(HL) ;/ CP $80 ;|jump if there are no variables JR Z,M0790 ;\ CP C ;/jump if the variable name in the new code starts with JR Z,M0776 ;\ the same letter as the one just found M075A: PUSH BC ;save C vars old BC,new ; CALLBANKS RECLEN,HOMEROM,$00 ;find the next variable or BASIC line ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,RECLEN ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM ; vars newrec new POP BC ;restore C EX DE,HL ;/put pointers back and try the next variable name vars newrec JR M0752 ;\ M0776: AND $E0 ;mask out the variable discriminator bits CP $A0 ;/jump if not a multi letter variable JR NZ,M078E ;\ ; ;loop through the characters of a multi-letter variable name to determine whether the new ; name matches the one in the variables area ; POP DE ;get the pointer to the new code vars new PUSH DE ;save it again vars new new PUSH HL ;save the pointer to the old code vars new vars,new M077F: INC HL ;/move to the next character INC DE ;\ LD A,(DE) ;/ CP (HL) ;|jump if the variable names do not match JR NZ,M078B ;\ RLA ;/loop back around if not the last character JR NC,M077F ;\ POP HL ;restore the pointer to the old code vars new new JR M078E ; M078B: POP HL ;/multi-letter name did not match, so vars new new JR M075A ;\ back around to try again M078E: LD A,$FF ;will force falling through at M0799 M0790: POP DE ;restore the pointer to the new code vars new -- EX DE,HL ;swap the pointers new vars INC A ; SCF ; CALL M0799 ; JR M0749 ; M0799: JR NZ,M07CF ;jump if we are just inserting a record EX AF,AF' ; LD (XPTR),HL ;save EX DE,HL ; vars new ;find the next line or variable, then delete it ; CALLBANKD RECLEN,HOMEROM,$00,DELREC,HOMEROM,$00 ;CALLBANKD: MACRO CALLADR1,DESTBANK1,HORIZSEL1,CALLADR2,DESTBANK2,HORIZSEL2 PUSH IX EXX LD HL,RECLEN ; PUSH HL ; LD L,$00 ; LD H,HOMEROM ; PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK EXX LD HL,DELREC ; PUSH HL ; LD L,$00 ; LD H,HOMEROM ; PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM EX DE,HL ; LD HL,(XPTR) ; EX AF,AF' ; ;insert a new record M07CF: EX AF,AF' ; PUSH DE ;save the pointer to the new code ; CALLBANKS RECLEN,HOMEROM,$00 ;find the next variable or program line ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,RECLEN ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM LD (XPTR),HL ;save pointer to old code LD HL,(PROG) ;get the pointer to the BASIC program EX (SP),HL ; PUSH BC ; EX AF,AF' ; JR C,M080E ; DEC HL ; ; CALLBANKS INSERT,HOMEROM,$00 ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,INSERT ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM INC HL ; JR M0825 ; M080E: ;M080E: CALLBANKS INSERT,HOMEROM,$00 ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,INSERT ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM M0825: INC HL ; POP BC ; POP DE ; LD (PROG),DE ; LD DE,(XPTR) ; PUSH BC ; PUSH DE ; EX DE,HL ; LDIR ; POP HL ; POP BC ; PUSH DE ; ; CALLBANKS DELREC,HOMEROM,$00 ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,DELREC ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM POP DE ; RET ; ;****************************************************************** ; Module: TAPE ; Routine: SAVE ;****************************************************************** ;select the keyboard and lower screen as the current channel SAVE: M0851: PUSH HL ;save the data buffer address LD A,$FD ;channel -3, keyboard and lower screen ; CALLBANKS SELECT,HOMEROM,$00 ;select channel -3 ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,SELECT ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM XOR A ;message number 0 LD DE,$3C89 ; ; CALLBANKS PUTMES,HOMEROM,$00 ;put message 0 to current channel ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,PUTMES ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM SET CLHS,(IY+OTVFLAG) ;force clear lower half screen if keypressed CALL M08AA ;wait for a key to be pressed PUSH IX ;save the header buffer address LD DE,$0011 ;tape header length XOR A ;tell W_TAPE we want to write a header CALL W_TAPE ; POP IX ;restore the header buffer address LD B,$32 ;/ M089A: HALT ;|wait for approx 1000mS DJNZ M089A ;\ LD E,(IX+BLKLEN) ;get the length of the data block from the LD D,(IX+BLKLEN+1) ; header LD A,$FF ;tell W_TAPE we are writing data POP IX ;pop the data buffer address JP W_TAPE ;write the data and return to ; caller via W_TAPE's return ;****************************************************************** ; Module: TAPE ; Routine: AKEY ;****************************************************************** AKEY: M08AA: PUSH AF ;/ PUSH BC ;|briefly save registers PUSH DE ;\ LD BC,$9C40 ;/ M08B0: DEC BC ;|wait for approx 238mS LD A,C ;| OR B ;| JR NZ,M08B0 ;\ ;wait for a key press M08B5: XOR A ;zero the accum IN A,($FE) ;poll the keyboard AND $1F ;use only the keyboard bits CP $1F ;/jump if no key is pressed JR Z,M08B5 ;\ ; CALLBANKS CLLHS,HOMEROM,$00 ;clear the lower half of the screen ;CALLBANKS: MACRO CALLADR,DESTBANK,HORIZSEL PUSH IX EXX LD HL,CLLHS ; PUSH HL ; LD L,$00 ;horizontal select LD H,HOMEROM ;home bank PUSH HL ; LD HL,$0000 ; PUSH HL ; PUSH HL ; EXX ; CALL M0F99 ;CALL BANK POP IX ; ENDM POP DE ;/ POP BC ;|restore registers POP AF ;\ RET ;back to the "save" routine BADBAS: M08D9: EXX ;alt regs LD HL,$1BED ;address for BAD BASIC COMMAND ; error routine PUSH HL ;save jump address LD L,$00 ;all chunks LD H,$FF ;home bank PUSH HL ;save bank/chunk EXX ;reg registers CALL GOTO_B ;local local GOTO_BANK ;****************************************************************** ; Module: INIT ; Routine: EXTINIT ;****************************************************************** EXTINIT: LD HL,$5EEA ;/initialize the SYSCON LD (SYSCON),HL ;\system variable CALL BLDSCT ;build the system config table LD HL,(SYSCON) ;point to SYSCON table LD DE,$0008 ;/point to LROS ID ADD HL,DE ;\ LD A,(HL) ;/ CP $01 ;|jump if not LROS JR NZ,M090F ;\ PUSH HL ;save LROS pointer CALL NORMSVAR ;initialize various system variables POP HL ;/ INC HL ;| LD E,(HL) ;|push LROS entry point INC HL ;| LD D,(HL) ;| PUSH DE ;\ LD B,$00 ;specify dock bank INC HL ;/ LD C,(HL) ;|get HSR byte PUSH BC ;\ EI ;enable interrupts CALL $5200+GOTO_BANK ;call GOTO_BANK - goto the AROS M090F: LD HL,(SYSCON) ;get SYSCON INC HL ;/get possible LROS ID LD A,(HL) ;\ CP $02 ;/jump if AROS machine code JR Z,M091E ;\ cartridge CALL NORMSVAR ;initialize various system variables JP M099A ;handle M091E: DEC HL ;/get the code type designator LD A,(HL) ;\ CP $01 ;/jump if BASIC code JR Z,M0956 ;\ CP $02 ;/jump if machine code JR NZ,LROS_ERR ;\ LD DE,$0006 ;/ ADD HL,DE ;| LD C,(HL) ;|BC contains the number of INC HL ;| bytes to reserve for machine code LD B,(HL) ;\ LD HL,$6840 ;start of LROS code buffer? ADD HL,BC ;/ EX DE,HL ;|move BC bytes at (HL) up to (DE) LD HL,$6840 ;| where (DE) = $6840+BC LDIR ;\ CALL INITSYSVAR ; LD HL,(SYSCON) ;/ LD DE,$0005 ;|get the AROS memory specification ADD HL,DE ;| LD A,(HL) ;\ CP $00 ;/jump if not autostart JR Z,M099A ;\ DEC HL ;/C = chunk specification LD C,(HL) ;\ DEC HL ;/ LD D,(HL) ;|DE = address of first BASIC line DEC HL ;| or first machine code instruction LD E,(HL) ;\ PUSH DE ;save the start address LD B,$00 ;/save the chunk specification PUSH BC ;\ EI ;enable interrupts CALL $5200+GOTO_BANK ;GOTO BANK (jump to the machine code) M0956: CALL NORMSVAR ; LD A,$80 ;/set flag to show AROS is present LD (ARSFLG),A ;\ LD HL,AROS ;/jump to the AROS handler PUSH HL ;\ LD B,$FF ;home bank LD C,$00 ;all of memory PUSH BC ; CALL $5200+GOTO_BANK ;GOTO BANK LROS_ERR: RST $08 ;/error "MISSING LROS" DEFB $1B ;\ NORMSVAR: LD HL,$6840 ;point past the RAM resident services LD DE,$0015 ;/reserve space for the CHANS table ADD HL,DE ;\ INITSYSVAR: LD (DATADD),HL ;initialize the DATA pointer INC HL ;/point to the start of BASIC LD (PROG),HL ;\ LD (VARS),HL ;initialize the variables pointer LD (HL),$80 ;/drop the sentinal at the end of the ;\ variables ares INC HL ;/initialize the input line buffer LD (ELINE),HL ;\ LD (HL),$0D ;stuff a carriage return INC HL ;/sentinal byte LD (HL),$80 ;\ INC HL ;/ LD (WORKSP),HL ;|initialize system variables LD (STKBOT),HL ;| LD (STKEND),HL ;\ XOR A ; LD (ARSFLG),A ;show no AROS present LD (VIDMOD),A ;normal video mode RET ; M099A: LD D,$FF ;home bank LD E,$80 ;HS select, top chunk in EXROM/DOCK LD HL,LED18 ;jump address in HOME ROM PUSH HL ;stack the jump address PUSH DE ;stack bank/HS LD HL,(SYSCON) ;/point to the first expansion bank LD DE,$000C ;| entry ADD HL,DE ;\ LD B,$00 ;prep BC for the next ops M09AC: LD A,(HL) ;get the entry for an expansion bank CP $80 ;/jump if at the end of the SYSCON area JR Z,M09E3 ;\ CP $00 ;/no entry for this bank, so move on JR Z,M09DD ;\to check the next one INC HL ;/pick up bank number LD B,(HL) ;\ LD DE,$0014 ;/ ADD HL,DE ;| LD A,(HL) ;|jump if active? or code? RRCA ;| JR C,M09C4 ;\ INC HL ;/point to the next exp bank entry in INC HL ;|the SYSCON area INC HL ;\ JR M09AC ;back around to check for more M09C4: INC HL ;/get HS for this exp bank LD A,(HL) ;\ POP DE ;remove the bank/HS from the stack CP E ;/jump if this exp bank needs more JR C,M09CF ;\ HS than is currently allocated PUSH DE ;save bank/HS INC HL ;/point to the next exp bank INC HL ;|entry in the SYSCON JR M09AC ;\ M09CF: POP DE ;trash the call address LD DE,$0005 ;/point to CAL nn or JP nn SBC HL,DE ;| in SYSCON table and PUSH HL ;\ stack it LD C,A ;update HS PUSH BC ;save bank/HS INC DE ;/ INC DE ;|point to next entry in SYSCON ADD HL,DE ;\ JR M09AC ;back around for more M09DD: LD DE,$0018 ;/point to the next expansion bank entry ADD HL,DE ;\in the SYSCON area JR M09AC ;back around to check for more M09E3: POP BC ;get the bank/HS LD A,B ;/ CP $FF ;|jump if going to HOME bank JR Z,M09ED ;\ LD C,$58 ;allow chunks 3, 4, and 6 to be in expansion banks JR M09EF ; M09ED: LD C,$00 ;allocate all chunks to HOME M09EF: PUSH BC ;save bank/HS EI ;enable interrupts CALL $5200+GOTO_BANK ;goto bank ;****************************************************************** ; Module: INIT ; Routine: BLDSCT ; build the system configuration table ;****************************************************************** BLDSCT: LD HL,(SYSCON) ;point to SYSCON buffer XOR A ;0 A LD (MAXBNK),A ;zero out MAXBANK LD ($6315),A ;zero out dispatcher's copy of MAXBANK LD DE,$0008 ;/point to LROS buffer ADD HL,DE ;\ ; ;transfer bytes from LROS to the SYSCON table ; LD E,$FF ;/dest bank = $FF (home) LD D,$00 ;|src bank = $00 (dock) PUSH DE ;\ LD DE,$0001 ;/set source address PUSH DE ;\ PUSH HL ;set destination address LD DE,$0004 ;/set length PUSH DE ;\ LD DE,$0001 ;/set direction (LDIR) PUSH DE ;\ CALL $5200+XFER_BYTES ;transfer the bytes LD A,(HL) ;/ CP $01 ;|jump if LROS signature present JR Z,M0A3E ;\ LD (HL),$00 ;zero LROS signature to prevent ; system from incorrectly seeing ; an LROS as present ; ;transfer bytes from AROS to the SYSCON ; LD E,$FF ;/dest bank = $FF (home) LD D,$00 ;|src bank = $00 (dock) PUSH DE ;\ LD DE,$8000 ;/set source address PUSH DE ;\ LD HL,(SYSCON) ;/get SYSCON buffer address PUSH HL ;\and use as destination address LD DE,$0008 ;/set length PUSH DE ;\ LD DE,$0001 ;/set direction PUSH DE ;\ CALL $5200+XFER_BYTES ;transfer the bytes INC HL ;/get AROS signature byte LD A,(HL) ;\ CP $02 ;/jump if valid AROS ID byte JR Z,M0A3E ;\ LD (HL),$00 ;zero out AROS ID byte, as we do not have ; a valid AROS cartridge ;we will also get to this point if there is a valid LROS via $0A1A M0A3E: LD HL,(SYSCON) ;get SYSCON buffer address LD DE,$000D ;/point to AROS buffer? ADD HL,DE ;\ LD D,$C0 ;bank status register address LD E,$00 ;bank status register value CALL $5200+WRITE_BS_REG ;write to bank status register M0A4C: CALL M0BD1 ;find valid banks JP NC,M0AD4 ; LD B,A ; SET 7,B ; LD (HL),B ; RES 7,B ; INC HL ; LD C,$FE ;/dest bank = EXROM PUSH BC ;\ LD DE,$08E7 ;/set source address PUSH DE ;\ LD DE,$0000 ;/get SYSCON buffer address PUSH DE ;\and use as destination address LD DE,$0001 ;/set length PUSH DE ;\ PUSH DE ;set direction CALL $5200+XFER_BYTES ;transfer the bytes LD E,$FF ;dest bank = $FF (home) LD D,A ;src bank provided by caller PUSH DE ;set bank LD DE,$0000 ;/set source adr PUSH DE ;\ PUSH HL ;set dest address LD DE,$0016 ;/set length PUSH DE ;\ LD DE,$0001 ;/set direction PUSH DE ;\ CALL $5200+XFER_BYTES ;transfer the bytes LD D,(HL) ;/ LD A,($08E7) ;|jump if we are not in CP D ;|the EXTROM JP NZ,M0AC2 ;\ LD C,$FE ;dest bank = $FE (external) PUSH BC ;set banks LD DE,$0A4C ;/set source adr PUSH DE ;\ LD DE,$0000 ;/set dest adr PUSH DE ;\ LD DE,$0001 ;length/direction PUSH DE ;set length PUSH DE ;set direction CALL $5200+XFER_BYTES ;get bytes LD E,$FF ;dest bank = home LD D,A ;src bank = user's PUSH DE ;set banks LD DE,$0000 ;/set source adr PUSH DE ;\ PUSH HL ;set user's destination LD DE,$0016 ;/set block length PUSH DE ;\ LD DE,$0001 ;/set direction PUSH DE ;\ CALL $5200+XFER_BYTES ;transfer the bytes LD D,(HL) ;/ LD A,($08E7) ;|get first byte of user's buffer CP D ;|and jump if user is not EXROM JP NZ,M0AC2 ;\ DEC HL ; DEC HL ; CALL M0ADB ; LD DE,$0015 ; ADD HL,DE ; JR M0ACA ; M0AC2: LD A,D ; AND $DF ; LD (HL),A ; DEC HL ; CALL M0C1F ; M0ACA: LD D,$C0 ; LD E,$01 ; CALL $5200+WRITE_BS_REG ; JP M0A4C ; M0AD4: DEC HL ; LD (HL),$80 ; CALL M0CFB ; RET ; M0ADB: LD (HL),$02 ; PUSH BC ;push user's bank info LD DE,$0038 ;/set source PUSH DE ;\ PUSH DE ;set destination LD DE,$0010 ;/set block length PUSH DE ;\ LD DE,$0001 ;/set direction PUSH DE ;\ CALL $5200+XFER_BYTES ;transfer bytes INC HL ; INC HL ; LD A,(HL) ; SET 0,A ; LD (HL),A ; LD DE,$0000 ; LD A,$01 ; M0AF9: EX AF,AF' ; PUSH HL ; EX DE,HL ; LD DE,$2000 ; ADD HL,DE ; EX DE,HL ; POP HL ; LD B,$FE ;src bank = EXROM LD A,(MAXBNK) ;get MAXBANK LD C,A ;dest bank = MAXBANK PUSH BC ;set banks LD BC,$08E7 ;/set source PUSH BC ;\ PUSH DE ;set destination LD BC,$0001 ;/ PUSH BC ;|set byte count and direction PUSH BC ;\ CALL $5200+XFER_BYTES ;transfer bytes LD A,(MAXBNK) ;get MAXBANK LD B,A ;src = MAXBANK LD C,$00 ;dest = Dock PUSH BC ;set banks PUSH DE ;set user's source INC HL ;bump user's destination PUSH HL ;set user's destination LD BC,$0001 ;/ PUSH BC ;|set block length and direction PUSH BC ;\ CALL $5200+XFER_BYTES ;transfer bytes LD B,(HL) ;/ DEC HL ;|jump if destination was LD A,($08E7) ;|not EXROM CP B ;| JR NZ,M0B95 ;\ LD B,$FE ;src bank = EXROM LD A,(MAXBNK) ;get MAXBANK LD C,A ;dest bank = MAXBANK PUSH BC ;set banks LD BC,$0A4C ;/set source PUSH BC ;\ PUSH DE ;set user's destination LD BC,$0001 ;/ PUSH BC ;|set direction and byte count PUSH BC ;\ CALL $5200+XFER_BYTES ;transfer bytes LD A,(MAXBNK) ;get MAXBANK LD B,A ;src bank = MAXBANK LD C,$00 ;dest bank = Dock PUSH BC ;set banks PUSH DE ;set user's source INC HL ;bump user's destination PUSH HL ;set user's destination LD BC,$0001 ;/ PUSH BC ;|set direction and byte count PUSH BC ;\ CALL $5200+XFER_BYTES ;transfer bytes LD B,(HL) ;get the value at (HL) DEC HL ;back a byte LD A,($0A4C) ;A=$CD??? CP B ;/jump if B is not $CD JR NZ,M0B95 ;\ ; ;this routine sets the bit whose number is in A' ; EX AF,AF' ; LD B,(HL) ;get the byte at (HL) CP $01 ;/ JR NZ,M0B68 ;|if 1, set bit 1 in B SET 1,B ;| then move on JR M0B92 ;\ M0B68: CP $02 ;/ JR NZ,M0B70 ;|if 2, set bit 2 in B SET 2,B ;| then move on JR M0B92 ;\ M0B70: CP $03 ;/ JR NZ,M0B78 ;|if 3, set bit 3 in B SET 3,B ;| then move on JR M0B92 ;\ M0B78: CP $04 ;/ JR NZ,M0B80 ;|if 4, set bit 4 in B SET 4,B ;| then move on JR M0B92 ;\ M0B80: CP $05 ;/ JR NZ,M0B88 ;|if 5, set bit 5 in B SET 5,B ;| then move on JR M0B92 ;\ M0B88: CP $06 ;/ JR NZ,M0B90 ;|if 6, set bit 6 in B SET 6,B ;| then move on JR M0B92 ;\ M0B90: SET 7,B ;else set bit 7 M0B92: LD (HL),B ;save byte back JR M0BCA ; ; ;this routine resets the bit whose number is in A' ; M0B95: EX AF,AF' ; LD B,(HL) ; CP $01 ;/ JR NZ,M0B9F ;|if 1, reset bit 1 in B RES 1,B ;| then move on JR M0BC9 ;\ M0B9F: CP $02 ;/ JR NZ,M0BA7 ;|if 2, reset bit 2 in B RES 2,B ;| then move on JR M0BC9 ;\ M0BA7: CP $03 ;/ JR NZ,M0BAF ;|if 3, reset bit 3 in B RES 3,B ;| then move on JR M0BC9 ;\ M0BAF: CP $04 ;/ JR NZ,M0BB7 ;|if 4, reset bit 4 in B RES 4,B ;| then move on JR M0BC9 ;\ M0BB7: CP $05 ;/ JR NZ,M0BBF ;|if 5, reset bit 5 in B RES 5,B ;| then move on JR M0BC9 ;\ M0BBF: CP $06 ;/ JR NZ,M0BC7 ;|if 6, reset bit 6 in B RES 6,B ;| then move on JR M0BC9 ;\ M0BC7: RES 7,B ;else reset bit 7 M0BC9: LD (HL),B ;save byte back M0BCA: INC A ; CP $08 ; JP NZ,M0AF9 ; RET ; ; ;find all used banks in the machine ; M0BD1: LD A,(MAXBNK) ;get MAXBANK INC A ;bump it LD (MAXBNK),A ;save new MAXBANK LD ($6315),A ;save dispatcher's ; local copy of MAXBANK LD D,$A0 ;/ LD E,A ;|write to bank status register CALL $5200+WRITE_BS_REG ;\ ; ;check expansion banks? ; LD D,$80 ;/ LD E,A ;|write to bank status register CALL $5200+WRITE_BS_REG ;\ LD D,$40 ;/ LD E,$00 ;|write to bank status register CALL $5200+WRITE_BS_REG ;\ PUSH AF ;save AF briefly LD A,($A000) ;/save value at $A0000 EX AF,AF' ;\ LD A,$04 ;/store 4 into chunk 5 BSR LD ($A000),A ;\ LD D,$A0 ;/ LD E,$C0 ;|read bank status register CALL $5200+READ_BS_REG ;\ BIT 2,E ;/jump if 4 was successfully written JR NZ,M0C0A ;(0C0A);\ EX AF,AF' ;/restore the value at $A000 LD ($A000),A ;\ POP AF ;restore AF SCF ;set error flag RET ;done M0C0A: EX AF,AF' ;/restore the value at $A000 LD ($A000),A ;\ POP AF ;restore A DEC A ; LD (MAXBNK),A ;save new MAXBANK LD ($6315),A ;save dispatcher's ; local copy of MAXBANK LD D,$C0 ;/ LD E,$04 ;|write to bank status register CALL $5200+WRITE_BS_REG ;\ AND A ; RET ; M0C1F: DEC HL ; LD (HL),$01 ; LD DE,$0015 ; ADD HL,DE ; LD A,(HL) ; RRA ; JR C,M0C2F ;(0C2F) ; LD DE,$0004 ; ADD HL,DE ; RET ; M0C2F: LD C,$08 ; LD A,(MAXBNK) ; DEC HL ; DEC HL ; DEC HL ; LD D,(HL) ; DEC HL ; LD E,(HL) ; LD H,D ; LD L,E ; LD B,A ; PUSH HL ; PUSH BC ; LD BC,$0000 ; PUSH BC ; PUSH BC ; CALL $5200+CALL_BANK ; LD DE,$0008 ; ADD HL,DE ; RET ; ;****************************************************************** ; Module: INIT ; Routine: RESSCT ;****************************************************************** XOR A LD (MAXBNK),A LD ($6315),A LD D,$C0 LD E,$00 CALL $5200+WRITE_BS_REG LD HL,(SYSCON) LD DE,$000C M0C60: ADD HL,DE CALL M0BD1 JP NC,M0CF5 LD A,(HL) PUSH HL CP $80 JR NZ,M0C72 ;(0C72) LD DE,$0018 ADD HL,DE LD (HL),A M0C72: CALL M0BD1 LD HL,$5FE9 LD E,$FF LD D,A PUSH DE LD DE,$0000 PUSH DE PUSH HL LD DE,$0016 PUSH DE LD DE,$0001 PUSH DE CALL $5200+XFER_BYTES EX AF,AF' LD A,(HL) CPL DEC HL LD (HL),A EX AF,AF' LD D,$FF LD E,A PUSH DE PUSH HL LD DE,$0002 PUSH DE LD DE,$0001 PUSH DE PUSH DE CALL $5200+XFER_BYTES LD E,$FF LD D,A PUSH DE LD DE,$0002 PUSH DE INC HL PUSH HL LD DE,$0001 PUSH DE PUSH DE CALL $5200+XFER_BYTES LD A,(HL) DEC HL LD B,(HL) CP B JR NZ,M0CCA ;(0CCA) POP HL LD A,(HL) CP $02 JR NZ,M0CC5 ;(0CC5) INC HL INC HL JR M0CE8 ;(0CE8) M0CC5: CALL M0ADB JR M0CE8 ;(0CE8) M0CCA: LD C,(HL) POP HL INC HL INC HL LD A,(HL) CP C JR Z,M0CE8 ;(0CE8) PUSH HL EX DE,HL LD HL,$5FE9 LD BC,$0016 LDIR POP HL DEC HL LD A,(MAXBNK) SET 7,A LD (HL),A CALL M0C1F INC HL M0CE8: LD D,$C0 LD E,$01 CALL $5200+WRITE_BS_REG LD DE,$0016 JP M0C60 M0CF5: LD (HL),$80 CALL M0CFB RET M0CFB: XOR A ;/load 0 into MAXBANK LD (MAXBNK),A ;\ M0CFF: LD HL,(SYSCON) ;get SYSCON buffer address LD DE,$000C ; ADD HL,DE ; M0D06: LD A,(HL) ; CP $80 ; JR Z,M0D84 ;(0D84) INC HL LD A,(HL) BIT 7,A JR NZ,M0D17 ;(0D17) LD DE,$0017 ADD HL,DE JR M0D06 ;(0D06) M0D17: LD ($5FE9),HL DEC HL LD A,(HL) CP $02 JR NZ,M0D28 ;(0D28) LD DE,$0017 ADD HL,DE LD A,$FF JR M0D2D ;(0D2D) M0D28: LD DE,$0017 ADD HL,DE LD A,(HL) M0D2D: LD ($5FEB),A M0D30: INC HL M0D31: LD A,(HL) CP $80 JR Z,M0D64 ;(0D64) INC HL LD A,(HL) BIT 7,A JR NZ,M0D42 ;(0D42) LD DE,$0017 ADD HL,DE JR M0D30 ;(0D30) M0D42: DEC HL LD A,(HL) CP $02 JR NZ,M0D4E ;(0D4E) LD DE,$0017 ADD HL,DE JR M0D30 ;(0D30) M0D4E: EX DE,HL LD BC,$0017 ADD HL,BC LD A,($5FEB) LD B,A LD A,(HL) CP B JR NC,M0D30 ;(0D30) LD ($5FEB),A LD ($5FE9),DE JR M0D30 ;(0D30) M0D64: LD A,(MAXBNK) INC A LD (MAXBNK),A LD HL,($5FE9) LD (HL),A LD E,$FF LD D,A PUSH DE LD E,(HL) LD D,$00 PUSH DE LD E,$00 PUSH DE LD E,$01 PUSH DE PUSH DE CALL $5200+XFER_BYTES JP M0CFF M0D84: XOR A LD (MAXBNK),A LD ($6315),A LD D,$C0 LD E,$00 CALL $5200+WRITE_BS_REG LD HL,(SYSCON) LD DE,$000D ADD HL,DE LD D,$A0 M0D9B: CALL M0BD1 RET NC LD E,(HL) CALL $5200+WRITE_BS_REG LD D,$C0 LD E,$01 CALL $5200+WRITE_BS_REG LD DE,$0018 ADD HL,DE JR M0D9B ;(0D9B) ;****************************************************************** ; Module: CHG_VID ; Routine: OPDFIL ; open the second display file. move the UDG then move the stack ; and RAM resident code to high memory. update the video mode and ; the video port. ;****************************************************************** OPDFIL: M0DB0: PUSH BC ;/ PUSH DE ;|save caller's PUSH HL ;|registers PUSH AF ;\ LD HL,(PRAMT) ;get physical ramtop LD DE,(UDG) ;get the pointer to the UDG AND A ;/number of bytes occupied by SBC HL,DE ;\the UDG LD B,H ;/put into byte counter LD C,L ;\ INC BC ;adjust for zero base LD HL,(UDG) ;point to the present UDG PUSH HL ;brefly save LD DE,$0840 ;number of bytes needed by ; RAM resident routines and ; stack AND A ;/compute the new address SBC HL,DE ;| for the UDG EX DE,HL ;\ POP HL ;restore the present UDG address LD (UDG),DE ;point to the new UDG location LDIR ;move the UDG LD HL,$0000 ;/HL will contain the new ADD HL,SP ;|SP used when the stack and LD BC,$97C0 ;|RAM resident code are moved ADD HL,BC ;\ DI ;interrupts now will be really, ; really bad! LD SP,HL ;update the stack pointer LD DE,$F7C0 ;new location for stack and RAM routines LD HL,$6000 ;old location LD BC,$0840 ;length of stuff to move LDIR ;move it LD HL,$1D00 ;point to the fix table LD BC,$97C0 ;offset to be added to addresses M0DEE: LD E,(HL) ;/ INC HL ;|get fix address LD D,(HL) ;\ INC HL ;point to next entry LD A,E ;/jump if we have reached the end OR D ;|of the table JR Z,M0E05 ;\ EX DE,HL ;/point to moved code that ADD HL,BC ;\needs fixing PUSH DE ;save the table pointer LD E,(HL) ;/ INC HL ;|get the code needing fixing LD D,(HL) ;\ EX DE,HL ;/ ADD HL,BC ;| EX DE,HL ;|fix the address and LD (HL),D ;|put it back DEC HL ;| LD (HL),E ;\ POP HL ;restore the table pointer JR M0DEE ;back around for more entries M0E05: POP AF ;/get caller's desired video mode LD (VIDMOD),A ;\and store it PUSH AF ;save it again EI ;interrupts are OK again ;clear the newly opend second display file LD HL,$6000 ;point to the second display file M0E0E: XOR A ;zero the accum LD (HL),A ;zero a byte INC HL ;point to the next LD A,H ;/zero until we reach $7AFF CP $7B ;\ JR NZ,M0E0E ;not done yet POP AF ;get the requested video mode PUSH AF ;save it again AND $7F ;only use the lower seven bits ; (don't munge the EXROM select) LD B,A ;save it in B IN A,($FF) ;get the present value of the ; video select port AND $80 ;save the EXROM select OR B ;OR in the request OUT ($FF),A ;update the port POP HL ;/ POP DE ;|restore caller's POP BC ;|registers POP AF ;\ RET ; ;****************************************************************** ; Module: CHG_VID ; Routine: CLDFIL ; close the second display file ; moves the stack and RAM resident code from high memory back to ; low memory. updates SP and relocates the UDG. ;****************************************************************** CLDFIL: M0E27: PUSH AF ;/ PUSH BC ;|save caller's registers PUSH DE ;| PUSH HL ;\ IN A,($FF) ;/get display mode port value AND $80 ;|and set for black and white, OUT ($FF),A ;\normal video,EXROM selected LD HL,$0000 ;/ ADD HL,SP ;|set HL to the value the LD DE,$97C0 ;|SP will need once the stack AND A ;|has been moved to low memory SBC HL,DE ;\ DI ;we can't be interruped or we ; will be in a real mess! LD SP,HL ;update the stack pointer LD HL,$FFFF ;/move the RAM resident code LD DE,$683F ;|and the stack back to low LD BC,$0840 ;|memory (starting at $6000) LDDR ;\ LD HL,$1D00 ;the location of the fix table LD BC,$97C0 ;offset value to convert code addresses ; from high memory addresses to ; low memory addresses M0E4E: LD E,(HL) ;/ INC HL ;|get a fix address LD D,(HL) ;\ INC HL ;point to the next one LD A,E ;/ OR D ;|jump if the end of the table JR Z,M0E66 ;\ PUSH HL ;save the table pointer EX DE,HL ;/ LD E,(HL) ;|get the JP/CALL address INC HL ;|in the RAM resident code LD D,(HL) ;\ EX DE,HL ;/convert the address from AND A ;|high memory to low memory SBC HL,BC ;\ EX DE,HL ;/ LD (HL),D ;|modify the code DEC HL ;| LD (HL),E ;\ POP HL ;restore the table pointer JR M0E4E ;back around for more entries M0E66: XOR A ;/force normal video mode LD (VIDMOD),A ;\ EI ;we can now allow interrupts again LD HL,$F7BF ;address of UDG end when code is in ; high memory LD DE,$FFFF ;new UDG location PUSH HL ;save the old UDG address LD BC,(UDG) ;get the current UDG pointer AND A ;/number of bytes to move SBC HL,BC ;\ LD B,H ;/transfer to byte counter LD C,L ;\ INC BC ;bump by one POP HL ;restore old address LDDR ;move the UDG LD DE,$0840 ;/ LD HL,(UDG) ;|update the UDG pointer ADD HL,DE ;|in the system variables LD (UDG),HL ;\ POP HL ;/ POP DE ;|restore the caller's POP BC ;|registers POP AF ;\ RET ; ;****************************************************************** ; Module: CHG_VID ; Routine: CHG_V ; change the 2068 video mode ; Entry: requested video mode in A ;****************************************************************** CHG_V: PUSH BC ;/ PUSH DE ;|save caller's registers PUSH HL ;| PUSH AF ;\ LD B,A ;save requester's mode LD A,(VIDMOD) ;/jump if present mode is NOT AND A ;|zero JR NZ,M0EED ;\ OR B ;/jump if mode '0' is requested JP Z ,M0F3D ;|and current mode is '0'. exit video mode change ;\with out doing anything ;intitiate a change from mode '0' to some other mode LD HL,$12C0 ;number of bytes needed for RAM services LD B,H ;/save for REMGSZ later on, if needed LD C,L ;\ LD DE,$0840 ;/$2B00 total bytes needed ADD HL,DE ;\ LD DE,(STKEND) ;/add to free RAM space stored in ADD HL,DE ;\STKEND ;possible error in memory check. the technical manual mentions that ; overflow is not checked LD DE,(RAMTOP) ;/ AND A ;|if the carry is set, RAMTOP is set SBC HL,DE ;\too low to allow moving the RAM services JP NC,M0F3A ;error exit ;adjust system variable address pointers LD HL,$683F ;fence value: all system variables ; that point above this will be ; changed. ; (BC was set up earlier to $12C0) LD DE,REMGSZ ;/address for REMGSZ PUSH DE ;\ LD DE,$FF00 ;/specify home bank, all chunks PUSH DE ;\ in home LD DE,$0000 ;/ PUSH DE ;|no parameters in or out PUSH DE ;\ CALL $5200+CALL_BANK ;CALL_BANK (REMGSZ) LD HL,(STKEND) ;/ EX DE,HL ;|move the fp stack LDDR ;\ POP AF ;/restore caller's video mode PUSH AF ;\ CALL OPDFIL ;open the second display file LD BC,$97C0 ;/ LD HL,(ERRSP) ;|point the ERRSP to the newly moved ADD HL,BC ;|stack LD (ERRSP),HL ;\ LD HL,(LISTSP) ;/ ADD HL,BC ;|update list stack pointer LD (LISTSP),HL ;\ LD HL,(MSTBOT) ;/ ADD HL,BC ;|update machine stack pointer LD (MSTBOT),HL ;\ JR M0F3D ;jump to exit M0EED: LD A,B ;/jump if requested mode is AND A ;|'0' (move the stack and JR Z,M0F01 ;\RAM resident code back down) ;the requested mode was NOT zero and the present mode is not zero, so ; simply update the necessary items, then exit AND $7F ;don't allow changes to the EXROM ; select LD B,A ;briefly save IN A,($FF) ;get the present video control port ; value AND $80 ;save the EXROM select OR B ;/OR in the requested mode OUT ($FF),A ;\ and output to the port LD A,B ;/save the requested mode to LD (VIDMOD),A ;\VIDMOD JR M0F3D ;we are outta here ;the present mode is not zero and the requested mode is zero, so ; prepare to move everything back around as needed M0F01: CALL CLDFIL ;close the display file LD BC,$97C0 ;/ LD HL,(ERRSP) ;|update ERRSP to new AND A ;|stack location SBC HL,BC ;| LD (ERRSP),HL ;\ LD HL,(LISTSP) ;/ AND A ;|do the same for the SBC HL,BC ;|LISTSP LD (LISTSP),HL ;\ LD HL,(MSTBOT) ;/ AND A ;|yet again for MSTBOT SBC HL,BC ;| LD (MSTBOT),HL ;\ LD BC,$12C0 ;number of bytes to delete LD HL,$6840 ;start address LD DE,DELREC ;/delete the bytes PUSH DE ;\ LD DE,$FF00 ;/HOME bank, all PUSH DE ;\ chunks LD DE,$0000 ;/ PUSH DE ;|no params in or out PUSH DE ;\ CALL $5200+CALL_BANK ; JR M0F3D ;we are done M0F3A: SCF ;/set carry flag (indicates error) JR M0F3E ;\and exit M0F3D: AND A ;reset carry flag (all's OK) M0F3E: POP AF ;/ POP HL ;|restore caller's registers POP DE ;| POP BC ;\ RET ; ;****************************************************************** ; Module: PASSING ; Routine: PASSIN ;****************************************************************** PASSIN: LD BC,(CHADD) ;I don't have a clue what this is trying to do. $255D in the home ; bank is the last byte of a CALL $65D0 ($65) and then presses on ; to call END? at $1B44 that lands us on a RST $38 that calls ; the RAM interrupt service CALL M255D LD HL,(CHADD) AND A SBC HL,BC DEC HL LD A,L LD HL,(STKEND) LD (HL),A INC HL POP BC LD (HL),B INC HL LD (HL),C INC HL LD (STKEND),HL LD HL,(CHADD) DEC HL BIT 0,A JR Z,M0F73 ; M0F67: DEC A LD B,(HL) DEC HL DEC A JP M ,M0F7D LD C,(HL) DEC HL PUSH BC JR M0F67 ;(0F67) M0F73: LD B,$20 AND A RET Z LD C,(HL) DEC HL DEC A PUSH BC JR M0F67 ;(0F67) M0F7D: LD HL,(STKEND) DEC HL LD A,(HL) DEC HL LD (STKEND),HL LD H,(HL) LD L,A PUSH HL RET ;****************************************************************** ; Module: BS ; Routine: GOTO_B ;****************************************************************** GOTO_B: M0F8A: PUSH AF ;/determine where the function LD A,(VIDMOD) ;| dispatcher is located AND A ;\ JR Z,M0F95 ;jump to normal fn dispatch POP AF ;restore AF JP MFD32 ;jump to high fn dispatch M0F95: POP AF ;restore AF JP $5200+GOTO_BANK ; ;****************************************************************** ; Module: BS ; Routine: CALL_B ;****************************************************************** CALL_B: M0F99: PUSH AF ;save AF LD A,(VIDMOD) ;/check VIDMOD AND A ;\ JR Z,M0FA4 ;jump if non-expanded video mode POP AF ;restor AF JP MFD90 ;jump to expanded video mode function dispatcher M0FA4: POP AF ;restore AF JP $5200+CALL_BANK ;jump to normal function dispatcher DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFC STKSZ = $200 DEFC SADDPT = $F5 DEFC SDATPT = $F6 DEFC HS = $40 DEFC HS_LSN = HS DEFC BNA = $80 DEFC HS_MSN = BNA DEFC ABN = $A0 DEFC HSP = ABN DEFC STA_L = ABN DEFC CMD = $C0 DEFC STA_O = CMD DEFC LOWNYB = $C000 DEFC FREE_BYTES = 32 DEFC PRMOUT = 8 DEFC HOR_SEL = 10 DEFC BANK = 11 DEFC UPD_K = $02E1 DEFC DKHSPT = $F4 DEFC HREXPT = $FF DEFC PRM_OUT = 8 ; DISPATCH (SVC_CODE: PASSED ON STACK) ; ; SVC_CODE IS A 16 BIT QUANTITY. BIT 15 IS USED AS A JUMP FLAG: IF ; SET, THE DISPATCHER WILL TO A GOTO_BANK TO THE SPECIFIED ROUTINE, ; OTHERWISE IT WILL DO A CALL_BANK. ; ; DEFC JMPTBL = $1FFF DEFC LAST_EXT_SVC = 13 DEFC LAST_RAM_SVC = 24 ; ; ; ORG $6200 ORG $1000 DEFC DISPATCH = $6200 LD IX,0 ;IX = SP ADD IX,SP ; PUSH BC ;RESERVE A WORD ON THE STACK PUSH AF ;SAVE REGS PUSH BC PUSH DE PUSH HL LD E,(IX+2) LD D,(IX+3) ;DE = SVC_CODE XOR A SLA E RL D ;DE = 2*DE RLA LD HL,LAST_EXT_SVC SLA L RL H ;HL = 2*HL AND A SBC HL,DE ;COMPARE HL AND DE JR NC,D_EXT ;IF DE <= HL LD HL,LAST_RAM_SVC SLA L RL H AND A SBC HL,DE JR C,D_HOME LD B,255 ;HERE FOR RAM-BASED SERVICES CALL $5200+GET_STATUS ;GET STATUS OF HOME BANK LD B,255 ;BC=HOME BANK/HORIZ SELECT JR D_SAVE D_EXT: LD B,254 ;HER FOR EXT ROM BASE SERVICES LD C,$FE JR D_SAVE D_HOME: LD B,255 ;SET BANK_ENABLE PARAMS FOR HOME LD C,0 D_SAVE: PUSH AF PUSH BC ;SAVE JUMP FLAG AND BANK_ENABLE PARAMS LD HL,JMPTBL ;CALC ADR OF TABLE ENTRY SCF SBC HL,DE LD B,254 CALL $5200+GET_WORD ;READ TABLE ENTRY EX DE,HL POP BC POP AF ;RESTORE JUMP FLAG ETC AND A JR Z,D_CALL LD (IX+(-2)),C ;PUT BANK AND HORZ SEL ON STACK LD (IX+(-1)),B LD L,(IX+0) ;SAVE RET ADDR LD H,(IX+1) LD (IX+3),H ;PUT RET ADDR BACK ON STACK LD (IX+2),L LD (IX+1),D ;SET UP STACK FOR GOTO_BANK LD (IX+0),E ;PUT ADDR ON STACK POP HL ;RESTORE REGS POP DE POP BC POP AF CALL $5200+GOTO_BANK ;HERE IF JUMP FLAG NOT SET D_CALL: LD L,(IX+0) ;SET UP STACK FOR CALL_BANK LD H,(IX+1) ;PUT RET ADDR IN PROPER LOC PUSH HL LD L,(IX+4) LD H,(IX+5) LD (IX+(-2)),L LD (IX+(-1)),H LD L,(IX+6) ;PUT PARM_OUT IN PROPER LOC LD H,(IX+7) LD (IX+0),L LD (IX+1),H LD (IX+2),C ;PUT BANK#, HS ON STACK LD (IX+3),B LD (IX+4),E ;PUT ADDR ON STACK LD (IX+5),D POP HL LD (IX+6),L LD (IX+7),H POP HL ;RESTORE REGS POP DE POP BC POP AF CALL $5200+CALL_BANK ;HERE IF JUMP FLAG NOT SET RET ;RST 56: HERE TO SERVICE INTERRUPT BY READING KEYBOARD INT: PUSH AF PUSH HL PUSH IX LD HL,0 ADD HL,SP PUSH DE LD A,(BS_MAX_BANK) LD E,A LD D,0 INC DE INC DE AND A SBC HL,DE EX DE,HL LD IX,0 ADD IX,DE POP DE LD SP,IX CALL $5200+SAVE_STATUS PUSH BC LD B,$FF CALL $5200+GET_STATUS LD B,$FF LD A,C AND $F8 LD C,A CALL BANK_ENABLE ;AAA POP BC LD HL,(FRAMES) ;INCREMENT FRAMES COUNTER INC HL LD (FRAMES),HL LD A,H OR L JR NZ,LIT3 INC (IY+(FRAMES2-Y)) ; LIT3: PUSH BC PUSH DE CALL UPD_K POP DE POP BC PHLAF: ;JUMP HERE TO POP HL, POP AF, ENABLE INTERRUPTS AND RETURN LD IX,0 ADD IX,SP CALL $5200+RESTORE_STATUS INC IX LD SP,IX POP IX POP HL POP AF EI RET ;HERE TO SERVICE THE NON-MASKABLE INTERRUPT ;IF (NMIADD)=0 THEN RETURNS STRAIGHT AWAY; ;ELSE, JUMPS TO (NMIADD) WHIT HL (ON TOP) , AF & RETN ADDR ON ;THE STACK NMI: PUSH AF PUSH HL LD HL,(USRNMI) LD A,H OR L JR NZ,LNI3 JP (HL) LNI3: POP HL POP AF RETN ; ; DEFC BS_MAX = $5200+ASMPC DEFC BS_MAX_BANK = BS_MAX DEFB $FF ;LOCAL COPY OF MAX_BANK ; ; GET_WORD (ADDR: HL, BANK: B, WORD: HL) ; GET_WORD: PUSH AF ;SAVE REGS PUSH BC PUSH DE CALL $5200+GET_NUMBER ;GET BANK# OF OWNER OF ADDR PUSH AF LD D,B LD B,A CALL $5200+GET_STATUS ;GET STATUS OF OWNER PUSH BC CALL $5200+GET_CHUNK ;SET HS FOR GETTING AT ADDR CPL ;PUT IN ACTIVE LOW FORMAT LD B,D LD C,A CALL BANK_ENABLE ;ENABLE ADDR LD E,(HL) ;WRITE THE WORD INC HL LD D,(HL) DEC HL EX DE,HL POP BC POP AF LD B,A CALL BANK_ENABLE ;REENABLE OWNER OF ADDR POP DE POP BC POP AF RET ; ; PUT_WORD (WORD: DE, ADDR: HL, BANK: B) ; PUT_WORD: PUSH AF PUSH BC CALL $5200+GET_NUMBER PUSH AF LD D,B LD B,A CALL $5200+GET_STATUS PUSH BC CALL $5200+GET_CHUNK CPL LD B,D LD C,A CALL BANK_ENABLE ;BBB LD (HL),E INC HL LD (HL),D DEC HL POP BC POP AF CALL BANK_ENABLE ;CCC POP BC POP AF RET ; ; WRITE_BS_REG (REG_ADDR: D, REG_DATA: E) ; WRITE_BS_REG: PUSH AF ;SAVE REGS PUSH BC PUSH HL LD H,D LD L,0 ;HL = MEMORY MAPPED ADR LD A,(LOWNYB) ;SAVE ($E000) PUSH AF LD A,(HL) ;SAVE (HL) PUSH AF LD A,7 OUT (SADDPT),A ;SAVE VALUES OF SOUND REGS $07 AND $0E IN A,(SDATPT) LD B,A LD A,$0E OUT (SADDPT),A IN A,(SDATPT) LD C,A LD A,7 ;SET IOA CHANNEL TO OUTPUT OUT (SADDPT),A LD A,$40 OUT (SDATPT),A LD A,$0E OUT (SADDPT),A XOR A OUT (SDATPT),A LD A,2 LD (LOWNYB),A ;RESET NYBBLE STEERING LOGIC LD A,E LD (HL),A ;WRITE LSN OF DATA SRA A SRA A SRA A SRA A LD (HL),A ;WRITE MSN OF DATA LD A,7 ;RESTORE SOUND REGS OUT (SADDPT),A LD A,B OUT (SDATPT),A LD A,$0E OUT (SADDPT),A LD A,C OUT (SDATPT),A POP AF LD (HL),A ;RESTORE (HL) POP AF LD (LOWNYB),A ;RESTORE ($E000) POP HL ;RESTORE REGS POP BC POP AF RET ; ; READ_BS_REG (LSN_ADDR: D, MSN_ADDR: E, BYTE_DATA: C) ; READ_BS_REG: PUSH AF ;SAVE REGS PUSH BC PUSH HL LD H,D LD L,0 ;HL=MEMORY MAPPED ADDR LD A,(LOWNYB) ;SAVE ($E000) PUSH AF LD A,(HL) ;SAVE (HL) PUSH AF LD A,7 OUT (SADDPT),A ;SAVE VALUES OF SOUND REGS $07 AND $0E IN A,(SDATPT) LD B,A LD A,$0E OUT (SADDPT),A IN A,(SDATPT) LD C,A PUSH BC LD A,7 ;SET IOA CHANNEL TO OUTPUT OUT (SADDPT),A LD A,$40 OUT (SDATPT),A LD A,$0E OUT (SADDPT),A XOR A OUT (SDATPT),A LD A,2 LD (LOWNYB),A ;RESET NYBBLE STEERING LOGIC LD A,(HL) ;READ LSN OF DATA AND $0F LD C,A LD H,E LD A,(HL) ;READ MSN OF DATA SLA A SLA A SLA A SLA A OR C LD E,A ;RETURN BYTE DATA IN E POP BC ;POP SAVED SOUND REG DATA LD A,7 ;RESTORE SOUND REGS OUT (SADDPT),A LD A,B OUT (SDATPT),A LD A,$0E OUT (SADDPT),A LD A,C OUT (SDATPT),A POP AF LD (HL),A ;RESTORE (HL) POP AF LD (LOWNYB),A ;RESTORE ($E000) POP HL ;RESTORE REGS POP BC POP AF RET ; ; GET_BANK_STATUS (BANK: B, STATUS: B, HORIZONTAL_SELECT: C) ; GET_STATUS: PUSH AF ;SAVE REGS PUSH DE LD A,B CP $FE JR Z,GS_EXT ;IF BANK=254 CP $FF JR Z,GS_HOME ;IF BANK=255 AND A JR Z,GS_DOCK ;IF BANK=0 LD D,BNA ;HERE IF EXP BANK LD E,B CALL $5200+WRITE_BS_REG LD D,HS_LSN LD E,HS_MSN CALL $5200+READ_BS_REG ;READ HS LD A,E CPL LD C,A LD D,STA_L LD E,STA_O CALL $5200+READ_BS_REG ;READ STATUS NYBBLES LD B,E JR GS_EXIT GS_HOME: LD BC,0 ;RETURN 0 FOR HOME BANK STATUS JR GS_EXIT GS_DOCK: IN A,(DKHSPT) ;RETURN DOCK BANK STATUS) CPL LD B,A LD C,0 JR GS_EXIT GS_EXT: IN A,(HREXPT) AND $80 ;CLEAR ALL BITS BUT BIT 7 CPL RLCA ;PUT ACTIVE BIT IN BIT ZERO LD B,A IN A,(DKHSPT) CPL AND 1 OR B LD B,A LD C,0 GS_EXIT: POP DE ;RESTORE REGISTERS POP AF RET ; ; GET_CHUNK (ADDR: HL, MASK: A) ; GET_CHUNK: PUSH BC ;SAVE B LD A,H ;CHUNK NUMBER=HIGH 3 BITS OF LD B,5 ; H SO SHIFT RIGHT 3 BITS GC_SHIFT: SRL A DJNZ GC_SHIFT INC A ;CREATE MASK BY ROLLING A 1 LD B,A ; LEFT CHUNK NUMBER+1 TIMES XOR A ; THE FLAG COMES FROM THE CARRY SCF GC_ROLL: RLA DJNZ GC_ROLL POP BC ;RESTORE B RET ; ;GET_BANK_NUMBER (ADDR: HL, BANK_NUMBER: A) ; GET_NUMBER: PUSH BC ;SAVE REGS PUSH DE CALL $5200+GET_CHUNK LD C,A LD A,(BS_MAX_BANK) ;GET LARGEST BANK NUMBER AND A JR Z,GN_RD_DOCK ;IF NO EXP BANKS LD B,A GN_CHECK: LD E,B ;SEARCH ALL EXP BANKS CALL $5200+GET_STATUS AND C JR Z,GN_EXP ;FOUND THE CHUNK, SO EXIT THE LOOP DJNZ GN_CHECK GN_RD_DOCK: IN A,(DKHSPT) ;NOT IN EXP BANKS SO CHECK DOCK CPL AND C JR Z,GN_DOCK DEC C ;IF CHUNK>1, THEN CAN'T BE IN EXT JR NZ,GN_HOME IN A,(HREXPT) ;CHECK IF IN EXT BANK AND $80 LD D,A IN A,(DKHSPT) AND 1 RRCA AND D JR Z,GN_HOME ;NOT IN EXT BANK LD A,$FE ;IN EXT BANK SO RETURN 254 JR GN_EXIT GN_HOME: LD A,$FF ;IN HOME BANK, SO RETURN 255 JR GN_EXIT GN_DOCK: XOR A ;FOUND IN DOCK SO RETURN 0 JR GN_EXIT GN_EXP: LD A,B ;RETURN EXP BANK NUMBER GN_EXIT: POP DE ;RESTORE REGS POP BC RET ; ;BANK_ENBALE (BANK: B, HORIZONTAL_SELECT: C) ; X_BANK_ENABLE: PUSH AF ;/SAVE REGS PUSH BC ;| PUSH DE ;| PUSH HL ;\ LD H,B ;bank to H LD A,(BS_MAX_BANK) ;GET LARGEST BANK NUMBER AND A ; JR Z,BE_SKIP ;IF NO EXP BANKS LD D,BNA ; LD E,0 ; CALL $5200+WRITE_BS_REG ; LD D,HSP ; PUSH AF ; LD A,C ; CPL ; LD E,A ; POP AF ; CALL $5200+WRITE_BS_REG ;TURN OFF APPROPRIATE BITS OF ; ALL EXP BANKS BE_SKIP: LD A,B AND A JR NZ,BE_NTDOCK LD A,C CP $FF JR Z,BE_EXT_OK IN A,(HREXPT) ;HERE FOR DOCK RES 7,A OUT (HREXPT),A BE_EXT_OK: LD A,C CPL OUT (DKHSPT),A ;ENABLE DOCK JR BE_EXIT BE_NTDOCK: LD A,B ;CHECK IF EXT CP $FE JR NZ,BE_NTEXT IN A,(HREXPT) ;HERE FOR EXT RLA RR C CCF RRA OUT (HREXPT),A BIT 7,A JR NZ,BE_SET IN A,(DKHSPT) RES 0,A OUT (DKHSPT),A JR BE_EXIT BE_SET: IN A,(DKHSPT) SET 0,A OUT (DKHSPT),A JR BE_EXIT BE_NTEXT: IN A,(DKHSPT) ;DISABLE DOCK CPL LD E,A LD A,C CPL OR E CPL OUT (DKHSPT),A BIT 0,C JR NZ,BE_CHK_HOME IN A,(HREXPT) ;DISABLE EXT RES 7,A OUT (HREXPT),A IN A,(DKHSPT) RES 0,A OUT (DKHSPT),A BE_CHK_HOME: LD A,B ;CHECK IF HOME CP $FF JR Z,BE_EXIT ;IS HOME, SO DONE LD D,BNA ;WRITE NEW EXP BANK STATUS LD E,B CALL $5200+WRITE_BS_REG LD D,HS LD A,C CPL LD E,A CALL $5200+WRITE_BS_REG BE_EXIT: POP HL ;RESTORE REGS POP DE POP BC POP AF RET ; ; SAVE_BANK_STATUSES (STATUS_ADR: IX) ; PUSHES THE STATUS OF ALL BANKS ONTO THE STACK (IX) ; SAVE_STATUS: PUSH AF ;SAVE REGS PUSH BC PUSH DE IN A,(HREXPT) ;SAVE EXT BANK STATUS NOP ; LEAVE BITS 0-6 ALONE. NOPS PUT IN NOP ; TO KEEP ADDRS THE SAME LD (IX+0),A INC IX IN A,(DKHSPT) ;GET DOCK BANK STATUS LD (IX+0),A INC IX LD A,(BS_MAX_BANK) ;GET NUMBER OF BANKS AND A JR Z,SS_EXIT LD B,A ;SET UP BANK COUNTER SS_LOOP: LD E,B ;BANK NUMBER INTO E CALL $5200+GET_STATUS ;GET STATUS OF BANK IN b LD (IX+0),C INC IX LD B,E DJNZ SS_LOOP ;AROUND FOR ALL SS_EXIT: DEC IX POP DE ;RESTORE REGS POP BC POP AF RET ; ; RESTORE_BANK_STATUSES (STATUS_ADR: IX) ; RESTORES THE STATUS OF ALL BANKS FROM THE STACK (IX) ; RESTORE_STATUS: PUSH AF ;SAVE REGS PUSH BC PUSH DE LD A,(IX+0) ;GET EXT ROM STATUS OUT (HREXPT),A INC IX LD A,(IX+0) ;GET DOCK BANK STATUS OUT (DKHSPT),A INC IX LD A,(BS_MAX_BANK) ;GET NUMBER OF BANKS AND A JR Z,RS_EXIT LD B,A ;SET UP BANK COUNTER RS_LOOP: LD C,(IX+0) CALL BANK_ENABLE ;WRITE BANK STATUS OF BANK IN B INC IX DJNZ RS_LOOP RS_EXIT: DEC IX POP DE POP BC POP AF RET ; ; GOTO_BANK (BANK, HORIZONTAL_SELECT, ADDR: PASSED ON STACK) ; SETS UP THE DESTINATION BANK AND JUMPS WITHOUT RETURN ADDRESS ; IN BANK ; GOTO_BANK: LD IX,0 ;SET IX TO SP ADD IX,SP LD (IX+0),C ;SAVE BC AND TRASH CALLER'S RETURN ADDRESS LD (IX+1),B LD C,(IX+2) ;SET PARAMS FOR BANK_ENABLE LD B,(IX+3) CALL BANK_ENABLE ;DDD POP BC ;RESTORE BC POP IX ;TRASH PARAMS TO GOTO_BANK POP IX ;GET ADDR JPIX: JP (IX) ; ; CALL_BANK (ADDR, BANK, HORIZONTAL_SELECT, PRM_OUT, PRM_IN) ; ALL INPUT PARAMETERS ARE PUSHED ON THE STACK ; ; CLOBBERS IX ; ; SETS UP THE BANK AND MAKES A JUMP WITH RETURN ADDRESS TO ; ADDRESS IN BANK DEFC BS_STACK = $6200+ASMPC-$1000 DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFC BS_SP = $5200+ASMPC DEFW $FFFF CALL_BANK: EX (SP),HL ;GET RET ADDR LD IX,(BS_SP) DEC IX LD (IX+0),H DEC IX LD (IX+0),L ;PUSH HL ON BS_STACK POP HL EX (SP),HL ;GET PARAM_IN DEC IX LD (IX+0),H DEC IX LD (IX+0),L LD (BS_SP),IX PUSH DE PUSH BC PUSH AF LD HL,0 ADD HL,SP ;HL = SP LD D,H LD E,L LD A,(BS_MAX_BANK) LD C,A LD B,0 INC BC INC BC ;BC = MAX_BANK+2 AND A SBC HL,BC LD SP,HL LD IX,0 ADD IX,DE EX DE,HL ;DE, HL NOW CONTAIN DEST, SRC ; POINTERS FOR A BLOCK MOVE LD C,(IX+PRM_OUT) LD B,(IX+PRM_OUT) LD A,14 ADD A,C LD C,A JR NC,CB_NC1 ;BC = PRM_OUT + 14 INC B CB_NC1: LDIR ;MAKE ROOM FOR BANK STATUS PUSH DE POP IX ;IX = DE CALL $5200+SAVE_STATUS LD IX,0 ADD IX,SP LD C,(IX+HOR_SEL) ;GET PARAMS FOR BANK_ENABLE LD B,(IX+BANK) CALL BANK_ENABLE ;ENABLE DESTINATION BANK POP AF ;RESTORE REGS POP BC POP DE POP HL POP IX ;TRASH PARAMS TO CALL_BANK AND GET ADDR POP IX POP IX CALL $5200+JPIX PUSH AF PUSH BC PUSH DE PUSH HL LD IX,(BS_SP) LD C,(IX+0) INC IX LD B,(IX+0) INC IX ;POP PRM_IN OFF BS_STACK LD (BS_SP),IX ;UPDATE BS_SP LD IX,0 ADD IX,SP LD A,8 ADD A,C LD C,A JR NC,CB_NC2 ;BC = PRM_IN + 8 INC B CB_NC2: ADD IX,BC ;IX = SP + PRM_IN +9 PUSH IX POP HL ;HL=IX DEC HL ;HL = SRC POINTER FOR BLOCK MOVE CALL $5200+RESTORE_STATUS PUSH IX POP DE ;DE= DEST POINTER FOR BLOCK MOVE LDDR ;DEALLOCATE SPACE FOR BANK STATUS EX DE,HL INC HL LD SP,HL ;RESTORE SP LD IX,(BS_SP) LD C,(IX+0) INC IX LD B,(IX+0) INC IX ;POP RET ADDR OF BS_STACK LD (BS_SP),IX ;UPDATE BS_SP PUSH BC POP IX POP HL POP DE ;RESTORE REGISTERS POP BC POP AF PUSH IX RET ; ; HERE ARE SOME EQUATES WHICH ARE USED BY XFER_BYTES AND THE ROUTINES IT ; CALLS ; DEFC DIRECTION = 0 DEFC BUF_PTR = 0 DEFC LENGTH = 2 DEFC DEST_ADDR = 4 DEFC SRC_ADDR = 6 DEFC DEST_BANK = 8 DEFC SRC_BANK = 9 ; ; MOVE_BYTES (BYTES_TO MOVE: DE, DIRECTION: A) ; MOVE_BYTES: PUSH HL ;SAVE REGISTERS PUSH DE PUSH BC LD C,B LD B,(IX+SRC_BANK) CALL BANK_ENABLE ;FFF LD B,D LD C,E LD E,(IX+BUF_PTR) LD D,(IX+BUF_PTR+1) LD L,(IX+SRC_ADDR) LD H,(IX+SRC_ADDR+1) RLCA RRCA JR C,MB_RV1 ;IF A<0 LDIR ADD HL,BC JR MB_UP1 MB_RV1: LDDR AND A SBC HL,BC ;DECREMENT POINTER MB_UP1: LD (IX+SRC_ADDR),L ;STORE NEW POINTER VALUE LD (IX+SRC_ADDR+1),H POP BC POP HL PUSH HL PUSH BC LD B,(IX+DEST_BANK) CALL BANK_ENABLE ;SELECT DEST BANK LD B,H ;MOVE FROM STACK TO DEST LD C,L LD E,(IX+DEST_ADDR) LD D,(IX+DEST_ADDR+1) LD L,(IX+BUF_PTR) LD H,(IX+BUF_PTR+1) RLCA RRCA JR C,MB_RV2 ;IF A<0 LDIR ADD HL,BC ;INCREMENT POINTER JR MB_UP2 MB_RV2: LDDR AND A SBC HL,BC ;DECREMENT POINTER MB_UP2: LD (IX+DEST_ADDR),L ;STORE NEW POINTER VALUE LD (IX+DEST_ADDR+1),H POP BC POP DE POP HL RET ; ; CREATE_BITMAP (ADDR: HL, BITMAP: A) ; CREATE_BITMAP: LD D,H ;SAVE START ADR LD E,L LD C,(IX+LENGTH) LD B,(IX+LENGTH+1) LD A,(IX+DIRECTION) RLCA ;CALCULATE END ADDR RRCA JR C,CB_SUB ;IF A<0 ADD HL,BC JR CB_CONT CB_SUB: SBC HL,BC CB_CONT: CALL $5200+GET_CHUNK ;GET END CHUNK BIT CPL LD B,A EX DE,HL CALL $5200+GET_CHUNK ;GET START CHUNK BIT CPL LD C,A XOR B JR Z,CB_EXIT LD A,C ;HERE IF START AND END CHUNKS AND B ; ARE NOT THE SAME LD B,A ;PUT START AND END BITS TOGETHER AND LD C,0 ; FILL BETWEEN THEM WITH ZEROES SCF CB_NB1: LD A,B ;TEST NEXT BIT RL C AND C JR NZ,CB_NB1 ;OTHERWISE, FOUND FIRST ZERO CB_NB2: LD A,B ;TEST NEXT BIT RL C AND C JR Z,CB_EXIT ;FOUND LAST ZERO XOR B ;OTHERWISE, UPDATE BITMAP LD B,A JR CB_NB2 CB_EXIT: LD A,B RET ;RETURN BITMAP ; ; XFER_BYTES (DIRECTION, LENGTH, DEST_ADDR, SRC_ADDR, DEST_BANK, ; SRC_BANK,: PASSED ON STACK IN ORDER SHOWN: STATUS_CODE: A) ; ; ALL PARAMETERS ON STACK HAVE OFFSETS DEFINED ABOVE XFER_BYTES: PUSH AF ;SAVE REGS PUSH BC PUSH DE PUSH HL LD HL,0 ADD HL,SP LD DE,10 ADD HL,DE EX DE,HL ;DE POINTS TO START OF PARAMS LD A,(BS_MAX_BANK) LD C,A LD B,0 LD HL,0 ADD HL,SP AND A SBC HL,BC DEC HL DEC HL ;HL=SP-MAX_BANK-2 PUSH HL POP IX ;IX POINTS TO LOCATION TO SAVE STATUS LD SP,IX CALL $5200+SAVE_STATUS ;SAVE BANKS' STATUS PUSH DE POP IX ;IX POINTS TO PARAMS LD L,(IX+SRC_ADDR) LD H,(IX+SRC_ADDR+1) CALL $5200+CREATE_BITMAP ;GET SRC BITMAP PUSH AF ;SAVE ON STACK TEMPORARILY LD L,(IX+DEST_ADDR) LD H,(IX+DEST_ADDR+1) CALL $5200+CREATE_BITMAP ;GET DESTINATION BIT MAP LD C,A ;C=DEST BITMAP POP AF LD B,A ;B=SRC BITMAP LD A,(IX+SRC_BANK) LD D,(IX+DEST_BANK) CP D ;COMPARE SRC AND DEST BANK NUMBERS JR NZ,XB_DIFF_BANKS LD A,B ;HERE IF BANK NUMBERS ARE DIFFERENT AND C LD B,A ;B=UNION OR SRC AND DEST BITMAPS JR XB_DO_MOVE XB_DIFF_BANKS: LD A,B ;CHECK FOR OVERLAP BETWEEN SRC AND OR C ; DEST CHUNKS CP $FF JR NZ,XB_OVERLAP LD E,B ;HERE IF NO OVERLAP LD B,D CALL BANK_ENABLE ;SELECT DEST BANK XB_DO_MOVE: LD B,(IX+SRC_BANK) LD C,E CALL BANK_ENABLE ;SELECT DEST BANK LD L,(IX+SRC_ADDR) LD H,(IX+SRC_ADDR+1) LD E,(IX+DEST_ADDR) LD D,(IX+DEST_ADDR+1) LD C,(IX+LENGTH) LD B,(IX+LENGTH+1) LD A,(IX+DIRECTION) RLCA RRCA JR C,XB_REVERSE ;IF A<0 LDIR JR XB_EXIT XB_REVERSE: LDDR JR XB_EXIT XB_OVERLAP: LD HL,MSTBOT PUSH BC LD B,255 CALL $5200+GET_WORD POP BC LD DE,STKSZ AND A SBC HL,DE ;HL=ADDRESS OF STACK LIMIT LD DE,FREE_BYTES ADD HL,DE EX DE,HL ;DE=SP_NEW LD HL,0 ADD HL,SP ;HL=SP_OLD INC DE ;COMPARE SP_OLD AND SP_NEW AND A SBC HL,DE JR NC,XB_SPACE ;IF SP_OLD-SP_NEW > 0 LD A,1 ;RETURN ERROR CODE JR XB_EXIT XB_SPACE: DEC DE EX DE,HL LD SP,HL ;SET SP TO SP_NEW INC DE ;DE=BUF_SZ LD A,(IX+DIRECTION) LD (IX+BUF_PTR),L LD (IX+BUF_PTR+1),H LD L,(IX+LENGTH) LD H,(IX+LENGTH+1) XB_MOVE_LOOP: AND A ;HL = BYTES LEFT TO MOVE SBC HL,DE ;DE = BYTES TO MOVE THIS TIME JR C,XB_LAST_MOVE ;IF LESS THAN BUF_SZ BYTES LEFT CALL $5200+MOVE_BYTES JR XB_MOVE_LOOP XB_LAST_MOVE: ADD HL,DE EX DE,HL CALL $5200+MOVE_BYTES EX DE,HL LD L,(IX+BUF_PTR) LD H,(IX+BUF_PTR+1) ADD HL,DE ;HL = BUF_PTR+BUF_SZ LD SP,HL ;RESTORE SP XB_EXIT: XOR A ;RETURN CODE FOR SUCCESSFUL COMPLETION LD IX,0 ADD IX,SP CALL $5200+RESTORE_STATUS ;RESTORE STATE AND RETURN ZERO CODE INC IX LD SP,IX POP HL ;RESTORE REGS POP DE POP BC POP AF POP IX ;CLEAN UP PARAMS EX (SP),IX POP IX EX (SP),IX POP IX EX (SP),IX POP IX EX (SP),IX POP IX EX (SP),IX RET ; ; GOTO_EXT_INIT (ADDR: HL) ; GOTO_EXT: POP IX ;TRASH RET ADDR PUSH AF IN A,(HREXPT) SET 7,A OUT (HREXPT),A LD A,1 OUT (DKHSPT),A POP AF JP (HL) ; ORG $1624 ;$1624 to $17FF BLK1: DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00 ;$1700 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$80 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 ;$1800 to $1BFF ;$1800 BLK2: DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ;$1900 DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DEFB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ;$1C00 to $1CFF BLK3: DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 ORG $1D00 FIXTBL: DEFW DISPATCH+$32 DEFW DISPATCH+$4D DEFW DISPATCH+$72 DEFW DISPATCH+$AB DEFW $5200+INT+$0A DEFW $5200+INT+$1F DEFW $5200+INT+$25 DEFW $5200+INT+$2E DEFW $5200+INT+$4D DEFW $5200+GET_WORD+$04 DEFW $5200+GET_WORD+$0A DEFW $5200+GET_WORD+$0E DEFW $5200+GET_WORD+$14 DEFW $5200+GET_WORD+$1F DEFW $5200+PUT_WORD+$03 DEFW $5200+PUT_WORD+$09 DEFW $5200+PUT_WORD+$0D DEFW $5200+PUT_WORD+$13 DEFW $5200+PUT_WORD+$1C DEFW $5200+GET_STATUS+$12 DEFW $5200+GET_STATUS+$19 DEFW $5200+GET_STATUS+$23 DEFW $5200+GET_NUMBER+$03 DEFW $5200+GET_NUMBER+$07 DEFW $5200+GET_NUMBER+$0F DEFW BANK_ENABLE+$06 DEFW BANK_ENABLE+$13 DEFW BANK_ENABLE+$1A DEFW BANK_ENABLE+$75 DEFW BANK_ENABLE+$7D DEFW $5200+SAVE_STATUS+$14 DEFW $5200+SAVE_STATUS+$1C DEFW $5200+RESTORE_STATUS+$12 DEFW $5200+RESTORE_STATUS+$1C DEFW BS_SP DEFW $5200+GOTO_BANK+$13 DEFW $5200+CALL_BANK+$03 DEFW $5200+CALL_BANK+$1D DEFW $5200+CALL_BANK+$29 DEFW $5200+CALL_BANK+$4E DEFW $5200+CALL_BANK+$5D DEFW $5200+CALL_BANK+$6A DEFW $5200+CALL_BANK+$72 DEFW $5200+CALL_BANK+$80 DEFW $5200+CALL_BANK+$96 DEFW $5200+CALL_BANK+$A2 DEFW $5200+CALL_BANK+$B0 DEFW $5200+MOVE_BYTES+$08 DEFW $5200+MOVE_BYTES+$34 DEFW $5200+CREATE_BITMAP+$15 DEFW $5200+CREATE_BITMAP+$1B DEFW $5200+XFER_BYTES+$0E DEFW $5200+XFER_BYTES+$2D DEFW $5200+XFER_BYTES+$2E DEFW $5200+XFER_BYTES+$38 DEFW $5200+XFER_BYTES+$54 DEFW $5200+XFER_BYTES+$5B DEFW $5200+XFER_BYTES+$85 DEFW $5200+XFER_BYTES+$BA DEFW $5200+XFER_BYTES+$C1 DEFW $5200+XFER_BYTES+$D4 DEFW 0 ;TABLE TERMINATOR ;****************************************************************** ; Module: DISPATCH ; Routine: UNUSED1 ;****************************************************************** DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00 ;****************************************************************** ; Module: DISPATCH ; Routine: JMPTBL ;****************************************************************** DEFW $1795 ;PUT_LN: DEFW $2813 ;DRAWLN: DEFW $2624 ;F_PNT: DEFW $0939 ;SCRL: DEFW $08A6 ;K_CLS: DEFW $073F ;PUTMES: DEFW $0566 ;P_NL: DEFW $0554 ;P_RT: DEFW $053A ;P_LFT: DEFW $02B0 ;K_SCAN: DEFW $0010 ;WRCH: DEFW $11ED ;SENDCH: DEFW $11CF ;RDCH: DEFW $3C6C ;TO_THE: DEFW $3C65 ;ROOT: DEFW $3C5E ;ACS: DEFW $3C4E ;ASN: DEFW $3BFD ;ATN: DEFW $3BF5 ;TAN: DEFW $3BD0 ;SIN: DEFW $3BC5 ;COS: DEFW $3B9E ;ANGLE: DEFW $3B2E ;LN: DEFW $3ADF ;EXP: DEFW $3ACA ;INT: DEFW $3ABB ;INTDIV: DEFW $3656 ;FLOAT: DEFW $35D3 ;TRUNC: DEFW $356E ;DIVIDE: DEFW $3489 ;TIMES: DEFW $3468 ;MULT: DEFW $33D3 ;ADD: DEFW $33CE ;TSSUB: DEFW $31A1 ;OUTPUT: DEFW $3193 ;FP2A: DEFW $3160 ;FP2BC: DEFW $30F9 ;ININT: DEFW $30E9 ;STK_EC: DEFW $30E6 ;STK_A: DEFW $3059 ;STKUSN: DEFW $2FC0 ;DIM: DEFW $2FAF ;POPSTR: DEFW $2EBD ;LET: DEFW $2E74 ;PAEDCB: DEFW $2E70 ;PSHSTR: DEFW $2C70 ;FIND_N: DEFW $29F2 ;F_INKY: DEFW $29E5 ;F_PI: DEFW $29B6 ;RND: DEFW $28D7 ;F_ATTR: DEFW $288E ;F_SCRN: DEFW $2854 ;EXPRN: DEFW $2810 ;DRAW_L: DEFW $26DB ;DRAW: DEFW $2679 ;CIRCLE: DEFW $2660 ;GET_XY: DEFW $263E ;PLOTBC: DEFW $2635 ;PLOT: DEFW $2603 ;SCRMBL: DEFW $241D ;HIFLSH: DEFW $23DE ;COLOR: DEFW $2380 ;NOTKBQ: DEFW $226B ;ISEQ: DEFW $222B ;INPUT: DEFW $217E ;P_SEQ: DEFW $2159 ;K_PRIN: DEFW $2155 ;K_LPR: DEFW $201D ;DEF: DEFW $2009 ;BREAKQ: DEFW $1FEB ;PAUSE: DEFW $1FD4 ;RETURN: DEFW $1FBB ;CHK_SZ: DEFW $1F99 ;GO_SUB: DEFW $1F39 ;CLR_BC: DEFW $1F36 ;CLEAR: DEFW $1F23 ;FIX_U: DEFW $1F1E ;FIX_Ul: DEFW $1EF1 ;JUMP: DEFW $1EE4 ;CONT: DEFW $1ED4 ;RAND: DEFW $1ECA ;RESTBC: DEFW $1E82 ;DATA: DEFW $1D97 ;READ: DEFW $1D55 ;NEXT: DEFW $1C59 ;STOP: DEFW $1C78 ;FOR: DEFW $1AD8 ;EXCUTE: DEFW $1A27 ;SYNTAX: DEFW $1788 ;PUT_BC: DEFW $1750 ;DELREC: DEFW $1720 ;RECLEN: DEFW $16F0 ;SUBLIN: DEFW $16D6 ;FIND_L: DEFW $160D ;FLASHA: DEFW $25D0 ;MOVE: DEFW $25CC ;FORMAT: DEFW $25D4 ;ERASE: DEFW $25C8 ;CAT: DEFW $1465 ;OPCHAN: DEFW $142A ;OPEN: DEFW $13BE ;CLCHAN: DEFW $139F ;CLOSE: DEFW $1354 ;RESET: DEFW $12BB ;INSERT: DEFW $1230 ;SELECT: DEFW $11E1 ;INCH: DEFW $0D31 ;INIT: DEFW $0D1D ;K_NEW: DEFW $0D0D ;DESLUG: DEFW $0A4A ;PRSCAN: DEFW $0A23 ;DUMPPR: DEFW $08EA ;CLS: DEFW $08A9 ;CLLHS: DEFW $0888 ;R_ATTS: DEFW $0710 ;ATTBYT DEFW $05B2 ;SET_AT DEFW $0500 ;SEND_TV DEFW $0A02 ;K_DUMP DEFW $0436 ;BEEP DEFW $03F3 ;PARP DEFW $02E1 ;UD_K start of home rom services DEFW $FFFF ; RESERVED24: DEFW $FFFF ; RESERVED23: DEFW $FFFF ; RESERVED22: DEFW $FFFF ; RESERVED21: DEFW $FFFF ; RESERVED20: DEFW $6721 ;XFER_BYTES?($6722) RESERVED19: DEFW $65CF ;CALL_BANK? ($65CF) RESERVED18: DEFW $6571 ;GOTO_BANK? ($6571) RESERVED17: DEFW $6499 ;BANK_ENABLE RESERVED16: DEFW $645E ;GET_NUMBER GET_NUMBER: DEFW $6405 ;GET_STATUS GET_STATUS: DEFW $FFFF ; RESERVED13: DEFW $FFFF ; RESERVED12: DEFW $FFFF ; RESERVED11: DEFW $FFFF ; RESERVED10: DEFW $00E5 ;W_BORD RESERVED9: DEFW $0EA3 ; RESERVED8: DEFW $0851 ;SAVE RESERVED7: DEFW $06E5 ; RESERVED6: DEFW $05CC ;LOAD RESERVED5: DEFW $01AB ;SLVM RESERVED4: DEFW $018D ;R_EDGE RESERVED3: DEFW $0189 ;RD_BIT RESERVED2: DEFW $00FC ;RD_TAPE RESERVED1: EXROM services DEFW $0068 ; ; Apparently the linker needs this to generate the correct addresses ; Why? Who knows? ORG 0 ; END [/sourcecode]