10 REM > ROMCMD/src
   20 REM Command hander for Command/Help/Status/Config
   30 REM by J.G.Harston
   40 :
   50 kbd%=3
   60 OSBYTE=&FFF4:OSARGS=&FFDA
   70 OSASCI=&FFE3:OSNEWL=&FFE7:OSWRCH=&FFEE
   80 EVNTV=&220:KEYV=&228:INSV=&22A
   90 usb_D=&FCF8:usb_S=&FCF9
  100 DIM mcode% &1000, L%-1
  110 ver$="0.01":date$=" (28 May 2018)"
  120 :
  130 FOR pass%=0 TO 1
  140   P%=&8000:O%=mcode%
  150   opt%=pass%*3+4
  160   [OPT opt%
  170   .rombase
  180   EQUB &00:EQUW RelocTable
  190   JMP Service
  200   EQUB &82:EQUB copyright-rombase
  210   .ROMTitle
  220   EQUB VALver$:EQUS "USB Support"
  230   EQUB &00:EQUS ver$+date$
  240   .copyright
  250   EQUB &00:EQUS "(C)J.G.Harston"
  260   EQUB &00
  270   :
  280   .Service
  290   PHA                             :\ Save service number
  300   CMP #&04:BNE P%+5:JMP ServCmd04 :\ *command
  310   CMP #&09:BNE P%+5:JMP ServCmd09 :\ *help
  320   CMP #&28:BNE P%+5:JMP ServCmd28 :\ *configure
  330   CMP #&29:BNE P%+5:JMP ServCmd29 :\ *status
  340   PLA:RTS
  350   :
  360   .ServCmd04:.ServCmd09
  370   LSR A                           :\ Convert service call number to bitmap
  380   .ServCmd28:.ServCmd29
  390   PHA
  400   \ 04 -> 02 -> 02 command   xxxx0010
  410   \ 09 -> 04 -> 04 help      xxxx0100
  420   \ 28 -> 28 -> 08 config    xxxx1000
  430   \ 29 -> 29 -> 09 status    xxxx1001
  440   \
  450   LDX #0                         :\ Point to start of table
  460   STX &F5                        :\ And set command number 0
  470   LDA (&F2),Y                    :\ Get first character
  480   CMP #&0D:BEQ ServCmdNull       :\ *help<cr>, *status<cr>, *configure<cr>
  490   CMP #&2E:BEQ ServCmdNull       :\ *help .    *status .    *configure .
  500   :
  510   .ServCmdEntryLp
  520   INC &F5                        :\ Increment command number
  530   PLA:PHA                        :\ Get search type bitmap
  540   AND CmdTable,X:BEQ ServCmdSkip :\ Don't match for this call
  550   INX                            :\ Point to start of command string
  560   TYA:PHA                        :\ Save line pointer
  570   :
  580   .ServCmdCharLp
  590   LDA (&F2),Y
  600   CMP #ASC".":BEQ ServCmdDot     :\ Abbreviation
  610   AND #&5F                       :\ Force to upper case
  620   CMP CmdTable,X:BNE ServCmdNext :\ No match, skip to next command
  630   INX:INY                        :\ Step to next characters
  640   LDA CmdTable,X
  650   BPL ServCmdCharLp              :\ Not end of table entry, loop back
  660   LDA (&F2),Y
  670   CMP #ASC"A":BCC ServCmdMatch   :\ End of command string, command matches
  680   .ServCmdNext
  690   PLA:TAY                        :\ Restore line pointer
  700   DEX                            :\ In case we are pointing to last+1 character
  710   .ServCmdSkip
  720   INX:LDA CmdTable,X
  730   BPL ServCmdSkip                :\ Step to next entry
  740   AND #15:BNE ServCmdEntryLp     :\ Not at end, check next entry
  750   PLA                            :\ Drop command type
  760   PLA:RTS                        :\ Restore and return unclaimed
  770   :
  780   .ServCmdDot
  790   .ServCmdSkipSpc
  800   INY                            :\ Step past dot
  810   .ServCmdMatch
  820   LDA (&F2),Y:CMP #ASC" "
  830   BEQ ServCmdSkipSpc             :\ And step past any spaces
  840   PLA                            :\ Drop old line pointer
  850   TSX:LDA #0:STA &102,X          :\ Claim this call
  860   .ServCmdNull
  870   LDA &F5:ASL A:TAX              :\ X=command offset, Carry Clear
  880   .ServCmdDispatch
  890   LDA CmdDispatch+1,X:STA &F7
  900   LDA CmdDispatch+0,X:STA &F6
  910   PLA:TAX:EOR #1:ADC #&D8:CMP #&01 :\ Convert command type, CC=Status
  920   JSR JumpF6
  930   PLA:RTS                        :\ Return claimed or unclaimed
  940   :
  950   \ On entry,
  960   \ Flags set from A:
  970   \  EQ = Status
  980   \  PL = Status/Configure
  990   \  MI = Help/Command
 1000   \ (&F2),Y=>command line
 1010   \ X=command type
 1020   \
 1030   .JumpF6
 1040   JMP (&F6)
 1050   .ServCallStatus
 1060   PHA:PHA:CLC                    :\ Push command type onto stack
 1070   JMP ServCmdDispatch            :\ Jump to call *Status routines
 1080   :
 1090   .cmdUSB                        :\ *Help USB
 1100   DEY
 1110   .cmdNull
 1120   CPX #4:BNE cmdHelp:JSR OSNEWL
 1130   .cmdTitleLp
 1140   LDA ROMTitle-3,X:BNE P%+4:LDA #ASC" "
 1150   CMP #ASC"(":BEQ cmdTitleDone   :\ Print ROM title
 1160   JSR OSWRCH:INX:BNE cmdTitleLp
 1170   .cmdTitleDone
 1180   JSR OSNEWL:LDX #2              :\ X=2 - list commands
 1190   LDA (&F2),Y:CMP #13:BNE cmdHelp
 1200   RTS                            :\ No parameter, only display ROM title
 1210   .cmdHelp
 1220   TYA:PHA:TXA:PHA                :\ Save Y=lineptr, X=command bitmap
 1230   LDX #0:LDY #0                  :\ Point to start of tables
 1240   .cmdHelpLp1
 1250   INY:INY                        :\ Step to next dispatch entry
 1260   PLA:PHA                        :\ Get search type bitmap
 1270   AND CmdTable,X:BEQ cmdHelpSkip :\ Don't match for this call
 1280   AND #2:BEQ cmdHelpLp2
 1290   JSR Pr2Spaces                  :\ Indent *Help list
 1300   .cmdHelpLp2
 1310   LDA CmdTable+1,X:BMI cmdHelpInfo
 1320   JSR OSWRCH:INX:BNE cmdHelpLp2
 1330   .cmdHelpInfo
 1340   TXA:PHA:TYA:PHA                :\ Save table index and command number
 1350   TSX:LDA &103,X:AND #2:ASL A    :\ Align syntax strings
 1360   ADC &308:ADC #10:SBC &318:TAX
 1370   .cmdHelpSpace
 1380   JSR PrSpace:DEX:BNE cmdHelpSpace
 1390   TSX:TXA:TAY
 1400   LDA &103,Y                     :\ Command type
 1410   LDX &101,Y                     :\ Dispatch table index
 1420   LDY #0:JSR ServCallStatus      :\ Call dispatcher to display info
 1430   PLA:TAY:PLA:TAX                :\ Get command number and index back
 1440   DEX
 1450   .cmdHelpSkip
 1460   .cmdHelpSkipLp
 1470   INX:LDA CmdTable,X
 1480   BPL cmdHelpSkipLp              :\ Step to next entry
 1490   AND #15:BNE cmdHelpLp1         :\ Not at end, check next entry
 1500   PLA:PLA:TAY:RTS
 1510   :
 1520   .CmdTable
 1530   EQUB &84:EQUS "USB"        :\ hlp
 1540   EQUB &82:EQUS "USBDEVICES" :\     cmd
 1550   EQUB &8B:EQUS "USBKBD"     :\     cmd cfg sta
 1560   EQUB &8B:EQUS "USBMOUSE"   :\     cmd cfg sta
 1570   EQUB &8B:EQUS "USBPRINT"   :\     cmd cfg sta
 1580   EQUB &82:EQUS "USBSTATUS"  :\     cmd
 1590   EQUB &80
 1600   :
 1610   .CmdDispatch
 1620   EQUW cmdNull               :\ <cr> or .
 1630   EQUW cmdUSB                :\ USB
 1640   EQUW cmdDevices            :\ USBDEVICES
 1650   EQUW cmdKBD                :\ USBKBD
 1660   EQUW cmdMouse              :\ USBMOUSE
 1670   EQUW cmdPrint              :\ USBPRINT
 1680   EQUW cmdStatus             :\ USBSTATUS
 1690   :
 1700   :
 1710   .cmdPrint :LDX #128:BNE cmdDoIt
 1720   .cmdMouse :LDX #64 :BNE cmdDoIt
 1730   .cmdKBD   :LDX #63
 1740   .cmdDoIt
 1750   BCC cmdStatus2            :\ *Status <command>
 1760   PHA:TYA:BEQ cmdSyntax     :\ Y=0, *help or *config. syntax requested
 1770   LDA (&F2),Y               :\ Save command type, get char from line
 1780   CMP #13:BEQ cmdStatus1    :\ *command<cr> or *configure command<cr>
 1790   JSR ScanOnOffName         :\ Parse parameter OFF|ON|<num> to Y
 1800   PLA:BMI cmdJump           :\ *command <param>
 1810   :
 1820   :                         :\ *Configure <word> <param>
 1830   TYA:PHA                   :\ Save <param>
 1840   TXA:EOR #255:PHA          :\ Mask to keep old bits
 1850   JSR CMOSRead:TSX          :\ Get my CMOS byte
 1860   EOR &102,X:AND &101,X     :\ Merge new setting into byte
 1870   EOR &102,X:TAY
 1880   PLA:PLA                   :\ Drop stacked bytes
 1890   :
 1900   .CMOSWrite                :\ Write my CMOS byte
 1910   LDX #19:LDA #162:JMP OSBYTE
 1920   .CMOSRead                 :\ Read my CMOS byte
 1930   CLC
 1940   .CMOSRead1
 1950   :\LDA &23D:\AND #&C0:\EOR #&80 :\ If keyboard not claimed, use 0
 1960   :\TAY:\BEQ P%+5                :\ else use current setting
 1970   LDY &23C:BCS CMOSRead2     :\ If CS or no CMOS, use current setting
 1980   LDX #19:LDA #161:JSR OSBYTE
 1990   .CMOSRead2
 2000   TYA:RTS
 2010   :
 2020   .cmdJump
 2030   TXA:ASL A
 2040   BCC P%+5:JMP usbPRINT
 2050   BPL P%+5:JMP usbMOUSE
 2060   JMP usbKBD
 2070   :
 2080   .cmdSyntax
 2090   PLA:CPX #64:BCS cmdSyntax2
 2100   JSR PrText:EQUS "OFF|<num>":EQUB 13:EQUB 0:RTS
 2110   .cmdSyntax2
 2120   JSR PrText:EQUS "OFF|ON":EQUB 13:EQUB 0:RTS
 2130   :
 2140   .errBadConfigure
 2150   JSR MkError
 2160   EQUB 254:EQUS "Bad command":BRK
 2170   :
 2180   .cmdStatus1                :\ *command<cr> or *configure command<cr>
 2190   PLA:BPL errBadConfigure    :\ *configure command<cr>
 2200   .cmdStatus2                :\ *Status <command>
 2210   TXA:PHA                    :\ Save parameter bitmap
 2220   JSR CMOSRead1:TSX          :\ Get CMOS or current setting
 2230   AND &101,X:TAY:PLA         :\ Y=value, A=mask
 2240   CMP #64:BCS PrOnOffEtc     :\ mask=64 or 128, OFF/ON
 2250   TYA:JSR PrDec:JSR PrSpace  :\ Print decimal value
 2260   .PrOnOffEtc
 2270   TYA:LDX #&FF               :\ Look for matching entry
 2280   .PrOnOffLp1
 2290   INX
 2300   CMP txtNames,X:BEQ PrOnOffLp2  :\ Matched entry prefix
 2310   LDY txtNames,X:BPL PrOnOffLp1  :\ End of table
 2320   .PrOnOffDone
 2330   JMP OSNEWL
 2340   .PrOnOffLp2
 2350   LDA txtNames+1,X:AND #127
 2360   CMP #ASC"A":BCC PrOnOffDone
 2370   JSR OSWRCH:INX:BNE PrOnOffLp2
 2380   :
 2390   .txtNames
 2400   EQUB 0:EQUS "OFF"
 2410   EQUB 1:EQUS "UK"
 2420   EQUB 2:EQUS "BBC"
 2430   EQUB 32:EQUS "Japan"
 2440   EQUB 48:EQUS "USA"
 2450   EQUB 64:EQUS "ON"
 2460   EQUB 128:EQUS "ON"
 2470   EQUB 0
 2480   :
 2490   :
 2500   .cmdDevices                :\ USBDEVICES
 2510   DEX
 2520   .cmdStatus                 :\ USBSTATUS
 2530   TYA:BNE x:JMP OSNEWL
 2540   .usbKBD                    :\ USBKBD <num>
 2550   .usbMOUSE                  :\ USBMOUSE ON|OFF
 2560   .usbPRINT                  :\ USBPRINT ON|OFF
 2570   \
 2580   .x
 2590   JSR PrHex:JSR PrSpace     :\ debug, command type
 2600   TXA:JSR PrHex:JSR PrSpace :\ debug, command number
 2610   TYA:JSR PrHex:JMP OSNEWL  :\ debug, line pointer
 2620   :
 2630   
 2640   
 2650   
 2660   
 2670   \ (&F2),Y=> OFF|<dec>|OFF
 2680   \ Returns Y=0 | 0-255 | 255
 2690   .ScanOnOffName
 2700   LDA (&F2),Y:AND #&DF
 2710   CMP #ASC"O":BNE ScanOnOffNum
 2720   INY:LDA (&F2),Y:AND #&DF
 2730   LDY #0:CMP #ASC"F":BEQ ScanOnOffDone
 2740   DEY:CMP #ASC"N":BEQ ScanOnOffDone
 2750   JMP errBadNumber
 2760   .ScanOnOffNum
 2770   JSR ScanDec:TAY
 2780   .ScanOnOffDone
 2790   RTS
 2800   :
 2810   :
 2820   .PrDec
 2830   TAX:LDA #&99               :\ Move value to X, start at -1 in BCD
 2840   SED                        :\ Switch to decimal arithmetic
 2850   .PrDecLp
 2860   CLC:ADC #1                 :\ Add one in BCD mode
 2870   DEX:BPL PrDecLp            :\ Loop for all of source number
 2880   CLD                        :\ Switch back to binary arithmetic
 2890   CMP #10:BCC PrNyb          :\ If <10, print single digit
 2900   \ Fall through into PrHex
 2910   :
 2920   .PrHex
 2930   PHA:LSR A:LSR A:LSR A:LSR A
 2940   JSR PrNyb:PLA
 2950   .PrNyb
 2960   AND #15:CMP #10:BCC PrDig:ADC #6
 2970   .PrDig
 2980   ADC #ASC"0":JMP OSWRCH
 2990   :
 3000   .PrText
 3010   PLA:STA &F6:PLA:STA &F7     :\ Pop address after JSR
 3020   TYA:PHA                     :\ Save Y
 3030   LDA #&FF:BNE PrTextNext     :\ Jump into loop
 3040   .PrTextLp
 3050   LDY #0:LDA (&F6),Y          :\ Get character
 3060   BEQ PrTextNext:JSR OSASCI   :\ Print if not zero
 3070   .PrTextNext
 3080   INC &F6:BNE P%+4:INC &F7    :\ Update address
 3090   TAY:BNE PrTextLp            :\ Loop back if not &00
 3100   PLA:TAY:LDA #0:JMP (&F6)    :\ Restore Y and return to code
 3110   :
 3120   .Pr2Spaces
 3130   JSR PrSpace
 3140   .PrSpace
 3150   LDA #ASC" ":JMP OSWRCH
 3160   :
 3170   :
 3180   .ScanDec
 3190   JSR ScanChkDigit          :\ Get current digit
 3200   BCS ScanDecExit           :\ Nothing to scan
 3210   .ScanDecLp
 3220   STA &F5                   :\ Store as current number
 3230   JSR ScanChkDigit          :\ Get current digit
 3240   BCS ScanDecDone           :\ No more digits
 3250   PHA:LDA &F5               :\ Save current digit
 3260   CMP #26:BCS ScanDecTooBig :\ If num>25, will overflow
 3270   ASL A:ASL A:ADC &F5:ASL A :\ num=num*10
 3280   STA &F5:PLA               :\ Get current digit back
 3290   ADC &F5:BCC ScanDecLp     :\ num=num*10+digit
 3300   .ScanDecTooBig
 3310   .errBadNumber
 3320   JSR MkError
 3330   EQUB 252:EQUS "Bad number":BRK
 3340   .ScanDecDone
 3350   LDA &F5:CLC               :\ CC=valid number scanned
 3360   .ScanDecExit              :\ CS=bad number or digit
 3370   RTS
 3380   :
 3390   .ScanChkDigit
 3400   LDA (&F2),Y                   :\ Get current character
 3410   CMP #ASC"0":BCC ScanDecErr    :\ <'0'
 3420   CMP #ASC"9"+1:BCS ScanDecErr  :\ >'9'
 3430   INY:AND #15:RTS               :\ Convert character to binary
 3440   .ScanDecErr
 3450   SEC:RTS                       :\ CS=invalid digit
 3460   :
 3470   :
 3480   .MkError
 3490   PLA:STA &FD:PLA:STA &FE      :\ Pop address after JSR
 3500   LDY #0                       :\ Index into the error block
 3510   .MkErrorLp
 3520   INY:LDA (&FD),Y:STA &100,Y   :\ Copy error block to stack
 3530   BNE MkErrorLp                :\ Loop until terminating &00 byte
 3540   STA &100:JMP &100            :\ Store &00 as BRK and jump to it
 3550   :
 3560   :
 3570   
 3580   .RelocTable
 3590 ]:NEXT
 3600 PRINT"*Save ROMCMD ";~(mcode%);" ";~O%;" FFFF0000 FFFBBC00"
 3610 END
 3620 :