> SMLoad/src v0.13 & Load Sideways Relocatable Module , 14-Jan-2001 v0.10 JGH: Initial version (; 15-Jan-2001 v0.11 JGH: Add LDX &F4 before JSR OldServ 2L 16-Jan-2001 v0.12 JGH: Optimised and squeezed down to fit in &880-&AFF " .errNotFound .\BRK:\EQUB 214:\EQUS "File not found":\BRK %BRK:EQUB 214:EQUS "Not found":BRK : .exec% LDA #1:LDX #lptr:LDY #0 3JSR OSARGS:LDA (lptr),Y :\ Get parameters 7CMP #13:BEQ errSyntax :\ No filename, error : "LDX lptr+0:LDY lptr+1 ,.LDA #&40:JSR OSFIND :\ Open file 6TAY:BEQ errNotFound @3LDX #size:LDA #2:JSR OSARGS :\ Read file size J&LDA size+3:A size+2:BNE errTooBig T"LDA size+1:CMP #&40:BCC SizeOk ^BNE errTooBig hLDA size+0:BNE errTooBig r .SizeOk |: 2\ Now look for a bank of RAM with enough space 5LDA &F4:PHA :\ Save current ROM 1TYA:PHA :\ Save channel 5LDX #15 :\ Start at bank 15  .FindLoop /JSR SelectROM :\ Select ROM /LDA &8008: #&AA:STA &8008 :\ Test for RAM :CMP &8008:BNE NotRAM :\ Not RAM, look at next 6 #&AA:STA &8008 :\ Restore tested byte ?LDY #&7F:STY addr+1 :\ Set to &7FFF in case empty LDY #&FF:STY addr+0 @LDA &2A1,X: #&C0:BEQ AllEmpty :\ Whole bank is empty, Y=&FF :INY:LDA #&BF:STA addr+1 :\ Start at &BFFF, Y=&00  .ScanLoop LDA (addr),Y ACMP &BFFF:BNE StartOfFree :\ Look for start of free space &5LDA addr+0:BNE P%+4 :\ Dec. ROM address 0DEC addr+1:DEC addr+0 :6LDA addr+1:BMI ScanLoop :\ Loop until <&8000 D8BPL AllEmpty :\ Whole bank is empty N: X2\ Found start of free space, check it for size b.StartOfFree lSEC:LDA addr+0:ADC size+0 vPHA:LDA addr+1:ADC size+1 ?CMP #&BF:BCC FoundSpace :\ Free+Size<&BF00 - use it ?BNE NotEnoughSpace :\ Size>=&C000 - not enough ?PLA:PHA:CMP #&FE:BCC FoundSpace :\ Free+Size<&BFFE - use it .NotEnoughSpace PLA  .NotRAM 6DEX:BPL FindLoop :\ Step to next bank 5PLA:TAY :\ Get channel back .errTooBig  JSR Close +BRK:EQUB 133:EQUS "Not enough SRAM":BRK )\BRK:\EQUB 133:\EQUS "SRAM full":\BRK : .FoundSpace  2PLA :\ Balance stack /.AllEmpty :\ addr=&7FFF  JSR UpdateAddr *\ 4 \ addr=>start of empty space >.\ Y=&FF - empty ROM, Y=&00 - non-empty ROM H\ R%\ Follow links to insertion point \:INY:STY base+0:STY base+1:BEQ linkhere :\ ROM is empty fCDEC base+0:LDA #&80:STA base+1 :\ Point to start of ROM p\ z \ addr=>start of loaded code \ base=>current module \ dest=>next module \ \ ----------------------- \ zzz zzz zzz \ JMP ccc  \ bbb \ ----------------------- \ ccc JSR bbb \ (LDX &F4) \ JMP eee  \ ddd \ ----------------------- \ base JSR ddd \ (LDX &F4) .\ JMP fff --> JMP mmm ------+ $.\ | ..\ dest JSR ggg xxx xxx <-----+ | 8.\ xxx | | B.\ ggg | | L.\ ----------------------- | | V.\ mmm BRK xxx xxx --> JSR dest -+ <-+ `\ nnn JMP ooo j\ t\ ooo .... ~\ \ ----------------------- \ .followlinks  LDY #3 .followlinks1 ILDA (base),Y:INY:CMP #&4C :\ Look for 'JMP', skipping any LDX &F4 BNE followlinks1 >TYA:CLC:ADC base+0:STA base+0 :\ base=>dest field of 'JMP'  LDA base+1:ADC #0:STA base+1  LDY #2 .followlinks3 9DEY:LDA (base),Y:STA dest,Y :\ Point to next module :TYA:BNE followlinks3 :\ or into service code  GLDA (dest),Y:CMP #&20:BNE linkhere :\ Not 'JSR', not another module  LDY #3 GLDA (dest),Y:CMP #&4C:BEQ nextlink :\ JSR,JMP - short module header (JCMP #&A6:BNE linkhere :\ JSR,LDX,JMP - long module header 2 .nextlink <LDA dest+0:STA base+0 FLDA dest+1:STA base+1 PBNE followlinks Z .linkhere d\ n \ addr=>start of empty space x9\ base=>current final module JMP dest address or 0000 8\ dest=>service code of current final module or XXXX \ 1PLA:TAY :\ Get channel start of previous module or &0000  \ addr=>start of loaded code  \ dest=>start of loaded code 3\ base=>offset of loaded code from start of ROM \ "3\ Everything before here can now be overwritten ,: 6,TYA:PHA :\ Channel @ .loadloop JLDA #0:LDX #12 T.loadclear ^7STA gbpb,X:DEX:BPL loadclear :\ Clear OSGBPB block h,PLA:PHA:STA gbpb+0 :\ Channel r1LDA #load 255:STA gbpb+1 :\ Addr=&FFFFload |LDA #load 256:STA gbpb+2 STX gbpb+3:STX gbpb+4 ,LDA #&01:STA gbpb+6 :\ Num=256 LDX #gbpb 255 LDY #gbpb 256 LDA #4:JSR OSGBPB LDY gbpb+6:BNE loaded LDX gbpb+5  .byteloop LDA load%,Y:STA (addr),Y INY:INX:BNE byteloop INC addr+1:TYA:BEQ loadloop  .loaded *PLA:TAY:JSR Close :\ Close \ \ addr=corrupted  \ dest=>start of loaded code &3\ base=>offset of loaded code from start of ROM 0\ :\ Check if header exists DLDY #6:LDA (dest),Y: #&8F N2CMP #&82:BNE jmpNoHeader :\ Not Serv+6502 X!INY:LDA (dest),Y:TAY:LDX #3+1 b .CheckHdr l0LDA (dest),Y:CMP CopyStr-1,X:BNE jmpNoHeader v@INY:DEX:BNE CheckHdr :\ Ends with X=0, CS ;LDY #2:LDA (dest),Y:BPL jmpNoRelocate :\ Jump with CS ;LDY #0:LDA (dest),Y:BNE jmpNoRelocate :\ Jump with CS \ \ addr=corrupted  \ dest=>start of loaded code 3\ base=>offset of loaded code from start of ROM \ CLC 4INY:LDA (dest),Y:ADC dest+0:STA addr+0:STA end+0 ;INY:LDA (dest),Y: #&3F:ADC dest+1:STA addr+1:STA end+1 \ 8\ addr=>end of loaded code/start of relocation table  \ dest=>start of loaded code 3\ base=>offset of loaded code from start of ROM  8\ end =>end of loaded code/start of relocation table \  LDY #0:BEQ relocloop * .CopyStr 4EQUS ")C("+0 >\ H.jmpNoHeader RCLC \.jmpNoRelocate f7PLA:PLA :\ Drop link address pMJMP NoRelocation :\ Skip relocation, CC=no header CS=header z\ .relocloop 6LDA (dest),Y:BPL nextbyte :\ <&80 - no change 6CMP #&C0:BCS nextbyte :\ >&BF - no change EDEX:BPL testbit :\ Relocation bits still available 9LDA (addr),Y:STA byte :\ Get relocation byte ?JSR UpdateAddr :\ Update relocation address 8LDX #7 :\ 7+1 bits available  .testbit EROR byte:BCC nextbyte :\ Bit clear, no relocation IDEY:DEC dest+1:CLC :\ Point to low byte of address ILDA (dest),Y:ADC base+0:STA (dest),Y :\ Relocate low byte of address OINY:INC dest+1 :\ Point back to high byte of address JLDA (dest),Y:ADC base+1:STA (dest),Y :\ Relocate high byte of address  .nextbyte @JSR UpdateDest :\ Update code address KCMP end+1:BNE relocloop :\ Loop until end of code reached $&LDA dest+0:CMP end+0:BNE relocloop .\ 8#\ addr=>end of relocation table B\ dest=>end of loaded code L3\ base=>offset of loaded code from start of ROM V8\ end =>end of loaded code/start of relocation table `\ j.clearloop tCTYA:STA (dest),Y :\ Clear relocation table ~@JSR UpdateDest :\ Update code address BCMP #&C0:BCC clearloop :\ Loop until end of ROM DLDA base+1:A #&80:STA base+1 :\ Point base back into ROM \ #\ addr=>end of relocation table \ dest=>&C000 \ base=>newly loaded code 8\ end =>end of loaded code/start of relocation table \ DPLA:STA addr+0:PLA:STA addr+1 :\ Get insertion addresses ?BPL NoRelocation :\ No previous module \ \ Cy = CS E\ addr=>start of penultimate module+4 or +6 - service entry point \ dest=>&C000 \ base=>newly loaded code 8\ end =>end of loaded code/start of relocation table (\ 29LDA base+0:SBC #2:STA base+0 :\ Space for 'LDX &F4' < LDA base+1:SBC #0:STA base+1 FDLDY #0:LDA #&20:STA (base),Y :\ New module does JSR OldService P .addrlp1 Z!LDA (addr),Y:INY:STA (base),Y d2CPY #2:BNE addrlp1 :\ Ends with CS n6LDA #&A6:INY:STA (base),Y :\ Insert 'LDX &F4' xLDA #&F4:INY:STA (base),Y LDY #1 .addrlp2 ELDA base,Y:STA (addr),Y :\ OldServEntry does JMP NewModule DEY:BPL addrlp2 : .NoRelocation =BCC NoHeader :\ No header found earlier 2LDA &8006:LDX &F4:STA &2A1,X :\ Set ROM type : .NoHeader PLA:TAX .SelectROM ESTA &FF30,X:STX &F4:JMP &FFB9 :\ Enable WERAM writes, select ROM :  .Close LDA #0:JMP OSFIND ": ,.UpdateAddr 6&INC addr+0:BNE P%+4:INC addr+1:RTS @.UpdateDest J1INC dest+0:BNE P%+4:INC dest+1:LDA dest+1:RTS T: ^EQUS "0.13" h: r] |gbpb=load+256  K" *Save SMLoad "+~mcode%+" "+~O%+" "+~(exec%&FFFF0000)+" "+~load%