10 REM > SpecPatch 1.05
   20 REM Patch Speculator to:
   30 REM *** Can't seem to get *Spectrum to notify RESET properly
   40 REM  * access separate Tapes directory
   50 REM  * display centred better
   60 REM  * Reset and OUT (nn),A passed to service call
   70 REM  * read standard tapefiles
   80 REM  * Ensure unused DD/ED/FD codes return silently
   90 REM  * Fixed RETN to actually pop to PC
  100 REM  * OUT (BC),r passed to service call
  110 REM  * Seperate &DDDD and &FDDD
  120 REM To do:
  130 REM  - IN A,(nn) passed to service call
  140 REM  - IN r,(BC) passed to service call
  150 REM  - prevent it writing to protected memory
  160 REM  - display with MonitorType 4
  170 REM  - extra MOS interface?
  180 :
  190 REM Doesn't like just removing !8=value
  200 :
  210 ver0$="1.03":REM Patches version 1.03
  220 ver1$="1.04 (23 Mar 1998)"
  230 infile$="<Spec$Dir>.Speculator"
  240 outfile$="<Spec$Dir>.Speculator"
  250 :
  260 SYS "OS_File",5,infile$ TO ,,,,len%
  270 DIM ver0% 20,ver1% 20,mem% len%+&200:OSCLI"Load "+infile$+" "+STR$~mem%
  280 $ver0%=ver0$:$ver1%=ver1$
  290 IF mem%!&266<>!ver0% AND mem%!&266<>!ver1%:PRINT"This program only patches Speculator 1.03":END
  300 $(mem%+&266)=ver1$:mem%?(&266+LEN ver1$)=0
  310 PROCScrCentre
  320 PROCXYTape
  330 PROCRdTape
  340 REM PROCWrTape
  350 PROCReset
  360 PROCOUT_A
  370 REM PROCIN_A
  380 REM PROCSwiVector
  390 PROCNullOps
  400 :
  410 OSCLI"Save "+outfile$+" "+STR$~mem%+"+"+STR$~len%
  420 OSCLI"SetType "+outfile$+" Module"
  430 OSCLI"Stamp "+outfile$
  440 END
  450 :
  460 DEF PROCPoke(A%,B%,C%)
  470 IF mem%!A%<>B% AND mem%!A%<>C%:PRINT"Unexpected word found at &";~A%;" (";~mem%!A%;")":END
  480 mem%!A%=C%:ENDPROC
  490 :
  500 :
  510 REM Move the displayed screen left about 4 columns
  520 DEF PROCScrCentre
  530 PROCPoke(&04E4,&8C140000,&8C0E8000):REM LHS psn
  540 PROCPoke(&04E8,&90340000,&902E8000):REM RHS psn
  550 REM PROCPoke(&051C,&00000100,&000000FF):REM XWindLimit
  560 REM PROCPoke(&0524,&000000C0,&000000BF):REM YWindLimit
  570 ENDPROC
  580 :
  590 REM Seperate &DDDD and &FDDD instructions
  600 DEFPROCXYTape
  610 PROCPoke(&129F8,&EAFFC14C,&E51B0002):REM MOV R0,[R11,#-2]
  620 PROCPoke(&129FC,&E1000090,&E35000FD):REM CMP R0,#&FD
  630 PROCPoke(&12A00,&E1000090,&1AFFC14A):REM BNE &2F30
  640 PROCPoke(&12A04,&E1000090,&E1A0F00E):REM MOV pc,link
  650 ENDPROC
  660 :
  670 REM Looks at SpecTape$Path for files
  680 DEF PROCRdTape
  690 PROCPoke(&3124,&E28F2048,&E28F201C):REM ADR R2,&3148
  700 PROCPoke(&3148,&6570533C,&63657053):REM "Spec"
  710 PROCPoke(&314C,&69442463,&65706154):REM "Tape"
  720 PROCPoke(&3150,&502E3E72,&0000003A):REM ":"
  730 PROCPoke(&31D8,&E24F0084,&E1A0F00E):REM MOV pc,link
  740 :
  750 REM Read TAP files as well as SpecTape files
  760 PROCPoke(&2FB4,&E1800401,&EB000092):REM BL    &3204      ; R0=R0|R1+2*TAP
  770 PROCPoke(&2FD0,&E50C4054,&EB000090):REM BL    &3218      ; R4=R4+TAP; Store R4
  780 PROCPoke(&306C,&E50C4054,&EB000069):REM BL    &3218      ; R4=R4+TAP; Store R4
  790 PROCPoke(&310C,&E3C11A0F,&E1A0600E):REM MOV   R6,R14
  800 PROCPoke(&3110,&E2211C07,&EB000027):REM BL    &31B4      ; Check filetype
  810 PROCPoke(&3114,&E2311001,&E1A0E006):REM MOV   R14,R6
  820 PROCPoke(&3204,&73206874,&E1800401):REM ORR   R0,R0,R1,LSL #8
  830 PROCPoke(&3208,&6E697274,&E55C104C):REM LDRB  R1,[R12,#-76]
  840 PROCPoke(&320C,&6F742067,&E2111004):REM ANDS  R1,R1,#4
  850 PROCPoke(&3210,&6F727020,&12400002):REM SUBNE R0,R0,#2
  860 PROCPoke(&3214,&6D617267,&E1A0F00E):REM MOV   R15,R14
  870 PROCPoke(&3218,&72696420,&E51C004C):REM LDR   R0,[R12,#-76]
  880 PROCPoke(&321C,&6F746365,&E2100004):REM ANDS  R0,R0,#4
  890 PROCPoke(&3220,&74207972,&12844001):REM ADDNE R4,R4,#1
  900 PROCPoke(&3224,&6C206F6F,&E50C4054):REM STR   R4,[R12,#-84]
  910 PROCPoke(&3228,&00676E6F,&E1A0F00E):REM MOV   R15,R14
  920 :
  930 PROCPoke(&31B4,&20646574,&E3C11A0F):REM BIC   R1,R1,#&F000
  940 PROCPoke(&31B8,&69727473,&E50C104C):REM STR   R1,[R12,#-76]
  950 PROCPoke(&31BC,&2020676E,&E3510C07):REM CMP   R1,#&700
  960 PROCPoke(&31C0,&20202020,&2A000002):REM BCS   xx2
  970 PROCPoke(&31C4,&20202020,&E2211C01):REM EOR   R1,R1,#&0100
  980 PROCPoke(&31C8,&20202020,&E231101D):REM EORS  R1,R1,#&1d
  990 PROCPoke(&31CC,&20202020,&E1A0F00E):REM MOV   R15,R14
 1000 PROCPoke(&31D0,&20202020,&E2211C07):REM EOR   R1,R1,#&700
 1010 PROCPoke(&31D4,&20202020,&E2311001):REM EORS  R1,R1,#1
 1020 PROCPoke(&31D8,&E24F0084,&E1A0F00E):REM MOV   R15,R14
 1030 ENDPROC
 1040 :
 1050 REM Speculator TAP file is:
 1060 REM   {<block len><type><block>}
 1070 REM Standard TAP file is:
 1080 REM   {<type+block+check len><type><block><check>}
 1090 :
 1100 :
 1110 REM Notify emulated hardware of a Reset
 1120 DEF PROCReset
 1130 REM PROCPoke(&0994,&E1A0F00E,&EA000A11):REM B     &31E0
 1140 PROCPoke(&0A74,&E1A0B00C,&EB0009D8):REM BL    &31DC
 1150 PROCPoke(&3178,&70533A3A,&E24F4DC6):REM ADR   R4,0
 1160 PROCPoke(&317C,&6C756365,&E1A0F00E):REM MOV   pc,link
 1170 PROCPoke(&31DC,&E24F1070,&E1A0B00C):REM MOV   R11,R12  ; z80pc=z80mem
 1180 PROCPoke(&31E0,&E3A02064,&E92D4000):REM STMDB R13!,{R14}
 1190 PROCPoke(&31E4,&EF000027,&EBFFFFE3):REM BL    &3178  ; R4=ModuleBase
 1200 PROCPoke(&31E8,&31A0F00E,&E59F1010):REM LDR   R1,[PC,#16]
 1210 PROCPoke(&31EC,&E28F0000,&E3A00000):REM MOV   R0,#0
 1220 PROCPoke(&31F0,&EF00002B,&E54C0042):REM STR   R0,[R12,#-66]
 1230 PROCPoke(&31F4,&00800006,&E1A0000C):REM MOV   R0,R12
 1240 PROCPoke(&31F8,&676E654C,&EF020030):REM SWI   "OS_ServiceCall"
 1250 PROCPoke(&31FC,&6F206874,&E8BD8000):REM LDMIA R13!,{PC}
 1260 PROCPoke(&3200,&61702066,&00080AC2):REM EQUD  &80AC2            ; Srv_Z80Reset
 1270 ENDPROC
 1280 :
 1290 :
 1300 REM OUT (N),A extended to call Srv_Z80OUT
 1310 DEF PROCOUT_A
 1320 REM OUT_A:
 1330 PROCPoke(&3180,&726F7461,&E1802403):REM ORR  R2,R0,R3,LSL #8   ; R2=port
 1340 PROCPoke(&3184,&212E242E,&E54C3100):REM STRB R3,[r12,#-256]
 1350 PROCPoke(&3188,&63657053,&E54C40FC):REM STRB R4,[r12,#-252]
 1360 PROCPoke(&318C,&6D757274,&E1A0000E):REM MOV  R0,R14
 1370 PROCPoke(&3190,&6F72502E,&EBFFFFF8):REM BL   &3178             ; Find ModuleBase
 1380 PROCPoke(&3194,&6D617267,&E1A0E000):REM MOV  R14,R0
 1390 PROCPoke(&3198,&68002E73,&E59F1010):REM LDR  R1,[PC,#16]
 1400 PROCPoke(&319C,&63617261,&E1A0000C):REM MOV  R0,R12
 1410 PROCPoke(&31A0,&73726574,&EF000030):REM SWI  "OS_ServiceCall"
 1420 PROCPoke(&31A4,&726F6620,&E55C40FC):REM LDRB R4,[r12,#-252]
 1430 PROCPoke(&31A8,&65687420,&E55C3100):REM LDRB R3,[r12,#-256]
 1440 PROCPoke(&31AC,&61727420,&E1A0F00E):REM MOV  pc,link
 1450 PROCPoke(&31B0,&616C736E,&00080AC1):REM EQUD Srv_Z80TubeOUT
 1460 :
 1470 REM OUT (N),A:
 1480 PROCPoke(&6738,&11A0F00E,&1AFFF290):REM BNE  OUT_A
 1490 :
 1500 REM OUT (C),r:
 1510 FOR A%=0 TO 7
 1520   PROCPoke(&C2FC+A%*512,mem%!(&C2FC+A%*512),&1A000005)    :REM BNE P%+6*4
 1530   REM &C314+1*512 used ADC HL,rr
 1540   PROCPoke(&C318+A%*512,&E1000090,&E1862405)              :REM ORR  R2,R6,R5,LSL #8   ; R2=BC - port
 1550   PROCPoke(&C31C+A%*512,&E1000090,&E54C3100)              :REM STRB R3,[r12,#-256]    ; Save R3 (A)
 1560   PROCPoke(&C320+A%*512,&E1000090,&E1A03000+A%+5+9*(A%>5)):REM MOV  R3,reg            ; Pass value to R3
 1570   PROCPoke(&C324+A%*512,&E1000090,&EAFFDB97-128*A%)       :REM B    &3188             ; Jump to do srv_Z80OUT
 1580 NEXT
 1590 ENDPROC
 1600 :
 1610 :
 1620 REM Ensure null EDxx and iDxx codes return silently, fix RETN
 1630 DEF PROCNullOps
 1640 A%=&45                                     :REM Fix RETN
 1650 PROCPoke(&B2B8+64*A%+0,&E1000090,&E3A000FF):REM MOV R0,#&FF
 1660 PROCPoke(&B2B8+64*A%+4,&E1000090,&E54C0041):REM STRB R0,[R12,#-65]
 1670 PROCPoke(&B2B8+64*A%+8,&E1000090,&EAFFE82A):REM B {ret}
 1680 :
 1690 A%=&46                                     :REM Fix IM 0
 1700 PROCPoke(&B2B8+64*A%+0,&E1000090,&E3A00000):REM MOV R0,#0
 1710 PROCPoke(&B2B8+64*A%+4,&E1000090,&E50C005C):REM STR R0,[R12,#-92]
 1720 PROCPoke(&B2B8+64*A%+8,&E1000090,&E1A0F00E):REM MOV PC,R14
 1730 :
 1740  PROCnull(&B2B8,&63,&63):REM Should be LD (nn),HL
 1750  PROCnull(&B2B8,&6B,&6B):REM Should be LD HL,(nn)
 1760 :
 1770 REM EDxx gaps:
 1780 PROCnull(&B2B8,&00,&3F)
 1790 PROCnull(&B2B8,&4C,&4C)
 1800 PROCnull(&B2B8,&4E,&4E)
 1810 PROCnull(&B2B8,&54,&55)
 1820 PROCnull(&B2B8,&5C,&5D)
 1830 PROCnull(&B2B8,&64,&66)
 1840 PROCnull(&B2B8,&6C,&6E)
 1850 PROCnull(&B2B8,&70,&71)
 1860 PROCnull(&B2B8,&74,&77)
 1870 PROCnull(&B2B8,&7C,&7F)
 1880 PROCnull(&B2B8,&80,&9F)
 1890 PROCnull(&B2B8,&A4,&A7)
 1900 PROCnull(&B2B8,&AC,&AF)
 1910 PROCnull(&B2B8,&B4,&B7)
 1920 PROCnull(&B2B8,&BC,&BF)
 1930 PROCnull(&B2B8,&C0,&FF)
 1940 :
 1950 REM xyxx gaps:
 1960 PROCnull(&F2B8,&00,&08)
 1970 PROCnull(&F2B8,&0A,&18)
 1980 PROCnull(&F2B8,&1A,&20)
 1990 PROCnull(&F2B8,&27,&28)
 2000 PROCnull(&F2B8,&2F,&33)
 2010 PROCnull(&F2B8,&37,&38)
 2020 PROCnull(&F2B8,&3A,&3F)
 2030 FOR B%=0 TO 3
 2040   PROCnull(&F2B8,&40+8*B%,&43+8*B%)
 2050   PROCnull(&F2B8,&47+8*B%,&47+8*B%)
 2060   REM FOR A%=&40+8*B% TO &43+8*B%:PROCPoke(&F2B8+64*A%,&E1000090,&E1A0F00E):NEXT
 2070   REM A%=&47+8*B%:PROCPoke(&F2B8+64*A%,&E1000090,&E1A0F00E)
 2080 NEXT
 2090 PROCnull(&F2B8,&78,&7B)
 2100 PROCnull(&F2B8,&7F,&7F)
 2110 FOR B%=0 TO 7
 2120   PROCnull(&F2B8,&80+8*B%,&83+8*B%)
 2130   PROCnull(&F2B8,&87+8*B%,&87+8*B%)
 2140   REM FOR A%=&80+8*B% TO &83+8*B%:PROCPoke(&F2B8+64*A%,&E1000090,&E1A0F00E):NEXT
 2150   REM A%=&87+8*B%:PROCPoke(&F2B8+64*A%,&E1000090,&E1A0F00E)
 2160 NEXT
 2170 PROCnull(&F2B8,&C0,&CA)
 2180 PROCnull(&F2B8,&CC,&DC)
 2190 PROCnull(&F2B8,&DE,&E0)
 2200 PROCnull(&F2B8,&E2,&E2)
 2210 PROCnull(&F2B8,&E4,&E4)
 2220 PROCnull(&F2B8,&E6,&E8)
 2230 PROCnull(&F2B8,&EA,&F8)
 2240 PROCnull(&F2B8,&FA,&FC)
 2250 PROCnull(&F2B8,&FE,&FF)
 2260 :
 2270 REM Unimplemented xy codes:
 2280 PROCnull(&F2B8,&24,&24):REM INC XYH
 2290 PROCnull(&F2B8,&2D,&2D):REM DEC XYL
 2300 PROCnull(&F2B8,&76,&76):REM HALT XY
 2310 PROCnull(&F2B8,&84,&85):REM ADD A,XYH/XYL
 2320 PROCnull(&F2B8,&8C,&8D):REM ADC A,XYH/XYL
 2330 PROCnull(&F2B8,&94,&95):REM SUB XYH/XYL
 2340 PROCnull(&F2B8,&9C,&9D):REM SBC XYH/XYL
 2350 PROCnull(&F2B8,&A4,&A5):REM AND XYH/XYL
 2360 PROCnull(&F2B8,&B4,&B5):REM OR XYH/XYL
 2370 PROCnull(&F2B8,&BC,&BD):REM CP XYH/XYL
 2380 :
 2390 ENDPROC
 2400 :
 2410 DEF PROCnull(B%,S%,E%):FOR A%=S% TO E%:PROCPoke(B%+64*A%,&E1000090,&E1A0F00E):NEXT
 2420 ENDPROC
 2430 :
 2440 :
 2450 :
 2460 :
 2470 DEF PROCSwiVector
 2480 REM There are three occurances of !8=value
 2490 REM 00A10 (drop out with error), 00AB0 (exit), 00D50 (setup)
 2500 PROCPoke(&0A10,&E5810008,&F5810008)
 2510 PROCPoke(&0AB0,&E5810008,&F5810008)
 2520 PROCPoke(&0D50,&E5810008,&F5810008)
 2530 REM Also need to knock out SWI &C0000 calls
 2540 PROCPoke(&0918,&EF0C0000,&FF0C0000)
 2550 PROCPoke(&3040,&EF0C0000,&FF0C0000)
 2560 REM and 8 more
 2570 REM Knock out !&3400000=x call
 2580 PROCPoke(&0BDC,&E5810000,&F5810000)
 2590 REM Still ends up wanting direct screen access
 2600 ENDPROC
 2610 :
 2620 :
 2630 REM Test code:
 2640 PROCPoke(&30D8,&6AFFF63C,&EA000034):REM 30D8: B &31B0
 2650 PROCPoke(&31B0,&616C736E,&6AFFF606):REM 31C0: BVS &09D0
 2660 PROCPoke(&31B4,&20646574,&E24C00EC):REM 31C4: SUB R0,R12,#236
 2670 PROCPoke(&31B8,&69727473,&EF000116):REM 31CC: SWI 256+22
 2680 PROCPoke(&31BC,&2020676E,&EF000100):REM 31CC: SWI 256+0
 2690 PROCPoke(&31C0,&20202020,&EF000002):REM 31C8: SWI "OS_Write0"
 2700 PROCPoke(&31C4,&20202020,&EF000107):REM 31CC: SWI 256+7
 2710 PROCPoke(&31C8,&20202020,&EAFFFFC3):REM 31D0: B &30DC
 2720 ENDPROC