> USBROM/src  DataCentre USB Support ROM  Needs HiBasic to assemble (: 2- v0.05 Command/Help/Config/Status parser <) v0.07 Keyboard driver, no USKBD OFF F7 v0.10 USBKBD ON|OFF, Break, Reset, OSBYTE 163,253 P! v0.11 adding printer driver Z1 v0.12 single vector table, *USBMOUSE header d5 v0.13 *Help returns unclaimed, mouse code added n< v0.14 *Help claimed as Y not returned, added OSWORD 64 x+ v0.20 Checks for USB hardware present : OSBYTE=&FFF4:OSARGS=&FFDA *OSASCI=&FFE3:OSNEWL=&FFE7:OSWRCH=&FFEE GBYTEV =&20A:WORDV =&20C:EVNTV =&220:KEYV =&228:UPTV =&222 GXBYTEV =&DAE:XWORDV =&DB1:XEVNTV =&DCF:XKEYV =&DDB:XUPTV =&DD2 GoldBYTEV=&D9B:oldWORDV=&D9D:oldEVNTV=&800:oldKEYV=&802:oldUPTV=&802 ?LASTK=&23C:KBDNUM=&23D:KBDMOD=&96:MSEPOSN=&D92:MSEKEYS=&D98 CNPV=&22E:RemV=&22C USBPRN=13 usb_D=&FCF8:usb_S=&FCF9 :  mcode% &1C00, L%-1 &ver$="0.20":date$=" (28 Dec 2018)" :  pass%=0 3 opt%=sm_pass(pass%)+8+16 " [OPT opt% , .ROMBase 6EQUB &00:EQUW RelocTable @JMP Service J#EQUB &82:EQUB copyright-ROMBase T .ROMTitle ^$EQUB ver$*10:EQUS "USB Support" hEQUB &00:EQUS ver$+date$ r.copyright |"EQUB &00:EQUS "(C)J.G.Harston"  EQUB &00 : : \ Support routines \ ----------------  .PrDec ETAX:LDA #&99 :\ Move value to X, start at -1 in BCD >SED :\ Switch to decimal arithmetic  .PrDecLp 5CLC:ADC #1 :\ Add one in BCD mode ?DEX:BPL PrDecLp :\ Loop for all of source number BCLD :\ Switch back to binary arithmetic .ScanDecLp H8STA &F5 :\ Store as current number R2JSR ScanChkDigit :\ Get current digit \/BCS ScanDecDone :\ No more digits f3PHA:LDA &F5 :\ Save current digit p9CMP #26:BCS ScanDecTooBig :\ If num>25, will overflow z+ASL A:ASL A:ADC &F5:ASL A :\ num=num*10 7STA &F5:PLA :\ Get current digit back 1ADC &F5:BCC ScanDecLp :\ num=num*10+digit .ScanDecTooBig .errBadNumber JSR MkError "EQUB 252:EQUS "Bad number":BRK .ScanDecDone 8LDA &F5:CLC :\ CC=valid number scanned 7.ScanDecExit :\ CS=bad number or digit RTS : .ScanChkDigit :LDA (&F2),Y :\ Get current character 'CMP #"0":BCC ScanDecErr :\ <'0' 'CMP #"9"+1:BCS ScanDecErr :\ >'9' >INY: #15:RTS :\ Convert character to binary $.ScanDecErr .5SEC:RTS :\ CS=invalid digit 8: B: L .MkError V9PLA:STA &FD:PLA:STA &FE :\ Pop address after JSR `>LDY #0 :\ Index into the error block j.MkErrorLp t=INY:LDA (&FD),Y:STA &100,Y :\ Copy error block to stack ~CBNE MkErrorLp :\ Loop until terminating &00 byte CSTA &100:JMP &100 :\ Store &00 as BRK and jump to it : :  .Service :PHA :\ Save service number 4CMP #&01:BEQ Serv01 :\ Break pressed 4CMP #&27:BEQ Serv27 :\ Break pressed /CMP #&04:BEQ ServCmd04 :\ *command ,CMP #&09:BEQ ServCmd09 :\ *help 1CMP #&28:BEQ ServCmd28 :\ *configure .CMP #&29:BEQ ServCmd29 :\ *status -CMP #&08:BEQ Serv08 :\ OSWORD -CMP #&07:BNE ServExit :\ OSBYTE  :  .Serv07 5LDA &EF:CMP #163:BNE ServExit :\ Not OSBYTE 163 (9LDA &F0:CMP #253:BNE ServExit :\ Not OSBYTE 163,253 2LDA &F1:JMP ForceReset <: F .Serv08 P LDA &EF:CMP #64:BNE ServExit ZJMP mseOsword d: n .Serv01 x .Serv27 TYA:PHA:JSR usbStartup  PLA:TAY  .ServExit  PLA:RTS : .ServCmd04:.ServCmd09 LLSR A :\ Convert service call number to bitmap .ServCmd28:.ServCmd29 PHA '\ 04 -> 02 -> 02 command xxxx0010 '\ 09 -> 04 -> 04 help xxxx0100 '\ 28 -> 28 -> 08 config xxxx1000 '\ 29 -> 29 -> 09 status xxxx1001 \ =LDX #0 :\ Point to start of table >STX &F5 :\ And set command number 0 "9LDA (&F2),Y :\ Get first character ,LCMP #&0D:BEQ ServCmdNull :\ *help, *status, *configure 6JCMP #&2E:BEQ ServCmdNull :\ *help . *status . *configure . @: J.ServCmdEntryLp T>INC &F5 :\ Increment command number ^BEQ ServCmdSkipSpc :\ And step past any spaces ;PLA :\ Drop old line pointer =\ To return *Help unclaimed need to preserve line pointer 9\TSX:\LDA &101,X:\ #4 :\ Get stacked call type C\BNE ServCmdNull:\STA &102,X :\ If not *Help, claim this call 5LDA #0:TSX:STA &102,X :\ Claim this call .ServCmdNull CLDA &F5:ASL A:TAX :\ X=command offset, Carry Clear .ServCmdDispatch LDA CmdDispatch+1,X:STA &F7 LDA CmdDispatch+0,X:STA &F6 CPLA:TAX: #1:ADC #&D8:CMP #1 :\ Convert command type, CC=Status JSR JumpF6  APLA:RTS :\ Return claimed or unclaimed .ServCallStatus  BPHA:PHA:CLC :\ Push command type onto stack *CJMP ServCmdDispatch :\ Jump to call *Status routines 4: >\ On entry, H\ Flags set from A: R\ EQ = Status \\ PL = Status/Configure f\ MI = Help/Command p\ (&F2),Y=>command line z\ Y=0 = Help syntax \ X=command type \  .JumpF6  JMP (&F6) : /.cmdUSB :\ *Help USB DEY  .cmdNull !CPX #4:BNE cmdHelp:JSR OSNEWL .cmdTitleLp 'LDA ROMTitle-3,X:BNE P%+4:LDA #" " 3CMP #"(":BEQ cmdTitleDone :\ Print ROM title !JSR OSWRCH:INX:BNE cmdTitleLp .cmdTitleDone 9JSR OSNEWL:LDX #2 :\ X=2 - list commands #LDA (&F2),Y:CMP #13:BNE cmdHelp $JRTS :\ No parameter, only display ROM title . .cmdHelp 8FTYA:PHA:TXA:PHA :\ Save Y=lineptr, X=command bitmap B>LDX #0:LDY #0 :\ Point to start of tables L.cmdHelpLp1 VAINY:INY :\ Step to next dispatch entry ` or . %EQUW cmdUSB :\ USB ,EQUW cmdDevices :\ USBDEVICES (EQUW cmdKBD :\ USBKBD *EQUW cmdMouse :\ USBMOUSE *EQUW cmdPrint :\ USBPRINT 'EQUW cmdReset :\ RESET : ": ,.cmdSyntax 6PLA:CPX #64:BCS cmdSyntax2 @2JSR PrText:EQUS "|OFF":EQUB 13:EQUB 0:RTS J.cmdSyntax2 T/JSR PrText:EQUS "ON|OFF":EQUB 13:EQUB 0:RTS ^: h#.cmdPrint :LDX #128:BNE cmdDoIt r#.cmdMouse :LDX #64 :BNE cmdDoIt |.cmdKBD :LDX #63 .cmdDoIt 2BCC cmdStatus2 :\ *Status HPHA:TYA:BEQ cmdSyntax :\ Y=0, *help or *config. syntax requested FLDA (&F2),Y :\ Save command type, get char from line GCMP #13:BEQ cmdStatus1 :\ *command or *configure command ?JSR ScanOnOffName :\ Parse parameter || to Y 1PLA:BMI cmdJump :\ *command : :: :\ *Configure -TYA:PHA :\ Save 4TXA: #255:PHA :\ Mask to keep old bits 1JSR CMOSRead:TSX :\ Get my CMOS byte 8 &102,X: &101,X :\ Merge new setting into byte  &102,X:TAY 3PLA:PLA :\ Drop stacked bytes : &3.CMOSWrite :\ Write my CMOS byte 0LDX #19:LDA #162:JMP OSBYTE :2.CMOSRead :\ Read my CMOS byte DCLC N.StatusRead X3PHP:LDA KBDNUM: #&80 :\ Get current keyboard b2CMP #64:BCC P%+4:LDA #0 :\ Use it if claimed l7ASL A:ASL A:PHA :\ Make space for PRN/MSE v,JSR MSECheckOn :\ CS=Mouse On PLA:ROR A:PHA .JSR PRNCheckOn :\ CS=Printer On ,PLA:ROR A:TAY :\ Y=%pmkkkkkk FPLP:BCS CMOSRead2 :\ If CS or no CMOS, use current setting #LDX #19:LDA #161:JSR OSBYTE:TYA .CMOSRead2 1RTS :\ A=Y=CMOS/Setting *\ CMOS byte is %pmkkkkkk PRN, MSE, KBD \ KBDNUM is %10kkkkkk KBD )\ %11xxxxxx MOS keyboard 3\ %0xxxxxxx International keyboard : .cmdJump  TXA:ASL A BCC P%+5:JMP usbPRINT BPL P%+5:JMP usbMOUSE JMP usbKBD *: 4H.cmdStatus1 :\ *command or *configure command >8PLA:BPL errBadConfigure :\ *configure command H3.cmdStatus2 :\ *Status R7TXA:PHA :\ Save parameter bitmap \=JSR StatusRead:TSX :\ Get CMOS or current setting f/ &101,X:TAY:PLA :\ Y=value, A=mask p5CMP #64:TYA:BCS PrOnOffEtc :\ mask=64 or 128, / z5JSR PrDec:JSR PrSpace :\ Print decimal value *TYA: #&F7 :\ Drop bit 3 .PrOnOffEtc 9LDX #&FF :\ Look for matching entry : ,\ A=match byte, X=offset-1 to start from .PrTableName .PrOnOffLp1 INX :CMP txtNames,X:BEQ PrOnOffLp2 :\ Matched entry prefix 2LDY txtNames,X:BPL PrOnOffLp1 :\ End of table .PrOnOffDone JMP OSNEWL .PrOnOffLp2 LDA txtNames+1,X: #127 CMP #"A":BCC PrOnOffDone !JSR OSWRCH:INX:BNE PrOnOffLp2 $: ..errBadConfigure 8JSR MkError B#EQUB 254:EQUS "Bad command":BRK L: V .txtNames `EQUB 0:EQUS "OFF" jEQUB 1:EQUS "UK" tEQUB 2:EQUS "BBC" ~\EQUB 13:\EQUS "Europe" EQUB 32:EQUS "Japan" EQUB 48:EQUS "USA" EQUB 64:EQUS "ON" EQUB 128:EQUS "ON"  EQUB 0 : .DeviceNames EQUB &01:EQUS "Keyboard" EQUB &02:EQUS "Mouse" EQUB &07:EQUS "Printer" EQUB &08:EQUS "Disk" EQUB &09:EQUS "Hub" EQUB &0B:EQUS "Card"  EQUB &00 : : (\ (&F2),Y=> || 2\ Returns Y=0 | 0-255 | 255 <.ScanOnOffName FLDA (&F2),Y: #&DF PCMP #"O":BNE ScanOnOffNum ZINY:LDA (&F2),Y: #&DF d&LDY #0:CMP #"F":BEQ ScanOnOffDone n#DEY:CMP #"N":BEQ ScanOnOffDone xJMP errBadNumber .ScanOnOffNum JSR ScanDec:TAY .ScanOnOffDone RTS : : \ Low-level USB I/O \ ----------------- '.usb_CmdX :\ A=command, X=parameter SEC:BCS usb_CmdCy .usb_Cmd :\ A=command CLC .usb_CmdCy :JSR usb_Sync:JSR usb_Wr:BCC usb_Cmd2 :\ Send command :LDA #" ":JSR usb_Wr:TXA:JSR usb_Wr :\ Send parameter  .usb_Cmd2 "DLDA #13 :\ Fall through with ,: 6,\ IRQs are off, so no point checking ESC @6.usb_Wr:\BIT &FF:\BMI usb_Wr2:BIT usb_S:BVS usb_Wr J.usb_Wr2:STA usb_D:RTS T6.usb_Rd:\BIT &FF:\BMI usb_Rd2:BIT usb_S:BMI usb_Rd ^.usb_Rd2:LDA usb_D:RTS h: r=\ Send command to USB, after waits for returned |<\ except after final command returns first byte of reply .usb_KbdCmdDRDSync JSR usb_Sync )LDX #usb_SC0-usb_KbdCmds :\ SC0, DRD .usb_KbdCmd6  LDY #6 .usb_KbdCmd !TXA:PHA:JSR usb_Flush:PLA:TAX .usb_KbdCmdLp1  LDA usb_KbdCmds,X:JSR usb_Wr INX:DEY:BEQ usb_Rd CMP #13:BNE usb_KbdCmdLp1 .usb_KbdCmdLp2 (JSR usb_Rd:CMP #13:BNE usb_KbdCmdLp2 BEQ usb_KbdCmd : @\ NB, after RESET, Vinc takes a couple of seconds to respond &'\ Callers expect Cy to be preserved 0 .usb_Sync :%BIT usb_S:BMI usb_Sync1:BIT usb_D D:BIT &FF:BPL usb_Sync:RTS :\ Loop until no byte pending N.usb_Sync1 X8BIT usb_S:BVS usb_Sync :\ Loop back if can't write bPHA lLDA #"E":STA usb_D v1LDA #13:STA usb_D :\ Send ECHO command /.usb_Sync2:JSR usb_Rd: #"E":BNE usb_Sync2 -.usb_Sync3:JSR usb_Rd: #13:BNE usb_Sync3 3PLA:BIT &FF:RTS :\ Return MI if Escape : ".usb_Flush :BIT usb_D:LDX #16 $.usb_FlushLp:DEX:BNE usb_FlushLp BIT usb_S:BPL usb_Flush:RTS : .usb_Check 0LDA #"E":STA usb_D:LDA #13:STA usb_D:LDX #4 .usb_CheckLp #LDA usb_D:CMP #13:BEQ usb_Flush CMP #"E":BEQ usb_CheckLp DEX:BNE usb_CheckLp  3JSR MkError:EQUB 210:EQUS "USB not present":BRK :  : *5\ *USBDEVICES - enumerate and display device info 45\ ----------------------------------------------- >.cmdDevices H-TYA:BNE P%+5:JMP OSNEWL :\ Syntax is "" R)JSR usb_Check:JSR usb_Sync:JSR PrText \*EQUS "Num Adr Prt Type":EQUB 13:EQUB 0 f;PHP:SEI :\ Prevent background USB actions p LDA #&10:JSR usb_Cmd :\ SCS z LDA #&91:JSR usb_Cmd :\ IPH  LDX #0  .L8257  TXA:PHA  LDA #&85:JSR usb_CmdX :\ QDn : \ Read device information \ Off Stack \ &10F,X=number \ 00 &10E,X=address \ 01 &10D,X \ 02 &10C,X \ 03 &10B,X \ 04 &10A,X \ 05 &109,X \ 06 &108,X \ 07 &107,X=type $\ 08 &106,X= .\ 09 &105,X=port 8\ 0A &104,X= BD\ 0B &103,X=class 03 03 03 07 08 09 0B L\ 0C &102,X=subclass V,\ 0D &101,X=protocol 01 02 00 `E\ Keyboard Mouse Joystick Printer Disk Hub Card j LDX #14 t .L826E ~6JSR usb_Rd:PHA:DEX:BNE L826E :\ Get first 14 bytes 0JSR usb_Sync :\ Discard rest +CLC:TSX:LDA &10E,X :\ Address 1BNE L8282:JMP L82FC :\ If zero, skip :  .L8282 0LDA &10F,X:JSR PrHex:JSR Pr2Spaces :\ Number 1LDA &10E,X:JSR PrHex:JSR Pr2Spaces :\ Address .LDA &105,X:JSR PrHex:JSR Pr2Spaces :\ Port .LDY #&FD:LDA &107,X:SEC :\ Type  .L829C INY:INY:INY:ROL A:BCC L829C "LDA DeviceTypes+0,Y:JSR OSWRCH "LDA DeviceTypes+1,Y:JSR OSWRCH  "LDA DeviceTypes+2,Y:JSR OSWRCH JSR PrSpace .LDA &0103,X:JSR PrHex:JSR PrSpace :\ Class (1LDA &0101,X:JSR PrHex:JSR PrSpace :\ Protocol 2: <LDA &0103,X F3 n.cmdDevicesName xLDX #DeviceNames-txtNames-1 JSR PrTableName:JMP L82FC :  .L82F9 JSR OSNEWL  .L82FC 8TSX:TXA:CLC:ADC #14:TAX:TXS :\ Drop from stack "PLA:TAX:INX:CPX #&10:BCS L830C SEI:JMP L8257  .L830C  PLP:RTS : .DeviceTypes &EQUS "HUBOTHBMDCDCHIDPRNRESSERNUL" : : .usbStartup "JSR CMOSRead ,- #63:BEQ usbStart_NotKBD :\ USBKBD 6LDY KBDNUM:CPY #&C0 @6BCC CheckVecOk :\ Already claimed J;PHA:JMP usbKBD_On2 :\ Turn on USB keyboard T.usbStart_NotKBD ^TYA:BPL usbStart_NotPRN h:JMP usbPRINT :\ Turn on USB printer r.usbStart_NotPRN |ASL A:BPL CheckVecOk 8JMP usbMOUSE :\ Turn on USB mouse : : .MSECheckOn ,LDX #BYTEV 255:LDY #mseBYTEV-usbVector BPL CheckXVector : .PRNCheckOn *LDX #UPTV 255:LDY #prnUPTV-usbVector : .CheckXVector \ Check if vector claimed 1\ X=System vector offset, Y=USB vector offset IJSR CheckVector:BCC CheckVecOff :\ Vector not extended MTXA:PHA:LSR A:TSX:ADC &101,X:TAX:PLA :\ X=(X/2)*3 =>XVEC offset @LDA &D9F+2,X:CMP &F4:BNE CheckVecOff :\ Not my ROM &DLDA &D9F+1,X:CMP usbVector+1,Y:BNE CheckVecOff :\ Not my routine 0KLDA &D9F+0,X:CMP usbVector+0,Y:BEQ CheckVecOk :\ My routine, return CS :.CheckVecOff:CLC D.CheckVecOk :RTS N.CheckVector X>LDA &201,X:CMP #&FF:BNE CheckVecOff :\ <&FF - not extended b>LDA &200,X:CMP #&51:BCS CheckVecOff :\ >&50 - not extended l@SEC :\ CS=Vector is extended v.usbKBD_OffOk RTS : .CheckClaimed "JSR CheckVector:BCC CheckVecOk .errBadClaim 3JSR MkError:EQUB 149:EQUS "Vectors claimed":BRK : .usbVector .mseBYTEV:EQUW mse_BYTE .kbdEVNTV:EQUW kbd_EVNT .kbdKEYV :EQUW kbd_KEY .prnUPTV :EQUW prn_UPT : :  #\ *USBKBD - enable USB keyboard #\ -----------------------------  -\ Note, DataCentre doesn't work with hubs *%\ Y= 0=Off, 1+=keyboard type 4\ > .usbKBD HLDA KBDNUM: #&C0 R3CMP #&80:PHP :\ Save result of CMP \1TYA: #63:BNE usbKBD_On :\ Claim USB keyboard f5PLP:BNE usbKBD_OffOk :\ Keyboard not claimed pDPHP:SEI:LDX #1 :\ Disable IRQs while changing vectors z.usbKBD_OffLp1 0LDA oldKEYV,X:STA KEYV,X :\ Restore vectors LDA oldEVNTV,X:STA EVNTV,X .LDA &FFB7,X:STA &A8,X :\ Also get VEC DEX:BPL usbKBD_OffLp1  LDY #&3C .usbKBD_OffLp2 5LDA (&A8),Y:STA &200,Y :\ Reset OSBYTE &AC/&AD INY:INX:BEQ usbKBD_OffLp2 -PLP :\ Restore IRQs 4LDA #13:LDX #4:JMP OSBYTE :\ Disable VSync event \RTS : .usbKBD_On DPLP:BEQ usbKBD_AlreadyOn :\ Already claimed, just change KBDNUM :BCC errBadClaim :\ Somebody else has claimed 5PHA :\ Save keyboard number $6JSR usb_Check:\JSR usb_Flush :\ Check also Flushes ..usbKBD_On2 8%LDX #EVNTV 255:JSR CheckClaimed B$LDX #KEYV 255:JSR CheckClaimed L: VOPT if() `5::LDA #0:STA usb_SC0+2 :\ Default to device 0 j/::LDX #usb_SCS-usb_KbdCmds :\ SCS, IPH, QP2 t::JSR usb_KbdCmd6 ~(::JSR usb_Flush:CMP #&80 :\ Cy=HUB :: #8:BEQ usb_NoKbd 8::BCS usb_KbdInitLp1a :\ HUB, start at device 1 ::.usb_KbdInitLp1 *::LDX #usb_SC0-usb_KbdCmds :\ SC0, DRD ::JSR usb_KbdCmd6 +::JSR usb_Flush:CMP #8:BEQ usb_KbdInit2 ::.usb_KbdInitLp1a !::INC usb_SC0+2:LDA usb_SC0+2 .::CMP #13:BNE usb_KbdInitLp1:BEQ usb_NoKbd .kbd_Init0 OPT endif : JSR usb_Sync  .kbd_Init1 JSR usb_Flush .LDX #usb_SCS-usb_KbdCmds :\ SCS, IPH, QP2 (JSR usb_KbdCmd6 2, #8:BEQ usb_NoKbd :\ No HID, error <\JSR usb_Sync F*\LDX #usb_SC0-usb_KbdCmds :\ SC0, DRD P\JSR usb_KbdCmd6 Z:JSR usb_KbdCmdDRDSync :\ Returns with MI+EQ from A dABEQ kbd_Init1 :\ Keep going until we get a packet n5CMP #8:BEQ usb_KbdInit2 :\ Keyboard data packet x.usb_NoKbd /JSR MkError:EQUB 214:EQUS "No keyboard":BRK : .usb_KbdInit2 2JSR usbPRINT_Off :\ Force printer off 0JSR usbMOUSE_Off :\ Force mouse off DPHP:SEI:LDX #1 :\ Disable IRQs while changing vectors .usbKBD_InitLp3 $\ This could become a subroutine  LDA KEYV,X :STA oldKEYV,X !LDA EVNTV,X :STA oldEVNTV,X LDA kbdKEYV,X :STA XKEYV,X LDA kbdEVNTV,X:STA XEVNTV,X DEX:BPL usbKBD_InitLp3  LDY &F4 1LDA #&30:STA EVNTV+0:STX EVNTV+1:STY XEVNTV+2 0LDA #&3C:STA KEYV+0 :STX KEYV+1 :STY XKEYV+2 "GPLP:PLA :\ Restore IRQs, get keyboard number back ,5LDX #0:STX LASTK :\ No key being pressed 6: @.usbKBD_AlreadyOn J3A #&80:STA KBDNUM :\ Set keyboard number T3LDA #14:LDX #4:JMP OSBYTE :\ Enable VSync event ^: h .kbd_KEY r/BVS jmpKEYV :\ Interupt, pass on |-BIT KBDMOD :\ M=Ctrl, V=Shift (PHP:PLA :\ A=CSxxxxxx 1BCC kbd_TEST :\ Test for CTRL+SHIFT 6CPX #&81:BEQ kbd_INKEY :\ -CTRL, will also set CS (ASL A :\ A=Sxxxxxxx 7CPX #&80:BEQ kbd_INKEY :\ -SHIFT, will also set CS 8ASL A:ASL A:ASL A:ASL A :\ A=gasc0000 H5A &FA: #&F0 :\ A=GASC0000 R>ASL A:ASL A:ROL A :\ A=C000000A, Cy=S \RBCC P%+4:A #&40 :\ A=CS00000A, b7=ctrl, b6=shift, b0=alt f>STA KBDMOD :\ Update modifiers pCCPX LASTK:BEQ kbd_repeat :\ Same key pressed down z@STX LASTK :\ New or no keypress KLDA &254:STA &E7 :\ Copy KeyDelay to KeyCountdown : \ Process keypress in X .kbd_keypress  2 GASL A:ASL A:ASL A:STA &FB :\ Offset into nonalpha keys 9TXA:JSR kbd_convert:BCS kbd_exit :\ No keypress 6TAY: &26C:BNE kbd_insert :\ Not Escape ?STA &E7 :\ Cancel autorepeat .kbd_insert  LDX #3  .kbd_save DLDA &EE,X:PHA:DEX:BNE kbd_save :\ Save OSBYTE parameters KLDA #153:JSR OSBYTE:LDX #&FD :\ Insert with Escape processing .kbd_restore $GPLA:STA &F2,X:INX:BNE kbd_restore :\ Restore OSBYTE parameters . .kbd_exit 8RTS B: L.kbd_repeat V=LDA &E7:BEQ kbd_exit :\ Repeat disabled `CDEC &E7:BEQ P%+6:DEC &E7:BNE kbd_exit :\ Countdown not reached jLLDA &255:STA &E7 :\ Copy KeyRepeat to KeyCountdown tELDX LASTK:JMP kbd_keypress :\ Insert another keypress ~: (\ Convert keypress to character code .kbd_convert CLDX KBDMOD:STX &FA :\ Get current modifiers MCMP #&48:BNE kbd_notbreak :\ BREAK keynum KBDNUM LBIT KBDNUM :\ test %01001000 %10xxQxxx EBNE kbd_notbreak :\ BREAK is II %00001000 AASL &FA:ADC #&B8:ASL A :\ Convert CTRL to 0/2 GJMP ForceReset :\ BREAK is RESET %00000000 .kbd_notbreak CMP #&39:BNE kbd_notcaps 0LDA &25A: #16:STA &25A:RTS :\ CAPS .kbd_notcaps BSEC:SBC #4:BPL kbd_test:SBC #&1F :\ Reduce range if &84+  .kbd_test 9CMP #&69:BCS kbd_exit :\ No keypress 0ADC #"A":CMP #"[":BCC kbd_alpha1 :\ Letter (1SBC #42:CMP #"9"+1:BCC kbd_nonalpha :\ Digit 2;SBC #26:CMP #39:BCC kbd_lookup :\ offset 32..37 <8SBC #08:CMP #39:BCS kbd_lookup :\ offset 38+ F@SBC #30:A &FB :\ offset 0-31 symbols P.kbd_lookup ZTAX:LDA kbd_keytable,X d1BNE kbd_nottab:LDA &26B :\ TAB n.kbd_nottab x5CMP #"!":BCC kbd_exit :\ ctrls+spc ACMP #127:BEQ kbd_done:BCS kbd_topset :\ DEL and topbit keys ACPX #&59:BEQ kbd_nonalpha :\ Special case JP '\' 7CMP #"_":BCS kbd_nonalpha :\ &5F and &60 ?_!"""+"#$%&'()*+_+>`" :\ 0=JP/BBC/ECMA D=EQUS "~!@~$%&"""+"()*+<_>?)!@" +"#$%^&*(*:<+>?" :\ 1=US N=EQUS "~!@~$%&@" +"()*+<_>?)!"""+"`$%^&*(*:<+>?" :\ 2=UK X=\EQUS "~!@~$%&@" +"()*+<_>?)!"""+"`$%^&*(*+<+>?" :\ 3=EU b4\ Shift+ !"#$%&' ()*+,-./012 3456789c;<=>? l4\ @ABCDEFG HIJKLMNOPQR STUVWXYZ[\]^_ v3\ `abcdefg hijklmnopqr stuvwxyz{|}~ \ .kbd_keytable $EQUS "^@[\];:_" :\ 0=JP/BBC/ECMA EQUS "=[]\#;'`" :\ 1=US EQUS "=[]\#;'`" :\ 2=UK \ ===================== !H\ Force a machine RESET !R\ ===================== !\ .cmdReset !fTYA:BEQ synReset !pJSR ScanDec !z0LDY #0:BCS P%+3:TAY :\ Default to 0 !2LDX #253:LDA #163:JMP OSBYTE :\ Pass to OSBYTE ! .synReset !,JSR PrText:EQUS "()":EQUB 13:EQUB 0 !RTS !: !.ForceReset !\ A=RESET type !\ 0=Soft Break !\ 1=Power On !\ 2=Hard Break !: !DSEI:CLD :\ Disable IRQs, ensure binary mode !@LDX #&FF:TXS:PHA :\ Reset stack, save Break type "LDA #&8F:LDX #&0C ".LDY #&FF:JSR OSBYTE :\ Claim NMIs "0LDX #&40:STX &0D00 :\ Disable NMIs "$5LDA #0:JSR OSBYTE :\ Read machine type ".5LDA &FFFC:STA &A8 :\ &A8/9=>RESET code "8LDA &FFFD:STA &A9 "B8TXA:BEQ ResetElk :\ Jump if &00=Electron "L: "V2LDA #&C0:STA &FEA0 :\ Reset hardware "`.LDA #&A0:STA &FEE0 :\ Tube Reset "j6LDA #&20:STA &FEE0 :\ Release Tube Reset "t.PLA:BEQ ResetJump :\ Soft Break "~8LSR A:BCC ResetHard :\ Hard Reset is fiddly "4LDA #127:STA &FE4E :\ Reset system VIA ".ResetJump "4JMP (&FFFC) :\ Enter RESET code ": " .ResetElk ";LDA #&C0:STA &FC28 :\ Reset Electron hardware "7LDA #&A0:STA &FCE0 :\ Electron Tube Reset "?LDA #&20:STA &FCE0 :\ Release Electron Tube Reset ".PLA:BEQ ResetJump :\ Soft Break ".LDY #24:LSR A:BCS ResetElkJump :\ Power On ".TAY:DEX :\ Y=0, X=&FF ".ResetElkHard #LDA (&A8),Y:INY # 0CMP #&20:BNE ResetElkHard :\ Look for JSR #INY:INY:LDA (&A8),Y #0CMP #&08:BNE ResetElkHard :\ Look for PHP #(.ResetElkJump #2ELDA &F4:A #&F0:STA &FE05 :\ Set up the ULA, set M=Ctrl Pressed #continuation of reset code $TGSEC:LDA #2:JMP (&A8) :\ CS=CTRL pressed, jump to RESET code $^: $h.ResetMaster $r LDY #0 $|.ResetMasterLp1 $0LDA (&A8),Y:INY :\ Look for JSR $CMP #&20:BNE ResetMasterLp1 $INY:LDA (&A8),Y:STA &F6 :\ (F6)=>reset code in ROM 15 $INY:LDA (&A8),Y:STA &F7 $.ResetMasterLp2 $9JSR ResetROMByte :\ Read byte from ROM 15 $2CMP #&E0:BNE ResetMasterLp2 :\ Look for 'CPX' $>JSR ResetROMByte :\ Read next byte from ROM 15 $7CMP #&80:BNE ResetMasterLp2 :\ Look for 'CPX #&80' $,\ &F6/7 now points to rest of RESET code $: %?LDA #&53:STA &FE8E :\ Write to hardware I/O RESET %:TRB &0366 :\ Reset 23,16 settings %:LDX #&FF:STX &FE63 :\ User VIA Port A=output %&>LDA #&CF:STA &FE42 :\ System VIA Port B=ooiioooo %07LDA #&0D:STA &DC00 :\ Command line = %:9LDA #&DC:STA &DF05:STZ &DF04 :\ Point to command line %D1STZ &DFDD :\ Clear * flag %N)LDX #(ResetCodeEnd-ResetCode-1) &FF %X.ResetLoop %bLDA ResetCode,X:STA &100,X %l/DEX:BPL ResetLoop:TXS :\ Reset stack %vELDA &F7: #&40 :\ Test if code is in SROM or I/O area %CSTA &FE34:STA &FC :\ Set memory map according to &F7 %LLDA #&0F:STA &028E :\ Set keypad SHIFT setting, prepare ROM=15 %IPHA:SEC:JMP &100 :\ Push <>0=Not PowerOn, CS=CTRL pressed %: %.ResetCode %BSTA &FE30 :\ Page in MOS ROM (IRQs are off) %6JMP (&F6) :\ Jump to RESET code %.ResetCodeEnd %: %.ResetROMByte %2LDA #&40:STA &FE34 :\ Set memory map %6LDA (&F6) :\ Read byte manually %:BIT &F7:BVS ResetByte :\ Exit if in high memory &9LDY #&0F:JSR &FFB9 :\ Read byte from ROM 15 & .ResetByte &5INC &F6:BNE P%+4:INC &F7 :\ Increment address & RTS &*: &4: &>(\ *USBPRINT | - enable USB printer &H+\ ------------------------------------- &R\ Y= 0 - Off, <>0 - On &\\ &f.usbPRINT_Off &p:LDY #0 :\ Ensure USBPRINT is off &z .usbPRINT & TYA:PHA &SEC:JSR StatusRead &3PLA:BNE usbPRINT_On :\ <>0, USBPRINT &:TYA:BPL usbPRN_OffOk :\ Already off, just exit &GPHP:SEI:LDX #1 :\ Disable IRQs while changing vectors &.usbPRN_OffLp1 &3LDA oldUPTV,X:STA UPTV,X :\ Restore vectors &DEX:BPL usbPRN_OffLp1 &PLP &.usbPRN_OffOk &RTS &: &.errAlreadyUSB '6JSR MkError:EQUB 194:EQUS "USB already in use":BRK ': '.usbPRINT_On '$SEC:JSR StatusRead '.TYA:BMI usbPRN_AlreadyOn '8 #127:BNE errAlreadyUSB 'B$LDX #UPTV 255:JSR CheckClaimed 'LJSR usb_Check 'V: '`\.usbPRN_Init2 'jGPHP:SEI:LDX #1 :\ Disable IRQs while changing vectors 't.usbPRN_InitLp3 '~LDA UPTV,X :STA oldUPTV,X 'LDA prnUPTV,X:STA XUPTV,X 'DEX:BPL usbPRN_InitLp3 ' LDY &F4 '.LDA #&33:STA UPTV+0:STX UPTV+1:STY XUPTV+2 '0PLP :\ Restore IRQs '.usbPRN_AlreadyOn '2LDA #5:LDX #13:JMP OSBYTE :\ Select printer ': ': '\ USER ER DRIVER '\ =================== ' .prn_UPT (9CPY #USBPRN:BNE NotMyPrinter :\ Respond to printer 13 ( 8CMP #3:CLC:BEQ PrintFlush :\ 3, CC=flush output (9CMP #1:BNE NotMyAction :\ Not character written (2: :\ CS=don't flush ((.PrintFlush (25PHP :\ Save CC=print all (<255 bytes, print some (P9CPX #48:BCS PrintSome :\ >47 bytes, print some (Z@PLP:BCC PrintBuff :\ End of job, print all so far (d=RTS :\ <48 bytes, return with CS (n.PrintSome (x7LDX #48:PLP :\ Print 48 characters (: (.PrintBuff (\ Print buffered characters (!\ X=number of bytes in buffer (: (4TXA:BEQ PrintDone :\ Nothing to print ('LDA #&10:JSR usb_Cmd :\ SCS ('LDA #&91:JSR usb_Cmd :\ IPH (-LDA #&83:JSR usb_CmdX :\ DSD,count (: ( .PrintLp ( TXA:PHA (,LDX #3:CLV:JSR CallREMV :\ A=Y=byte )JSR usb_Wr );PLA:TAX:DEX:BNE PrintLp :\ Loop for all characters ).PrintDone )"3SEC :\ Printer dormant ),.NotMyAction )6RTS )@.NotMyPrinter )JJMP (oldUPTV) )T .CallCNPV )^JMP (CNPV) )h .CallREMV )rJMP (RemV) )|: ): )&\ *USBMOUSE | - enable USB mouse ))\ ----------------------------------- )\ Y= 0 - Off, <>0 - On )\ ).usbMOUSE_Off ):LDY #0 :\ Ensure USBMOUSE is off ) .usbMOUSE ) TYA:PHA )SEC:JSR StatusRead )3PLA:BNE usbMOUSE_On :\ <>0, USBPRINT ):TYA:ASL A:BPL usbMSE_OffOk :\ Already off, just exit )GPHP:SEI:LDX #1 :\ Disable IRQs while changing vectors *.usbMSE_OffLp1 *3LDA oldBYTEV,X:STA BYTEV,X :\ Restore vectors *DEX:BPL usbMSE_OffLp1 *&PLP *0.usbMSE_OffOk *:RTS *D: *N.usbMOUSE_On *X"TYA:ASL A:BMI usbMSE_AlreadyOn *b+ROR A: #&BF:BEQ P%+5:JMP errAlreadyUSB *l%LDX #BYTEV 255:JSR CheckClaimed *vJSR usb_Check *: *GPHP:SEI:LDX #1 :\ Disable IRQs while changing vectors *.usbMSE_InitLp3 *!LDA BYTEV,X :STA oldBYTEV,X *LDA mseBYTEV,X:STA XBYTEV,X *DEX:BPL usbMSE_InitLp3 * LDY &F4 *1LDA #&0F:STA BYTEV+0:STX BYTEV+1:STY XBYTEV+2 *0PLP :\ Restore IRQs *.usbMSE_AlreadyOn * LDX #5 *.usbMSE_InitPosn *7TXA: #1:ASL A:STA MSEPOSN,X :\ Initialise position +DEX:BPL usbMSE_InitPosn + 4SEC:ROR MSEPOSN+0 :\ X=&280, Y=&200 +1INX:STX MSEKEYS:RTS :\ Buttons=&00 + : +* .mse_BYTE +4"CMP #&80:BEQ mseRdPosn :\ +>"CMP #&81:BEQ mseRdButtons :\ +H .jmpBYTEV +RJMP (oldBYTEV) +\.mseRdPosn +f CPX #7:BCC jmpBYTEV :\ <7 +p!CPX #11:BCS jmpBYTEV :\ >10 +zPHP:PHA:SEI +CPX #9:BNE P%+4:LDX #0 +ACPX #10:BNE P%+3:DEX :\ Offset into POSN or zero for buttons +L%:"Code overrun": .="4647",pass%+1,1) .: /sm_table /Bbase80%=mcode%+mclen%:base81%=mcode%:byte%=0:count%=0:off%=0: /Tbyte80%=base80%?off%:byte81%=base81%?off%: off%>=mclen%:byte80%=&80:byte81%=&80 /&] ((byte81%-byte80%) &FE)<>0 "ERROR: Offset by more than one page at &";~&8000+off% /0M (byte80% &C0)=&80:byte%=byte%2+128*(byte81%-byte80%):count%=count%+1 /:1 count%=8:?O%=byte%:O%=O%+1:byte%=0:count%=0 /D(off%=off%+1:off%>=mclen% count%=0 /N