   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
