10 REM > RSTROM/src
   20 REM Implements *RESET and OSBYTE 163,253 to cause machine reset
   30 :
   40 REM OSBYTE 163,253,n causes a machine reset
   50 REM   n=reset type as for OSBYTE 253
   60 REM     0=Soft reset    (Break)
   70 REM     1=PowerOn reset (Power On)
   80 REM     2=Hard reset    (Ctrl-Break)
   90 :
  100 REM *RESET (<n>) calls OSBYTE 163,253,n
  110 REM Defaults to n=0 for Soft Break
  120 :
  130 PROCassem(0):CLEAR:PROCassem(2):PROCsm_table
  140 A$="*SAVE "+fname$+" "+STR$~(mcode%+M%)+" "+STR$~O%+" FFFF0000 FFFBBC00"
  150 PRINTA$;:OSCLIA$:PRINT
  160 END
  170 :
  180 DEFPROCassem(pass%)
  190 OSBYTE=&FFF4:OSFILE=&FFDD:OSARGS=&FFDA:OSNEWL=&FFE7:OSWRCH=&FFEE
  200 ver$="0.10":date$=" (16 Apr 2018)":fname$="RSTROM"
  210 DIM mcode% &1400, L%-1
  220 :
  230 FOR pass%=pass% TO pass%+1
  240   opt%=FNsm_pass(pass%)+8+16
  250   [OPT opt%
  260   .rombase
  270   EQUB &00:EQUW RelocTable
  280   JMP Service
  290   EQUB &82:EQUB copyright-rombase
  300   .ROMTitle
  310   EQUB VALver$*10:EQUS "RESET"
  320   EQUB &00:EQUS ver$+date$
  330   .copyright
  340   EQUB &00:EQUS "(C)J.G.Harston"
  350   EQUB &00
  360   :
  370   .Service
  380   CMP #4:BEQ Serv4          :\ *command
  390   CMP #7:BEQ Serv7          :\ OSBYTE
  400   CMP #9:BNE NotServ9       :\ Not *Help
  410   LDA (&F2),Y
  420   CMP #13:BNE Serv9Skip     :\ Not *Help <cr>
  430   JSR OSNEWL:LDX #0
  440   .Serv9Lp
  450   LDA ROMTitle+1,X          :\ Print ROM title
  460   BNE P%+4:LDA #ASC" "      :\ Convert &00 to <spc>
  470   CMP #ASC"(":BEQ Serv9Done :\ End at '('
  480   JSR OSWRCH:INX:BNE Serv9Lp
  490   .Serv9Done
  500   JSR OSNEWL
  510   .Serv9Skip
  520   LDA #9
  530   .NotServ9
  540   RTS
  550   :
  560   .Serv4
  570   TYA:PHA:DEY:LDX #&FF
  580   .Serv4Lp
  590   INX:INY:LDA (&F2),Y
  600   CMP #ASC".":BEQ Serv4Dot
  610   CMP #ASC"!":BCC Serv4End
  620   CMP ROMTitle+1,X:BEQ Serv4Lp :\ Match with ROM title
  630   EOR #&20                     :\ Change case
  640   CMP ROMTitle+1,X:BEQ Serv4Lp :\ Match with ROM title
  650   .Serv4Quit
  660   PLA:TAY                      :\ Restore Y
  670   .Serv4Exit
  680   LDA #4:RTS                   :\ Restore A and return unclaimed
  690   .Serv4End
  700   LDA ROMTitle+1,X:BNE Serv4Quit
  710   DEY
  720   .Serv4Dot
  730   INY:LDA (&F2),Y              :\ Step past '.'
  740   CMP #ASC" ":BEQ Serv4Dot     :\ Skip any spaces
  750   :
  760   LDY #0:CMP #13:BEQ Serv4Reset:\ *RESET <cr>
  770   AND #7:TAY                   :\ *RESET <num>
  780   .Serv4Reset
  790   LDX #253:LDA #163:JSR OSBYTE :\ Send the call
  800   PLA:TAY:PLA                  :\ If we get back, return unclaimed
  810   .ServQuit
  820   RTS
  830   :
  840   .Serv7
  850   LDA &EF:CMP #163:BNE ServQuit
  860   LDA &F0:CMP #253:BNE ServQuit
  870   LDA &F1                        :\ *FX 163,253,n
  880   :
  890   .ForceReset
  900   \ A=RESET type
  910   \   0=Soft Break
  920   \   1=Power On
  930   \   2=Hard Break
  940   :
  950   SEI:CLD                        :\ Disable IRQs, ensure binary mode
  960   LDX #&FF:TXS:PHA               :\ Reset stack, save Break type
  970   LDA #&8F:LDX #&0C
  980   LDY #&FF:JSR OSBYTE            :\ Claim NMIs
  990   LDX #&40:STX &0D00             :\ Disable NMIs
 1000   LDA #0:JSR OSBYTE              :\ Read machine type
 1010   LDA &FFFC:STA &A8              :\ &A8/9=>RESET code
 1020   LDA &FFFD:STA &A9
 1030   TXA:BEQ ResetElk               :\ Jump if &00=Electron
 1040   :
 1050   LDA #&C0:STA &FEA0             :\ Reset hardware
 1060   LDA #&A0:STA &FEE0             :\ Tube Reset
 1070   LDA #&20:STA &FEE0             :\ Release Tube Reset
 1080   PLA:BEQ ResetJump              :\ Soft Break
 1090   LSR A:BCC ResetHard            :\ Hard Reset is fiddly
 1100   LDA #127:STA &FE4E             :\ Reset system VIA
 1110   .ResetJump
 1120   JMP (&FFFC)                    :\ Enter RESET code
 1130   :
 1140   .ResetElk
 1150   LDA #&C0:STA &FC28             :\ Reset Electron hardware
 1160   LDA #&A0:STA &FCE0             :\ Electron Tube Reset
 1170   LDA #&20:STA &FCE0             :\ Release Electron Tube Reset
 1180   PLA:BEQ ResetJump              :\ Soft Break
 1190   LDY #24:LSR A:BCS ResetElkJump :\ Power On
 1200   TAY:DEX                        :\ Y=0, X=&FF
 1210   .ResetElkHard
 1220   LDA (&A8),Y:INY
 1230   CMP #&20:BNE ResetElkHard      :\ Look for JSR
 1240   INY:INY:LDA (&A8),Y
 1250   CMP #&08:BNE ResetElkHard      :\ Look for PHP
 1260   .ResetElkJump
 1270   LDA &F4:ORA #&F0:STA &FE05     :\ Set up the ULA, set M=Ctrl Pressed
 1280   PHA:PHP                        :\ Push NotPowerOn, push CTRL pressed
 1290   BMI ResetAddJump               :\ Branch to jump into reset code
 1300   :
 1310   .ResetHard
 1320   LDY #&0F:STY &FE42             :\ SysVIA PortB=iiiioooo
 1330   .ResetIO
 1340   DEY:STY &FE40                  :\ Write to I/O latch
 1350   CPY #&09:BCS ResetIO           :\ Loop to set up internal I/O
 1360   CPX #&03:BCS ResetMaster
 1370   :
 1380   \ Read BBC keyboard links
 1390   LDX #&09
 1400   .ResetBBCLinks
 1410   LDY #&03:STY &FE40
 1420   LDY #&7F:STY &FE43
 1430   STX &FE4F:LDX &FE4F
 1440   CPX #&80:ROR &FC               :\ Rotate keystate in bit 7 into &FC
 1450   DEX:BNE ResetBBCLinks
 1460   ROL &FC                        :\ &FC holds link state
 1470   :
 1480   LDY #0                         :\ Y=0, X=&FF
 1490   .ResetBBClp
 1500   LDA (&A8),Y:INY
 1510   CMP #&26:BNE ResetBBClp        :\ Look for 'ROL zp'
 1520   .ResetAddJump
 1530   TYA:ADC &A8:STA &A8            :\ Update (&A8) to next instruction
 1540   LDA #0:STA &028D:STA &FE00     :\ Initialise last BREAK flag and Elk ULA
 1550   ADC &A9:STA &A9                :\ (A8)=>continuation of reset code
 1560   SEC:LDA #2:JMP (&A8)           :\ CS=CTRL pressed, jump to RESET code
 1570   :
 1580   .ResetMaster
 1590   LDY #0
 1600   .ResetMasterLp1
 1610   LDA (&A8),Y:INY                :\ Look for JSR
 1620   CMP #&20:BNE ResetMasterLp1
 1630   INY:INY:LDA (&A8),Y            :\ Check if followed by JMP
 1640   CMP #&4C:BNE ResetMasterLp1
 1650   INY:LDA (&A8),Y:STA &F6        :\ (F6)=>reset code in ROM 15
 1660   INY:LDA (&A8),Y:STA &F7
 1670   .ResetMasterLp2
 1680   JSR ResetROMByte               :\ Read byte from ROM 15
 1690   CMP #&E0:BNE ResetMasterLp2    :\ Look for 'CPX'
 1700   JSR ResetROMByte               :\ Read next byte from ROM 15
 1710   CMP #&80:BNE ResetMasterLp2    :\ Look for 'CPX #&80'
 1720   \ &F6/7 now points to rest of RESET code
 1730   :
 1740   LDA #&53:STA &FE8E             :\ Write to hardware I/O RESET
 1750   EQUB &1C:EQUW &0366:\ TSB      :\ Reset VDU 23,16 settings
 1760   LDX #&FF:STX &FE63             :\ User VIA Port A=output
 1770   LDA #&CF:STA &FE42             :\ System VIA Port B=ooiioooo
 1780   LDA #&0D:STA &DC00             :\ Command line = <cr>
 1790   LDA #&DC:STA &DF05             :\ Point to command line
 1800   EQUB &9C:EQUW &DF04:\ STZ
 1810   EQUB &9C:EQUW &DFDD:\ STZ      :\ Clear *MOVE flag
 1820   LDX #(ResetCodeEnd-ResetCode-1) AND &FF
 1830   .ResetLoop
 1840   LDA ResetCode,X:STA &100,X
 1850   DEX:BPL ResetLoop:TXS          :\ Reset stack
 1860   LDA &F7:AND #&40               :\ Test if code is in SROM or I/O area
 1870   STA &FE34:STA &FC              :\ Set memory map according to &F7
 1880   LDA #&0F:STA &028E             :\ Set keypad SHIFT setting, prepare ROM=15
 1890   PHA:SEC:JMP &100               :\ Push <>0=Not PowerOn, CS=CTRL pressed
 1900   :
 1910   .ResetCode
 1920   STA &FE30                      :\ Page in MOS ROM (IRQs are off)
 1930   JMP (&F6)                      :\ Jump to RESET code
 1940   .ResetCodeEnd
 1950   :
 1960   .ResetROMByte
 1970   LDA #&40:STA &FE34             :\ Set memory map
 1980   EQUB &B2:EQUB &F6:\ LDA (&F6)  :\ Read byte manually
 1990   BIT &F7:BVS ResetByte          :\ Exit if in high memory
 2000   LDY #&0F:JSR &FFB9             :\ Read byte from ROM 15
 2010   .ResetByte
 2020   INC &F6:BNE P%+4:INC &F7       :\ Increment address
 2030   RTS
 2040   :
 2050   ]:RelocTable=P%
 2060 NEXT:ENDPROC
 2070 :
 2080 DEFFNsm_pass(pass%)
 2090 IFpass%=0:M%=0
 2100 IFpass%=1:M%=O%-mcode%
 2110 P%=&8100-128*(pass%AND2)
 2120 O%=mcode%+M%*(pass%AND2)DIV2
 2130 IFpass%=1:IF O%+M%*2.125>L%:PRINT"Code overrun":END
 2140 =VALMID$("4647",pass%+1,1)
 2150 :
 2160 DEFPROCsm_table
 2170 base80%=mcode%+M%:base81%=mcode%:byte%=0:count%=0:off%=0:REPEAT
 2180   byte80%=base80%?off%:byte81%=base81%?off%:IF off%>=M%:byte80%=&80:byte81%=&80
 2190   IF ((byte81%-byte80%) AND &FE)<>0 THEN PRINT "ERROR: Offset by more than one page at &";~&8000+off%
 2200   IF (byte80% AND &C0)=&80:byte%=byte%DIV2+128*(byte81%-byte80%):count%=count%+1
 2210   IF count%=8:?O%=byte%:O%=O%+1:byte%=0:count%=0
 2220 off%=off%+1:UNTILoff%>=M% AND count%=0
 2230 ENDPROC