10
20
30 :
40
50
60
70
80
90 :
100
110
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