REM Basic Assembler Supplement 1.00 © 1996-1998 Straylight REMÂÁÓhack REM ----- Licensing note ---------------------------------------------------- REM REM This file is part of Straylight's BASIC Assembler Supplement (BAS) REM REM BAS is free software; you can redistribute it and/or modify REM it under the terms of the GNU General Public License as published by REM the Free Software Foundation; either version 2, or (at your option) REM any later version REM REM BAS is distributed in the hope that it will be useful, REM but WITHOUT ANY WARRANTY; without even the implied warranty of REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the REM GNU General Public License for more details. REM REM You should have received a copy of the GNU General Public License REM along with BAS. If not, write to the Free Software Foundation, REM 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. REM --- Hacking warning --- REM REM That gorp on the second line is a magic marker word inserted by hand REM (the three letters `BAS' with their top bits set) and space for an offset REM word which marks the offset of the code section from the beginning of REM the LIBRARY link block. Don't play with them unless you (a) know what REM you're doing (and it should be perfectly clear by now that I don't have REM a clue), and (b) want to seriously upset the library search code below. ERROR 0,"You can't run the Basic Assembler Supplement" REM --- A note --- REM REM To make this program particularly easy to strip down and transmogrify, REM it contains directives which are picked up by a sed script during REM munging. The directives currently are `del ... edel' which deletes REM all the enclosed lines, and `hex' which inserts the generated hex version REM of the library search code. Directives are enclosed in square brackets. REM It's usual to put them in REM statements. REM ----- Initialisation ---------------------------------------------------- REM [del] DEF FNbas_assign(RETURN d,v%):d=v%:=0 DEF PROCbas_const(var$,val%) IF bas_cf% THEN BPUT #bas_cf%,"/\<"+var$+"\>/s//"+STR$(val%)+"/g" IF EVAL("FNbas_assign("+var$+",val%)") ENDPROC DEF FNnext:R%+=4:=R%-4 DEF PROCbas_saveconst bas_cf%=OPENOUT("work.basconst") DEF PROCbas_constants bas_cf%=bas_cf% R%=0 PROCbas_const("bcode_wSize",FNnext) PROCbas_const("bcode_init",FNnext) PROCbas_const("bcode_aofInit",FNnext) PROCbas_const("bcode_newPass",FNnext) PROCbas_const("bcode_import",FNnext) PROCbas_const("bcode_export",FNnext) PROCbas_const("bcode_get",FNnext) PROCbas_const("bcode_area",FNnext) PROCbas_const("bcode_reloc",FNnext) PROCbas_const("bcode_noReloc",FNnext) PROCbas_const("bcode_entry",FNnext) PROCbas_const("bcode_save",FNnext) PROCbas_const("bcode_align",FNnext) PROCbas_const("bcode_reserve",FNnext) PROCbas_const("bcode_lit",FNnext) PROCbas_const("bcode_ltorg",FNnext) PROCbas_const("bcode_saveOpt",FNnext) PROCbas_const("bcode_restoreOpt",FNnext) IF bas_cf% THEN CLOSE #bas_cf% ENDPROC REM [edel] REM --- Unexplainable horridness --- REM REM Tim wants to be able to embed the code into this library file, so REM that it doesn't have to be searched for. I'll therefore have to write REM some code to scan the library list and locate this one, and find the REM code tacked onto the end. Yuk. DEF PROCbas_init LOCAL type%,size% :REM [dl] LOCAL workSize%,H%,len%,f% PROCbas_constants :REM [dl] REM --- Old code to load the library from disk --- REM [del] IF TRUE THEN DIM bas_scratch% 300 SYS "OS_File",17,"libs:BAScode" TO type%,,,,size% IF type%<>1 THEN ERROR 0,"BAS code not found" DIM bas_code% size% SYS "OS_File",16,"libs:BAScode",bas_code%,0 ELSE DEF PROCbas_dumpcode REM [edel] REM --- New hacking to scan the library list --- REM REM This must be done in assembler, of course ;-) Time to put on my pointy REM Rincewind hat... I've tried to do this in one pass because I'm lazy -- REM I guess that's why it's unreadable. DIM bas_scratch% 300 P%=bas_scratch% [ opt 0 ; exit with r0 == pointer to code, or 0 if not found (erk!) ldr r2,[pc] ; load the magic marker word mov pc,pc ; skip over the magic marker word dcd &d3c1c2f4 ; this is `REMBAS', with the top bits set ldr r0,[r14,#&24] ; find offset of TIMEOF add r0,r8,r0 ; add on ARGP to find TIMEOF ldr r0,[r0,#&c] ; load the library list base ;.loop cmp r0,#0 ; is that the end of it all? moveqs pc,r14 ; yes -- oh, well -- it was a nice try ldr r1,[r0,#&44] ; load mystic recognition word cmp r1,r2 ; does it match? ldrne r0,[r0] ; if not there, load the next link subne pc,pc,#28 ; and jump back to `loop' (erk) ldr r1,[r0,#&48] ; load the code offset add r0,r1,r0 ; and add it to the base address movs pc,r14 ] REM --- Now some code to dump that out as hex --- bas_code%=USR bas_scratch% IF bas_code%=0 THEN ERROR 0,"BAS code not found: is the library corrupt?" REM [del] ENDIF REM [edel] REM --- Back to life as normal --- workSize%=USR(bas_code%+bcode_wSize) DIM bas_workspace% workSize% H%=bas_workspace% CALL bas_code%+bcode_init SYS "XOS_ReadVarVal","BAS$Output",bas_scratch%,256,3 TO ,,len%;f% IF f% AND 1 THEN bas_fileName$="" ELSE bas_scratch%?len%=13 bas_fileName$=$bas_scratch% ENDIF ENDPROC DEF PROCbas_aofInit(size%) LOCAL H% IF size% THEN DIM bas_asmCode% size% ELSE bas_asmCode%=bas_asmCode% IF bas_asmCode%=0 THEN ERROR 0,"No buffer allocated for assembler code" H%=bas_workspace% CALL bas_code%+bcode_aofInit,bas_asmCode% ENDPROC REM This function saves a few bytes and tidies up the code a bit. DEF FNbas_call(offset%) LOCAL H% H%=bas_workspace% =USR(bas_code%+offset%) REM ----- AOF code generation ----------------------------------------------- DEF PROCbas_aofSaveAs(name$) LOCAL H% H%=bas_workspace% CALL bas_code%+bcode_save,name$ ENDPROC DEF PROCbas_aofSave IF bas_fileName$="" THEN ERROR 0,"No implicit filename" PROCbas_aofSaveAs(bas_fileName$) bas_fileName$="" ENDPROC DEF FNpass=FNbas_call(bcode_newPass) DEF FNbas_port(offset%,A%,s$,t$) LOCAL H% H%=bas_workspace% CALL bas_code%+offset%,s$,t$ =0 DEF FNimport(var$)=FNbas_port(bcode_import,0,var$,var$) DEF FNimportAs(sym$,var$)=FNbas_port(bcode_import,0,sym$,var$) DEF FNimportWeak(var$)=FNbas_port(bcode_import,1,var$,var$) DEF FNimportWeakAs(sym$,var$)=FNbas_port(bcode_import,1,sym$,var$) DEF FNexport(var$)=FNbas_port(bcode_export,0,var$,var$) DEF FNexportAs(var$,sym$)=FNbas_port(bcode_export,0,var$,sym$) DEF FNexportStrong(var$)=FNbas_port(bcode_export,1,var$,var$) DEF FNexportStrongAs(var$,sym$)=FNbas_port(bcode_export,1,var$,sym$) DEF FNget(file$) LOCAL H% H%=bas_workspace% CALL bas_code%+bcode_get,file$ =0 DEF FNbas_lib(lib$) LOCAL err%,leaf$,lower$,i% leaf$=lib$ FOR i%=1 TO LEN(lib$) IF INSTR(":.",MID$(lib$,i%,1)) THEN leaf$=MID$(lib$,i%+1) NEXT FOR i%=1 TO LEN(leaf$) lower$+=CHR$(ASC(MID$(leaf$,i%,1)) OR &20) NEXT LOCAL ERROR ON ERROR LOCAL err%=TRUE IF err%=FALSE THEN IF EVAL("FN"+lower$+"_test") ENDIF RESTORE ERROR IF err%=TRUE THEN LIBRARY lib$ =0 DEF FNarea(name$,attr$) LOCAL A%,H% A%=2 IF INSTR(attr$,"CODE") THEN A%+=&200 IF INSTR(attr$,"COMDEF") THEN A%+=&400 IF INSTR(attr$,"COMMON") THEN A%+=&800 IF INSTR(attr$,"NOINIT") THEN A%+=&1000 IF INSTR(attr$,"READONLY") THEN A%+=&2000 IF INSTR(attr$,"DEBUG") THEN A%+=&8000 IF A% AND &800 THEN A%=A% OR &1000 IF A% AND &200 THEN A%=A% OR &2000 H%=bas_workspace% CALL bas_code%+bcode_area,name$ =0 DEF FNreloc=FNbas_call(bcode_reloc) DEF FNnoReloc=FNbas_call(bcode_noReloc) DEF FNentry=FNbas_call(bcode_entry) REM ----- Literal handling -------------------------------------------------- DEF PROClitStart bas_litStart%=P% bas_savedOpt%=USR(bas_code%+bcode_saveOpt) ENDPROC DEF FNlitw(val%) PROClitStart [ opt 4: dcd val%:] =FNlitAlign DEF FNlits(str$) PROClitStart [ opt 4: equs str$:] =FNlit DEF FNlitmagic(str$) PROClitStart [ opt 4: equs str$:] =FNlitAlign DEF FNlitsz(str$) PROClitStart [ opt 4: equs str$+CHR$0:] =FNliteral DEF FNliterr(err%,str$) PROClitStart [ opt 4: dcd err%: equs str$+CHR$0:] =FNlitAlign DEF FNliteral LOCAL A%,B%,C% A%=bas_savedOpt% CALL bas_code%+bcode_restoreOpt B%=P%-bas_litStart% A%=O%-B% C%=0 P%=bas_litStart% O%=A% =FNbas_call(bcode_lit) DEF FNlitAlign LOCAL A%,B%,C% A%=bas_savedOpt% CALL bas_code%+bcode_restoreOpt B%=P%-bas_litStart% A%=O%-B% C%=1 P%=bas_litStart% O%=A% =FNbas_call(bcode_lit) DEF FNltorg=FNbas_call(bcode_ltorg) REM ----- Initialising areas ------------------------------------------------ DEF FNalign=FNbas_call(bcode_align) DEF FNreserve(A%)=FNbas_call(bcode_reserve) DEF FNbin(file$) LOCAL size% IF FNbas_call(bcode_noReloc) size%=FNfSize(file$) SYS "OS_File",16,file$,O%,0 O%+=size% P%+=size% IF FNbas_call(bcode_reloc) =0 DEF FNfSize(file$) LOCAL size% SYS "OS_File",17,file$ TO ,,,,size% =size% REM ----- Laying out storage areas ------------------------------------------ DEF PROCws_start bas_R%=0 ENDPROC DEF PROCws_base(start%) bas_R%=start% ENDPROC DEF FNws(size%) bas_R%+=size% =bas_R%-size% DEF PROCws_align bas_R%=(bas_R%+3) AND -4 ENDPROC DEF FNws_word PROCws_align =FNws(4) DEF FNws_byte=FNws(1) REM ----- Long directives --------------------------------------------------- DEF FNadrl(r%,adr%)=FNaddccl(14,r%,15,adr%-P%-8) DEF FNadrccl(cc%,r%,adr%)=FNaddccl(cc%,r%,15,adr%-P%-8) DEF FNaddl(r%,b%,off%)=FNaddccl(14,r%,b%,off%) DEF FNaddccl(cc%,r%,b%,off%) IF off%>0 THEN [opt 4:addeq r%,b%,#off% AND 255:addeq r%,r%,#off% AND -256:] ELSE [opt 4:subeq r%,pc,#(-off%) AND 255:subeq r%,r%,#(-off%) AND -256:] ENDIF !(O%-8)=!(O%-8) OR (cc%<<28) !(O%-4)=!(O%-4) OR (cc%<<28) =0 DEF FNldrl(r%,adr%)=FNldrrccl(14,r%,15,adr%-P%-8) DEF FNldrccl(cc%,r%,adr%)=FNldrrccl(cc%,r%,15,adr%-P%-8) DEF FNldrrl(r%,b%,off%)=FNldrrccl(14,r%,b%,off%) DEF FNldrrccl(cc%,r%,b%,off%) IF off%>0 THEN [opt 4:addeq r%,b%,#off% AND -256:ldreq r%,[r%,#off% AND 255]:] ELSE [opt 4:subeq r%,b%,#(-off%) AND -256:ldreq r%,[r%,#-((-off%) AND 255)]:] ENDIF !(O%-8)=!(O%-8) OR (cc%<<28) !(O%-4)=!(O%-4) OR (cc%<<28) =0 REM ----- That's all, folks -------------------------------------------------