10REM SAVE"$.Arabic.Source.Copy" 20REM ####################################################################### 30REM ## ## 40REM ## This code is the most fragile part of the Arabic Rom - ## 50REM ## Do NOT change anything in the area handling Ram interception ## 60REM ## unless you know EXACTLY what is happening. If you are an ## 70REM ## Acorn systems programmer of two or three years standing you ## 80REM ## will understand why I am leaving this warning! ## 90REM ## ## 100REM ####################################################################### 110very_temp = T% : REM MOS Scratch workspace. Only use where nothing 120 REM else can get in between loading and using. 130ArabicByteHandler = F% 140PROCConsts 150PROCVars 160data=FNzp(2) 170DIM O% &BFFF-P% 180R%=P%:Q%=O% 190ramEnter=&0:ramReturn=&0:ramPasson=&0 200REM The three labels above are offsets in our private page into which 210REM the OsByte redirections are relocated. The exact size of data needed 220REM for these areas is calculated by a multi-phase assembly. 230REM If you are not familiar with this concept PLEASE DO NOT FIDDLE WITH IT! 240REM - the likelihood of getting UNREPORTED phase errors in the assembly is 250REM high. 260FOR Phase = 0 TO 1 : REM Find out code area sizes first time round. 270OL%=L%:REMIF W%<>&FFFF THEN L%=Phase 280FOR Pass=4 TO 6+L% STEP 2+L% 290P%=R%:O%=Q% 300[OPT Pass 310.CopyHandlerInit 320 OPT FNEnter 330\ Copy rambytecode here 340 OPT FNRelocate(enterStart, enterEnd, ramEnter) 350 OPT FNRelocate(returnStart, returnEnd, ramReturn) 360 OPT FNRelocate(passonStart, passonEnd, ramPasson) 370 \ Code copied to Ram must be patched at start-up with our rom number. 380 Ldx &F4:Txa:OPT FNSta(enterPatch+1-enterStart+ramEnter) 390 Ldx &F4:Txa:OPT FNSta(passonPatch+1-passonStart+ramPasson) 400 Lda ByteV:OPT FNSta(oldbytev) 410 Lda ByteV+1:OPT FNSta(oldbytev+1) 420 OPT FNAddr(ramEnter):Stx ByteV:Sty ByteV+1 430 OPT FNExit 440 Rts 450 460\\\\\\\\\\\\\\\\\\\\ This section may be safely altered \\\\\\\\\\\\\\\\\\\ 470.MyByte 480 PHP:PHA 490 Cmp #71 500 Beq KeyboardAlphabet 510 Cmp #70 520 Bne notCountry 530 \Cpx #21 540 \Bne notCountry Not so fussy now. In fact, we want to unflip on others 550 PLA:PLP 560 Jsr ArabicByteHandler 570 Cmp #0:Beq return 580 OPT FNJmp(ramPasson) 590 600.return 610 OPT FNJmp(ramReturn) 620 630.KeyboardAlphabet 640 PLA:PLP 650 Jsr ArabicByteHandler 660 Cmp #0:Beq return 670 OPT FNJmp(ramPasson) 680 690.notCountry 700 Cmp #135:Beq DoCopy 710 PLA:PLP 720 OPT FNJmp(ramPasson) \ This one restores last selected sideways rom 730.DoCopy 740 PLA:PLP 750 Jsr HisByte \ Must leave this sideways rom selected for return 760 Cpx #0:Bpl notarabic 770 Pha:Lda Undo-128,X:Tax:Pla 780 .notarabic 790 OPT FNJmp(ramReturn) 800 810.HisByte 820 OPT FNJmpI(oldbytev) 830\\\\\\\\\\\\\\\\\\\\\\\\\\ STOP - go no farther! \\\\\\\\\\\\\\\\\\\\\\\\\\ 840 850\ The overhead added by the code below is excessive, but it is the 860\ only guaranteed 'clean' way to intercept MOS calls in a sideways Rom. 870 880\ Not that references to code inside this relocated code must be RELATIVE 890 900.enterStart 910 Php:Pha:Phx:Phy 920.enterPatch Ldx #6 930 Lda &DF0,X 940 \ Save old Rom number 950 Sta very_temp+1:Lda #ramPrevRom:Sta very_temp:Lda &F4:Sta (very_temp) 960 \ Select our Rom so we can jump in to it. 970 Stx &F4:Stx &FE30 \ Rom No. still in X 980 Ply:Plx:Pla:Plp 990 Jmp MyByte 1000.enterEnd 1010 1020.returnStart 1030 Php:Pha:Phx:Phy 1040 Ldx &F4:Lda &DF0,X:Sta very_temp+1:Lda #ramPrevRom:Sta very_temp 1050 Lda (very_temp):Sta &F4:Sta &FE30 1060 Ply:Plx:Pla:Plp 1070 Rts 1080.returnEnd 1090 1100.passonStart 1110 Php:Pha:Phx:Phy 1120.passonPatch Ldx #6 1130 Lda &DF0,X:Sta very_temp+1 1140 Lda #ramPrevRom:Sta very_temp\ NOT IF ramPrevRom >= &100 1150 Lda (very_temp):Sta &F4:Sta &FE30 \ Warning - not re-entrant 1160 \ Note - if debugging with PHEX or whatever from Rom, the write to the 1170 \ latch must be AFTER any Rom accesses. 1180 Lda #oldbytev:Sta very_temp \ NOT IF oldbytev >= &100 1190 Lda (very_temp):PHA:Inc very_temp:Bne P%+4:Inc very_temp+1 1200 Lda (very_temp):Sta very_temp+1 1210 PLA:Sta very_temp 1220 Ply:Plx:Pla:Plp 1230 Jmp (very_temp) 1240.passonEnd 1250 1260.PHEX \ Here for debugging - may be removed if you need the space 1270 \ Any Ram code calling this MUST ensure this rom is switched in. 1280 PHA 1290 Lsr A:Lsr A:Lsr A:Lsr A 1300 Jsr PN 1310 Pla 1320.PN 1330 And #&0F 1340 Cmp #10 1350 Bcc noc 1360 Adc #6 1370.noc Adc #ASC("0") 1380 Jmp OsWrCh 1390 1400 1410 1420 1430.Undo \ ************** Must be last label in this block unless you want 1440 \ to import the FNLoad from some other module. 1450] 1460NEXT Pass 1470IF Phase = 0 THEN ramEnter=FNRmb(enterEnd-enterStart) 1480IF Phase = 0 THEN ramReturn=FNRmb(returnEnd-returnStart) 1490IF Phase = 0 THEN ramPasson=FNRmb(passonEnd-passonStart) 1500IF (Phase = 1) AND (W%<>&FFFF) THEN PRINT "Enter=";~ramEnter;",Return=";~ramReturn;",Passon=";~ramPasson 1510NEXT Phase 1520E%=CopyHandlerInit 1530OSCLI("LOAD $.Arabic.Object.Reverse "+STR$~(O%)):O%=O%+128:P%=P%+128 1540OSCLI("Save $.Arabic.Object.CopyOBJ "+STR$~(Q%)+" "+STR$~(O%)+" "+STR$~(R%-&8000+&3000)+" "+STR$~(R%-&8000+&3000)) 1550L%=OL%:CHAIN"$.Arabic.Source.OsBytes" 1560 1570DEFFNRelocate(from, to, ram) 1580IF (ram+to-from)>=&100 THEN =FNLongRelocate(from, to, ram) 1590[OPT Pass 1600 Ldx #0:Ldy #ram \ Y is pointer, X is counter 1610.copy 1620 Lda from,X: Sta (data),Y 1630 Iny 1640 Inx:Cpx #to-from:Bne copy 1650] 1660=Pass 1670 1680DEFFNAddr(offset) 1690IF offset >= &100 THEN =FNLongAddr(offset) 1700[OPT Pass 1710 PHP:PHA:Ldx &F4:Lda &DF0,X:Tay:Ldx #offset:PLA:PLP 1720] 1730=Pass 1740 1750DEFFNJmp(offset) : REM Jumps to private ram - absolute NOT indirect. 1760IF offset >= &100 THEN =FNLongJmp(offset) 1770[OPT Pass 1780 PHP:PHA:PHX 1790 Ldx &F4:Lda &DF0,X:Sta very_temp+1:Lda #offset:Sta very_temp 1800 PLX:PLA:PLP 1810 Jmp (very_temp) 1820] 1830=Pass 1840 1850DEFFNJmpI(offset) : REM Jumps VIA private ram - indirect. 1860IF offset >= &100 THEN =FNLongJmpI(offset) 1870[OPT Pass 1880 PHP:PHA:PHX 1890 Ldx &F4:Lda &DF0,X:Sta very_temp+1:Lda #offset:Sta very_temp 1900 Lda (very_temp):Pha:Inc very_temp:Bne P%+4:Inc very_temp+1 1910 Lda (very_temp):Sta very_temp+1:Pla:Sta very_temp 1920 PLX:PLA:PLP 1930 Jmp (very_temp) 1940] 1950=Pass 1960 1970DEFPROCConsts 1980 REM MyXXX's are initialised here for 1990 REM 2-pass assembly in Basic. 2000Ins = 21 : InsV = FNVector(Ins) 2010OsByte = &FFF4 2020Byte = 5 : ByteV = FNVector(Byte) 2030OsWord = &FFF1 2040OsCli = &FFF7 2050OsRdCh = &FFE0 2060RdCh = 8 : RdChV = FNVector(RdCh) 2070OsRdSc = &FFB9 2080OsWrCh = &FFEE 2090OsNewl = &FFE7 2100OsAscii = &FFE3 2110OsWrSc = &FFB3 2120OsFind = &FFCE 2130OsFile = &FFDD 2140OsArgs = &FFDA 2150OsGbPb = &FFD1 2160OsBPut = &FFD4 2170OsBGet = &FFD7 2180OsEvent = &FFBF 2190GSInit = &FFC2 2200GSRead = &FFC5 2210ENDPROC 2220 2230DEFFNVector(N) 2240 = &200 + 2*N 2250 2260DEFPROCVars 2270 oldbytev = FNRmb(2) 2280 ramPrevRom = FNRmb(1) 2290ENDPROC 2300 2310DEFFNzp(N) 2320LOCAL I 2330 I = N% 2340 N% = N% + N 2350 IF N% > Z% THEN PRINT"ERROR: Using too much zero page.":END 2360 = I 2370 2380DEFFNRmb(N) 2390LOCAL I 2400 I = M% 2410 M% = M% + N 2420 = I 2430 2440DEFFNEnter : REM Called once on entry to Rom 2450 REM Sets uplocal data area for easy access 2460[OPT Pass 2470 Lda data:PHA 2480 Lda data+1:PHA 2490 Ldx &F4:Lda &DF0,X 2500 Sta data+1 2510 Stz data 2520] 2530=Pass 2540 2550DEFFNLda(variable_offset) 2560[OPT Pass 2570 Ldy #variable_offset:Lda (data),Y 2580] 2590=Pass 2600 2610DEFFNSta(variable_offset) 2620[OPT Pass 2630 Ldy #variable_offset:Sta (data),Y 2640] 2650=Pass 2660 2670DEFFNExit :REM Called once on exit from Rom 2680[OPT Pass 2690 Pla: Sta data+1 2700 Pla: Sta data 2710] 2720=Pass