--- /dev/null
+// 11.0592MHz=>921600 T0 clk=>112.5 ops=2.27`5s time
+// Code is big-endian!
+public BaudRate equ 2400 // Communication speed
+public StackSiz51 equ 24 // LaserGun stack size required
+ MagicRAMw equ 0x53AC // RAM-check
+ TestChar equ 't' // For Ph_Test
+
+MaxDecimal equ 99 // If dec>99
+BauDiv equ 28800/BaudRate // 3=9600, 6=4800, 12=2400 (PCON=0)
+
+/*
+Init display:
+Pn-Player ID
+Gx-Game mode: A=Anarchy, G=Green team, R=Red team
+Display:
+Lt-Loading
+Fn-Shot from friend detected
+En-Shot from enemy detected but already dead
+Sn-Shot down by enemy
+dt-Currently dead
+Left dot-reloading
+Right dot-dead
+*/
+
+/******************************/
+ seg data
+ org 0x00
+DataStart:
+ rb 4 // r0-r3
+#define DispL r4
+#define DispR r5
+#define Timer r6
+#define XMitPhase r7
+ // 0='s';1=PktType;2=SwConfigX;3=PktData;4=XSumH;5=XSumL;6='e'
+ rb 4
+
+TimPhase: rb 1 // Timer for current phase
+TimLED4: rb 1 // 4-LED period
+TimScroll: rb 1 // Scroll advance to next char
+
+ ScrollPtr: rb 1 // Scroll-text start rel. ScrBase
+ SeriCnt: rb 1 // Shots in current series
+ CAPktEnd: rb 1 // End of ConfigReq being answered (or 0)
+ WDogCnt: rb 1 // WatchDog timer count-down
+ Phase: rb 1 // Current phase # (see below)
+Ph_CfgDump equ 0 // Configuration to display dump [Phase1=sub-phase]
+Ph_Ammo equ 1 // Normal Ammo display
+Ph_Laser equ 2 // Laser on
+Ph_Delay equ 3 // Laser off, laser button disabled
+Ph_First equ 4 // Additional first-in-series delay
+ // Laser allowed boundary
+Ph_Reload equ 5 // Reload countdown period [Phase1=cdown]
+Ph_Dead equ 6 // Dead-state countdown period [Phase1=cdown]
+Ph_Test equ 7 // Test mode with transmit/receive of 'T'
+ Phase1: rb 1 // Sub-phase
+// Ph_CfgDump:
+CD_Bootup equ 0 // Right after boot-up
+CD_PNum equ 1 // Player no. (P#)
+CD_GMode equ 2 // Game mode (G#: Anarchy, Green, Red)
+CD_LEDs equ 3 // BBS_QuietL [Ld]
+CD_Sound equ 4 // BBS_QuietS [Sd]
+CD_WDogs equ 5 // WDogsCnt (dr, TU)
+CD_WDogsN equ 6 // {TU}
+CD_RSwChg equ 7 // RSwChgs (SC, TU)
+CD_RSwChgN equ 8 // {TU}
+CD_TotSh equ 9 // TotShotsW (FS, [TH], TU)
+CD_TotShM equ 10 // {[TH]}
+CD_TotShN equ 11 // {TU}
+CD_Grave0 equ 12 // GraveW #0 (d#, [TH], TU)
+CD_GraveL equ 60 // GraveW #++F(d#, [TH], TU)
+CD_Last equ 60
+// Ph_Reload: Reload cycles countdown
+// Ph_Dead: Dead cycles countdown
+
+ CurPktE: rb 1 // +1 of last L2 packet byte received
+ XMitNib: rb 1 // Transmit-remaining nibble (or 0)
+ PktNibble: rb 1 // Recevied L2 packet hex nibble
+ CurPktS: rb 1 // Addr of size of L2 packet being received
+ UserPktS: rb 1 // Addr of size of 1st L2 packet in user queue
+ TimedL: rb 1 // Left digit of TimedDisp
+ TimedR: rb 1 // Right digit of TimedDisp
+ ConvDecW1: // For use by ConvDecW
+ RxChkXSumW: rw 1 // Computed xsum of incoming L2 packet
+ XMitXSumW: rw 1 // XSum being computed during XMit
+ XMitType: rb 1 // Actual XMit L3 Pkt type - One of PktN_* below
+
+ClearTop:
+
+public TotShotsW: rw 1 // Fire statistics
+public RSwChgs: rb 1 // Run-Time switch configuration change #
+public WDogsCnt: rb 1 // # of gurus-WatchDog restarts since power-on
+
+public SwConfigXA equ $-DataStart // Address of SwConfigX
+ SwConfigX: rb 1 // Copy of SwitchP
+ SysFlagsX: rb 1 // [XMittedN|XMitByte|XMit1stNib|XMitHaveP|TimedDisp|XMitting|PktGotNib|PktRcvng]
+PktRcvng bit SysFlagsX.0 // Currently receiving packet (after 's')
+PktGotNib bit SysFlagsX.1 // Already got one hex nibble in PktNibble
+XMitting bit SysFlagsX.2 // Background packet transmit in progress
+TimedDisp bit SysFlagsX.3 // Generated 2-digit display override
+XMitHaveP bit SysFlagsX.4 // XMitNib is prepared and filled
+XMit1stNib bit SysFlagsX.5 // Transmit 1st nibble from XMitNib
+XMitByte bit SysFlagsX.6 // Transmitting byte instead of two nibbles
+XMittedN bit SysFlagsX.7 // Sth was already xmitted this round
+public UsrFlagsX: rb 1 // [RFU:2|FastFireRD|FullFireT|DisRSwChg|DispDotTR|DispDotRD|UnConfig]
+UnConfig bit UsrFlagsX.0 // Ignore all further configuration attempts
+DispDotRD bit UsrFlagsX.1 // Display LDot & RDot when [R]eload/[D]ead
+DispDotTR bit UsrFlagsX.2 // Display LDot & RDot when [T]ransmit/[R]eceive
+DisRSwChg bit UsrFlagsX.3 // Disable run-time switch reconfiguration
+FullFireT bit UsrFlagsX.4 // Transmit full 10B packets for fires (safer)
+FastFireRD bit UsrFlagsX.5 // Receive disable for FastFires (see FullFireT)
+
+/******************************/
+public Mark_Start equ 's' // L1 layer packet start
+public Mark_End equ 'e' // L1 layer packet end
+public XSum_Base equ 0xB3A7 // L2 packet xsumming base number
+public XSum_Mul equ 13 // L2 packet xsumming advance multiply
+public PktN_Fire equ 'S' // L3 packet ID for fire
+public PktN_CfgR equ 'R' // L3 packet ID for configuration request
+public PktN_CfgA equ 'A' // L3 packet ID for configuration answer
+
+DispP equ P0
+BMD_U equ 0x01
+BMD_UR equ 0x02
+BMD_UL equ 0x04
+BMD_M equ 0x08
+BMD_BR equ 0x10
+BND_DOT equ 5
+BBD_DOT equ DispP.BND_DOT
+BMD_DOT equ 1<<BND_DOT
+BMD_B equ 0x40
+BMD_BL equ 0x80
+
+MiscP equ P1
+BPM_DispR equ P1.0
+BMM_DispR equ 0x01
+BPM_DispL equ P1.1
+BMM_DispL equ 0x02
+BPM_Laser equ P1.2
+BMM_Laser equ 0x04
+BMM_LED0 equ 0x08 // RED ^ - cable up
+BMM_LED1 equ 0x10 // GREEN <
+BMM_LED2 equ 0x20 // RED >
+BNM_LED3 equ 6
+BMM_LED3 equ 1<<BNM_LED3 // GREEN v
+BMM_LEDM equ BMM_LED0|BMM_LED1|BMM_LED2|BMM_LED3
+BPM_Sound equ P1.7
+BMM_Sound equ 0x80
+
+SwitchP equ P2
+BMS_IdentM equ 0x0F // However defined, hard-coded
+BNS_IsTeam equ 4
+BBS_IsTeam equ SwConfigX.BNS_IsTeam
+BNS_TeamN equ 5 // 1=Green
+BBS_TeamN equ SwConfigX.BNS_TeamN
+BBS_QuietL equ SwConfigX.6 // 1=LEDs off
+BBS_QuietS equ SwConfigX.7 // 1=Disable
+
+IfaceP equ P3
+BPI_Fire equ P3.2
+BPI_Status equ P3.4
+
+/******************************/
+Font__ equ low~(0 )
+Font_0 equ low~(0|BMD_U|BMD_UL|BMD_UR |BMD_BL|BMD_BR|BMD_B)
+Font_1 equ low~(0 |BMD_UR |BMD_BR )
+Font_2 equ low~(0|BMD_U |BMD_UR|BMD_M|BMD_BL |BMD_B)
+Font_3 equ low~(0|BMD_U |BMD_UR|BMD_M |BMD_BR|BMD_B)
+Font_4 equ low~(0 |BMD_UL|BMD_UR|BMD_M |BMD_BR )
+Font_5 equ low~(0|BMD_U|BMD_UL |BMD_M |BMD_BR|BMD_B)
+Font_6 equ low~(0|BMD_U|BMD_UL |BMD_M|BMD_BL|BMD_BR|BMD_B)
+Font_7 equ low~(0|BMD_U |BMD_UR |BMD_BR )
+Font_8 equ low~(0|BMD_U|BMD_UL|BMD_UR|BMD_M|BMD_BL|BMD_BR|BMD_B)
+Font_9 equ low~(0|BMD_U|BMD_UL|BMD_UR|BMD_M |BMD_BR|BMD_B)
+Font_A equ low~(0|BMD_U|BMD_UL|BMD_UR|BMD_M|BMD_BL|BMD_BR )
+Font_B equ low~(0 |BMD_UL |BMD_M|BMD_BL|BMD_BR|BMD_B)
+Font_C equ low~(0|BMD_U|BMD_UL |BMD_BL |BMD_B)
+Font_c_ equ low~(0 |BMD_M|BMD_BL |BMD_B)
+Font_D equ low~(0 |BMD_UR|BMD_M|BMD_BL|BMD_BR|BMD_B)
+Font_E equ low~(0|BMD_U|BMD_UL |BMD_M|BMD_BL |BMD_B)
+Font_F equ low~(0|BMD_U|BMD_UL |BMD_M|BMD_BL )
+Font_G equ low~(0|BMD_U|BMD_UL |BMD_BL|BMD_BR|BMD_B)
+Font_H equ low~(0 |BMD_UL|BMD_UR|BMD_M|BMD_BL|BMD_BR )
+Font_I equ low~(0 |BMD_UL |BMD_BL )
+Font_L equ low~(0 |BMD_UL |BMD_BL |BMD_B)
+Font_N equ low~(0 |BMD_M|BMD_BL|BMD_BR )
+Font_O equ low~(0|BMD_U|BMD_UL|BMD_UR |BMD_BL|BMD_BR|BMD_B)
+Font_P equ low~(0|BMD_U|BMD_UL|BMD_UR|BMD_M|BMD_BL )
+Font_R equ low~(0 |BMD_M|BMD_BL )
+Font_S equ low~(0|BMD_U|BMD_UL |BMD_M |BMD_BR|BMD_B)
+Font_T equ low~(0 |BMD_UL |BMD_M|BMD_BL |BMD_B)
+Font_U equ low~(0 |BMD_UL|BMD_UR |BMD_BL|BMD_BR|BMD_B)
+Font_Y equ low~(0 |BMD_UL|BMD_UR|BMD_M |BMD_BR|BMD_B)
+Font_MIN equ low~(0 |BMD_M )
+Font_ equ low~(0|BMD_U|BMD_UL|BMD_UR|BMD_M|BMD_BL|BMD_BR|BMD_B)
+
+/******************************/
+public GraveWA equ $-DataStart // GraveW address
+public GraveW: rw 16 // Kills by players #0..#F
+// Config:
+LoadPart:
+public ReloadN: rb 1 // Reload countdown
+public DeadN: rb 1 // Dead state countdown
+public SeriC_Max: rb 1 // Maximum # of shots per one series
+public Ammo_Max: rb 1 // Ammo # in one clip
+public Ammo: rb 1 // Remaining ammo in the current clip
+public DeadDivN: rb 1 // 4LED-Dead -> Dead cycle divisor
+public T_Start: rb 1 // Startup info cycle delay
+public T_Reload: rb 1 // Reload cycle delay
+public T_Laser: rb 1 // Laser firing
+public T_Delay: rb 1 // Inter-Laser delay
+public T_First: rb 1 // Additional series start delay period
+public T_LED4: rb 1 // 1 of RY-LED switch period
+public T_Scroll: rb 1 // Scroll of one letter
+public T_ScrollF: rb 1 // Scroll of 1st two letters
+public T_Dead: rb 1 // 4LED-Dead (and Dead) cycle delay
+public T_TimedD: rb 1 // TimedDisp delay (temporary, non-scrolling)
+public AddrSpace equ $-DataStart // +1 of remote configurable address space
+LoadPartS equ $-LoadPart
+ MagicRAM: rw 1 // Contains MagicRAMw for RAM-check
+public RxBufSiz equ 0x80+DataStart-$-StackSiz51 // Receive buffer size
+RxBuf: rb RxBufSiz // Receive buffer
+StackBtm: // Start of stack
+
+/******************************/
+ seg code
+
+ org 0x0 // Reset, SUsage=6
+Reset:
+ jb BPI_Fire,BadRAM
+ mov a,#high MagicRAMw
+ xrl a,MagicRAM
+ jnz BadRAM
+ sjmp ResCont
+
+ org 0xB // T0, SUsage=4
+T0Int: push psw
+ push acc
+ inc Timer
+ dec WDogCnt
+ mov a,WDogCnt
+ jnz NWDogFail
+ inc WDogsCnt // Failing!
+WarmBoot: mov r0,#ClearTop-1 // Mustn't reset RAM
+ sjmp ContBoot
+
+NWDogFail: pop acc
+ pop psw
+ reti
+
+ org 0x23 // Ser, SUsage=14
+SerInt: ajmp SerICont
+
+SwRConfig: inc RSwChgs
+ sjmp WarmBoot
+
+ResCont: mov a,#low MagicRAMw
+ xrl a,MagicRAM+1
+ jz SwRConfig
+BadRAM: mov MagicRAM,#high MagicRAMw
+ mov MagicRAM+1,#low MagicRAMw
+ mov r0,#LoadPart
+ mov dptr,#LoadContn
+ mov r2,#LoadPartS
+FillMem: clr a
+ movc a,@a+dptr
+ mov @r0,a
+ inc r0
+ inc dptr
+ djnz r2,FillMem
+ColdBoot: mov r0,#LoadPart-1
+
+ContBoot: clr a
+ mov IE,a
+ mov TCON,a
+ mov sp,#StackBtm-1
+
+ClearMem: mov @r0,a
+ djnz r0,ClearMem
+
+ mov SwConfigX,SwitchP
+ mov SysFlagsX,a
+
+ mov Timer,#1
+ mov CurPktS,#RxBuf
+ mov UserPktS,#RxBuf
+
+ mov DispP,a
+ jb BPI_Fire,0f
+ mov MiscP,#~(BMM_DispL|BMM_DispR)
+ jnb BPI_Fire,$
+ mov a,SwitchP
+ xch a,SwConfigX
+ xrl a,SwConfigX
+ jz 0f
+ mov Phase,#Ph_Test
+ setb DispDotTR
+0: mov MiscP,#~BMM_DispR
+
+ mov UsrFlagsX,#0x03 //DEBUG!!!
+
+ clr a
+ mov IP,#0x10 // Pri: Ser=1
+ mov TCON,a
+ mov TL1,#-BauDiv
+ mov TH1,#-BauDiv
+ mov TL0,a
+ mov TH0,a
+ mov TMOD,#0x20 // T1=m2, T0=m0
+ mov PCON,a // SerSpd=normal
+ mov SCON,#0x50 // 8N1, T1, clr
+ mov TCON,#0x50 // T1+T0=run, clr
+
+ mov IE,#0x92 // Int: Ser+T0
+
+ mov r0,#TimPhase
+ acall StartTim
+ acall InitLED4
+MainLoop: mov WDogCnt,#0 // Reset WatchDog
+// Check run-time change of configuration
+ jb DisRSwChg,1f
+ mov a,SwConfigX
+ xrl a,SwitchP
+ jz 1f
+ ajmp SwRConfig
+1:
+// Display refresh
+ mov DispP,#0xFF
+ xrl MiscP,#BMM_DispL|BMM_DispR
+ mov a,Phase
+ jnb BPM_DispR,0f
+ jnb DispDotTR,6f
+ jb Xmitting,7f
+6: jnb DispDotRD,1f
+ xrl a,#Ph_Reload
+ jnz 1f
+7: clr BBD_DOT
+1: mov a,ScrollPtr
+ jnz 4f
+ mov a,DispL
+ jnb TimedDisp,2f
+ mov a,TimedL
+ sjmp 2f
+
+0: jnb DispDotTR,8f
+ jb PktRcvng,9f
+8: jnb DispDotRD,3f
+ xrl a,#Ph_Dead
+ jnz 3f
+9: clr BBD_DOT
+3: mov a,ScrollPtr
+ jz 5f
+ inc a
+4: mov dptr,#ScrBase
+ movc a,@a+dptr
+ sjmp 2f
+
+5: mov a,DispR
+ jnb TimedDisp,2f
+ mov a,TimedR
+2: anl DispP,a
+// 4-LED cycle
+ jb BBS_QuietL,NoLED4Fr
+ mov a,Phase
+ xrl a,#Ph_Dead
+ jz NoLED4Fr
+ mov r0,#TimLED4
+ acall QueryTim
+ jnc NoLED4Fr
+ jnb BBS_IsTeam,1f
+ mov a,#BMM_LED0|BMM_LED2
+ jnb BBS_TeamN,5f
+ mov a,#BMM_LED1|BMM_LED3
+5: xrl MiscP,a
+ sjmp 2f
+
+1: mov a,#~BMM_LEDM
+ orl a,MiscP
+ rl a
+ jb acc.(BNM_LED3+1),4f
+ mov a,#~BMM_LED0
+4: orl MiscP,#BMM_LEDM
+ anl MiscP,a
+2: mov r0,#TimLED4
+ mov a,T_LED4
+ acall StartTim
+NoLED4Fr:
+// Fire series maintenance
+ jnb BPI_Fire,0f
+ mov SeriCnt,#0
+0:
+/*** Here end mandatory MainLoop routines ***/
+ mov r0,#TimPhase
+ acall QueryTim
+ jnc NoPhases
+ mov dptr,#PhaseTab
+ mov r1,#Phase1
+ mov a,Phase
+ acall JmpByTab
+NoPhases:
+// Fire check
+ mov a,Phase
+ jz 1f
+ dec a
+ jnz 2f
+1: jb BPI_Status,0f
+ clr a
+ mov Phase,a
+ mov Phase1,a
+ mov r0,#TimPhase
+ acall StartTim
+ sjmp CantFire
+
+2: cjne a,#Ph_First-Ph_Ammo,CantFire
+ mov a,SeriCnt
+ dec a
+ jz CantFire
+0: jb BPI_Fire,CantFire
+ mov a,SeriCnt
+ subb a,SeriC_Max
+ jnc CantFire
+ mov a,Ammo
+ jz CantFire
+ jb XMitting,CantFire
+// Fire one shot NOW!
+ inc SeriCnt
+ mov Phase,#Ph_Laser
+ dec Ammo
+ clr BPM_Laser
+ mov c,BBS_QuietS
+ mov BPM_Sound,c
+ inc TotShotsW+1
+ mov a,TotShotsW+1
+ jnz 1f
+ inc TotShotsW
+1: mov a,#PktN_Fire
+ acall StartXMiX
+ mov ScrollPtr,#0
+ acall DispAmmo
+ mov a,T_Laser
+ mov r0,#TimPhase
+ acall StartTim
+CantFire:
+// Scroll Update
+ mov r0,#TimScroll
+ acall QueryTim
+ jnc 6f
+ clr TimedDisp
+ mov a,ScrollPtr
+ jz 6f
+ mov dptr,#ScrBase+2
+ movc a,@a+dptr
+ jnz 0f
+ mov ScrollPtr,a
+ sjmp 6f
+
+0: inc ScrollPtr
+ mov a,ScrollPtr
+ movc a,@a+dptr
+ jnz 1f
+ mov a,T_ScrollF
+ sjmp 2f
+
+1: mov a,T_Scroll
+2: acall StartTim
+6:
+// Packet received?
+ mov a,UserPktS
+ mov r0,a
+ xrl a,CurPktS
+ jnz 0f
+GotNoSerS: ajmp GotNoSer
+
+ShortPkt: mov a,r0
+ acall RxBufInc
+ push 0 //r0
+ mov r0,a
+ sjmp ProcSPkt
+
+0: mov a,@r0
+; jb acc.7,ShortPkt
+ jb XMitting,GotNoSerS
+ inc a
+ add a,r0
+ subb a,#RxBuf+RxBufSiz
+ jnc 1f
+ add a,#RxBufSiz
+1: add a,#RxBuf
+ push acc
+ mov a,@r0
+ clr c
+ subb a,#3
+ jc FailRPktN
+ mov @r0,a
+ push 0 //r0
+ inc a
+ mov r2,a
+ acall RxBufInc
+ mov r1,#RxChkXSumW+1
+ mov @r1,#low XSum_Base
+ dec r1
+ mov @r1,#high XSum_Base
+0: mov a,@r0
+ acall AddXSum
+ acall RxBufInc
+ djnz r2,0b
+ pop 2 //r2
+ mov a,@r0
+ xrl a,@r1
+FailRPktN: jnz FailRPktS
+ acall RxBufInc
+ mov a,@r0
+ inc r1
+ xrl a,@r1
+ jnz FailRPktS
+// XSum is correct
+ mov a,r2
+ mov r0,a
+ mov a,@r0
+ mov r2,a
+ acall RxBufInc
+ mov a,@r0
+ mov r3,a
+ acall RxBufInc
+ cjne r3,#PktN_Fire,NoPFire
+ cjne r2,#1,FailRPktS
+// Fire packet received, @R0=remote SwConfigX
+ProcSPkt: mov a,@r0
+ jnb BBS_IsTeam,ShotDown // We're anarchy
+ jnb acc.BNS_IsTeam,ShotDown // From anarchy one
+ xrl a,SwConfigX
+ jnb acc.BNS_TeamN,FriendS // One of our team
+ mov a,@r0
+ShotDown: xrl a,SwConfigX
+ anl a,#BMS_IdentM
+ jz FriendS
+// Really shot by enemy
+ mov TimedL,#Font_E
+ mov a,Phase
+ xrl a,#Ph_Dead
+ jz PrintIDR
+ mov a,@r0
+ anl a,#0x0F
+ rl a
+ add a,#GraveW+1
+ mov r1,a
+ inc @r1
+ mov a,@r1
+ jnz 0f
+ dec r1
+ inc @r1
+0: mov TimedL,#Font_S
+ mov Phase,#Ph_Dead
+ mov Phase1,DeadN
+ anl MiscP,#~BMM_LEDM
+ push 0 //r0
+ acall NxtDead
+ pop 0 //r0
+ sjmp PrintIDR
+
+FriendS: mov TimedL,#Font_F
+PrintIDR: mov a,@r0
+ anl a,#0x0F
+ mov dptr,#FontHex
+ movc a,@a+dptr
+ mov TimedR,a
+ setb TimedDisp
+ mov ScrollPtr,#0
+ mov a,T_TimedD
+ mov r0,#TimScroll
+ acall StartTim
+FailRPktS: sjmp FailRPkt
+
+NoPFire: cjne r3,#PktN_CfgR,NoPCfgR
+ jnb XMitting,0f
+ dec sp
+ sjmp GotNoSer
+
+0: mov a,@r0
+ xrl a,SwConfigX
+ anl a,#BMS_IdentM
+ jnz FailRPkt
+ acall RxBufInc2
+CfgNBlock: mov a,r2
+ jz FailRPkt
+ mov a,@r0
+ acall RxBufInc2
+ jz CRRepRes
+ mov r3,a
+ mov a,r2
+ jz FailRPkt
+ mov a,@r0
+ acall RxBufInc2
+ mov r1,a
+CfgBlock: mov a,r2
+ jz FailRPkt
+ mov a,@r0
+ acall RxBufInc2
+ push acc
+ mov a,r1
+ clr c
+ subb a,#AddrSpace
+ pop acc
+ jnc SkipWrite
+ jb UnConfig,SkipWrite
+ mov @r1,a
+SkipWrite: inc r1
+ djnz r3,CfgBlock
+ sjmp CfgNBlock
+
+CRRepRes: pop acc
+ clr c
+ subb a,#RxBuf+2
+ jnc 0f
+ add a,#RxBufSiz
+0: add a,#RxBuf
+ mov CAPktEnd,a
+ mov a,r0
+ mov UserPktS,a
+ mov a,#CfgRS-ScrBase
+ acall DoScroll
+ mov a,#PktN_CfgA
+ acall StartXMiX
+ sjmp GotNoSer
+
+NoPCfgR: cjne r3,#PktN_CfgA,FailRPkt
+ mov a,#CfgAS-ScrBase
+ScrRPkt: acall DoScroll
+FailRPkt: pop UserPktS
+
+GotNoSer:
+
+ ajmp MainLoop
+
+/******************************/
+PhaseTab:
+ db PhCfgDump-PhaseTab
+ db PhAmmo -PhaseTab
+ db PhLaser -PhaseTab
+ db PhDelay -PhaseTab
+ db PhFirst -PhaseTab
+ db PhReload -PhaseTab
+ db PhDead -PhaseTab
+ db PhTest -PhaseTab
+
+PhCfgDump: mov a,T_TimedD
+ acall StartTim
+SkpCDump: inc @r1
+ mov dptr,#CfgDTab
+ mov a,@r1
+ clr c
+ subb a,#CD_Grave0
+ jnc CDGrave
+ mov a,@r1
+JmpByTab: movc a,@a+dptr
+ jmp @a+dptr
+
+PhLaser: orl MiscP,#BMM_Laser|BMM_Sound
+ inc Phase
+ mov a,T_Delay
+ sjmp StartTimS
+
+PhDelay: inc Phase
+ mov a,Ammo
+ jz PD_Reload // Do Reload
+ mov a,T_First
+ sjmp StartTimS
+
+PhTest: jb XMitting,PT_WaitTI
+ mov a,#TestChar
+ acall StartXMiX
+PT_WaitTI:
+ mov a,SwConfigX
+ swap a
+ rr a
+ anl a,#0x78
+ sjmp StartTimS
+
+PD_Reload: inc Phase
+ mov Phase1,ReloadN
+ mov Ammo,Ammo_Max
+ mov a,#ReloadS-ScrBase
+ acall DoScroll
+PhReload: dec Phase1
+ mov a,Phase1
+ jz NormAmmo
+ mov DispL,#Font_L
+ mov a,Phase1
+ acall PutHexFnR
+ mov a,T_Reload
+ sjmp StartTimP
+
+PhDead: xrl MiscP,#BMM_LEDM
+ dec Phase1
+ mov a,Phase1
+ jz RAmmonLED
+NxtDead: mov B,DeadDivN
+ div aB
+ xch a,B
+ jnz 0f
+ mov DispL,#Font_D
+ mov a,B
+ acall PutHexFnR
+0: mov a,T_Dead
+StartTimP: mov r0,#TimPhase
+StartTimS: ajmp StartTim
+
+RAmmonLED: acall InitLED4
+PhFirst:
+NormAmmo: mov Phase,#Ph_Ammo
+PhAmmo: // PhAmmo shouldn't happen <= no timer
+ ajmp DispAmmo
+
+CDGrave: cjne a,#CD_Last-CD_Grave0,1f
+ sjmp NormAmmo
+
+1: mov B,#3
+ div aB
+ mov r2,a
+ rl a
+ add a,#GraveW
+ mov r0,a
+ mov a,@r0
+ inc r0
+ orl a,@r0
+ jz SkpCDump2
+ mov a,B
+ cjne a,#0,0f
+ mov DispL,#Font_D
+ mov a,r2
+PutHexFnR: mov dptr,#FontHex
+ ajmp PutFontR
+
+0: dec r0
+ mov r3,a
+ acall ConvDecW
+ cjne r3,#1,DispHexS
+ mov a,@r0
+ sjmp DispHexS
+
+CfgDTab equ $-1
+ db CDPNum -CfgDTab
+ db CDGMode -CfgDTab
+ db CDLEDs -CfgDTab
+ db CDSound -CfgDTab
+ db CDWDogs -CfgDTab
+ db CDWDogsN -CfgDTab
+ db CDRSwChg -CfgDTab
+ db CDRSwChgN-CfgDTab
+ db CDTotSh -CfgDTab
+ db CDTotShM -CfgDTab
+ db CDTotShN -CfgDTab
+
+CDPNum: mov DispL,#Font_P
+ mov a,SwConfigX
+ anl a,#0x0F
+ sjmp PutHexFnR
+
+CDGMode: mov DispL,#Font_G
+ mov a,#Font_A
+ jnb BBS_IsTeam,DoGaMode
+ mov a,#Font_R
+ jnb BBS_TeamN,DoGaMode
+ mov a,#Font_G
+DoGaMode: mov DispR,a
+ ret
+
+CDLEDs: jnb BBS_QuietL,SkpCDumpS
+ mov DispL,#Font_L
+ mov DispR,#Font_D
+ ret
+
+CDSound: jnb BBS_QuietS,SkpCDumpS
+ mov DispL,#Font_S
+ mov DispR,#Font_D
+ ret
+
+CDWDogs: mov a,WDogsCnt
+ jz SkpCDump1
+ mov DispL,#Font_D
+ mov DispR,#Font_R
+ ret
+
+SkpCDump2: inc @r1
+SkpCDump1: inc @r1
+SkpCDumpS: ajmp SkpCDump
+
+CDWDogsN: mov a,WDogsCnt
+ sjmp DispDecS
+
+CDRSwChg: mov a,RSwChgs
+ jz SkpCDump1
+ mov DispL,#Font_S
+ mov DispR,#Font_C
+ ret
+
+CDRSwChgN: mov a,RSwChgs
+DispDecS: ajmp DispDec
+
+CDTotSh: mov a,TotShotsW
+ orl a,TotShotsW+1
+ jz SkpCDump2
+ mov DispL,#Font_F
+ mov DispR,#Font_S
+ ret
+
+CDTotShM: mov r0,#TotShotsW
+ acall ConvDecW
+ mov a,@r0
+ sjmp DispHexS
+
+CDTotShN: mov r0,#TotShotsW
+ acall ConvDecW
+DispHexS: ajmp DispHex
+/******************************/
+SerICont: push psw
+ push acc
+ push 0 //r0
+ push 2 //r2
+RetryRI: jbc RI,GotRI
+RetryTI: jbc TI,GotTI
+ pop 2 //r2
+ pop 0 //r0
+ pop acc
+ pop psw
+ reti
+/******************************/
+GotRI: mov a,SBUF
+ jnb acc.7,5f
+ jb FastFireRD,ScratchRI
+ jb acc.6,ScratchRI
+ mov r0,CurPktS
+ mov @r0,a
+ acall RxBufInc
+ mov a,r0
+ xrl a,UserPktS
+ jz ScratchRI
+ mov a,r0
+ mov CurPktS,a
+ sjmp ScratchRI
+
+5: cjne a,#Mark_Start,0f
+ mov r0,CurPktS
+ acall RxBufInc
+ mov a,r0
+ xrl a,UserPktS
+ jz ScratchRI
+ mov CurPktE,r0
+ setb PktRcvng
+ clr PktGotNib
+ sjmp RetryRI
+
+0: cjne a,#Mark_End,1f
+ jnb PktRcvng,RetryRI
+ jb PktGotNib,ScratchRI
+ clr PktRcvng
+ mov a,CurPktE
+ mov r0,CurPktS
+ clr c
+ subb a,r0
+ jnc 3f
+ add a,#RxBufSiz
+3: dec a
+ jz RetryRI
+ mov @r0,a
+ mov a,CurPktE
+ mov CurPktS,a
+// Successfuly received packet
+ sjmp RetryRI
+
+1: jnb PktRcvng,RetryRI
+ clr c
+ subb a,#'0'
+ jc ScratchRI
+ subb a,#10
+ jc GotRITen
+ subb a,#'A'-('9'+1)
+ jc ScratchRI
+ subb a,#6
+ jc GotRISix
+ScratchRI: clr PktRcvng
+RetryRIS: sjmp RetryRI
+/******************************/
+GotTI: jnb XMitting,RetryTI
+ clr XMittedN
+ jnb XMitHaveP,PrepXMit
+ mov a,XMitNib
+SendPrepd: jb XMittedN,RetryTIS
+ jbc XMitByte,XMitByteC
+ jnb XMit1stNib,Have2ndN
+ swap a
+Have2ndN: anl a,#0x0F
+ add a,#'0'
+ mov r2,a
+ clr c
+ subb a,#'9'+1
+ mov a,r2
+ jc XMitByteC
+ add a,#'A'-('9'+1)
+XMitByteC: mov SBUF,a
+ setb XMittedN
+ mov c,XMit1stNib
+ clr XMit1stNib
+ mov XMitHaveP,c
+ jnc PrepXMit
+RetryTIS: ajmp RetryTI
+/******************************/
+GotRISix: add a,#6
+GotRITen: add a,#10
+ jb PktGotNib,2f
+ swap a
+ mov PktNibble,a
+ sjmp DoneFNRI
+
+2: orl a,PktNibble
+ mov r2,a
+ mov r0,CurPktE
+ acall RxBufInc
+ mov a,UserPktS
+ xrl a,r0
+ jz ScratchRI
+ mov a,r0
+ xch a,CurPktE
+ mov r0,a
+ mov a,r2
+ mov @r0,a
+DoneFNRI: cpl PktGotNib
+ sjmp RetryRIS
+/******************************/
+PrepXMit: mov a,XMitPhase
+ mov dptr,#PhXMitTab
+ movc a,@a+dptr
+ jmp @a+dptr
+
+PhXMitTab: db XPStart -PhXMitTab
+ db XPType -PhXMitTab
+ db XPSwCfg -PhXMitTab
+ db XPData -PhXMitTab
+ db XPXSumH -PhXMitTab
+ db XPXSumL -PhXMitTab
+ db XPEnd -PhXMitTab
+ db XPFinish-PhXMitTab
+
+InvalCR: mov CAPktEnd,a
+XPFinish: clr XMitting
+ sjmp RetryTIS
+
+XPStart: mov a,XMitType
+ xrl a,#TestChar
+ jnz 1f
+ mov a,#TestChar
+ sjmp 2f
+
+1: xrl a,#TestChar^PktN_Fire
+ jnz 0f
+ jb FullFireT,0f
+ mov a,SwConfigX
+ clr acc.6
+ setb acc.7
+2: mov XMitPhase,#6 //XPFinish-1
+ sjmp ContXMitB
+
+0: mov a,#Mark_Start
+ContXMitB: setb XMitByte
+ inc XMitPhase
+ clr XMit1stNib
+ContXMit: setb XMitHaveP
+ mov XMitNib,a
+ ajmp SendPrepd
+
+XPType: mov XMitXSumW ,#high XSum_Base
+ mov XMitXSumW+1,#low XSum_Base
+ mov a,XMitType
+XMitXHexP: inc XMitPhase
+XMitXHex: push 1 //r1
+ push 3 //r3
+ push B
+ mov r1,#XMitXSumW
+ push acc
+ acall AddXSum
+ pop acc
+ pop B
+ pop 3 //r3
+ pop 1 //r1
+XMitHex: clr XMitByte
+ setb XMit1stNib
+ sjmp ContXMit
+
+XPSwCfg: mov a,SwConfigX
+ sjmp XMitXHexP
+
+XPData: mov a,XMitType
+ xrl a,#PktN_CfgA
+ jnz XPDatDone
+ mov r0,UserPktS
+NxtBlock: mov a,r0
+ xrl a,CAPktEnd
+ jz DoneAns
+ mov a,@r0
+ dec @r0
+ mov r2,a
+ acall RxBufInc
+ mov a,r0
+ xrl a,CAPktEnd
+ jz InvalCR // Invalid CfgReq
+ mov a,r2
+ jz DoneBlock
+ mov a,@r0
+ inc @r0
+ mov r0,a
+ mov a,@r0
+ sjmp XMitXHex
+
+DoneBlock: acall RxBufInc
+ mov UserPktS,r0
+ mov a,r0
+ xrl a,CAPktEnd
+ jnz NxtBlock
+DoneAns: mov CAPktEnd,a // Cancel CfgA pending alert
+ acall RxBufInc
+ acall RxBufInc
+ mov UserPktS,r0
+XPDatDone: inc XMitPhase
+XPXSumH: mov a,XMitXSumW
+XMitHexP: inc XMitPhase
+ sjmp XMitHex
+
+XPXSumL: mov a,XMitXSumW+1
+ sjmp XMitHexP
+
+XPEnd: mov a,#Mark_End
+ sjmp ContXMitB
+
+/******************************/
+StartXMiX: mov XMitType,a
+ clr a
+ mov XMitPhase,a
+ clr XMitHaveP
+ setb XMitting
+ setb TI // Start XMit now!
+ ret
+/******************************/
+// I: A=text offset, O: Filled DispL+DispR, D: A,R0,R2
+DoScroll: mov ScrollPtr,a
+ mov r0,#TimScroll
+ mov a,T_ScrollF
+ sjmp StartTim
+/******************************/
+// O: Filled DispL+DispR, D: A,B,R2
+DispAmmo: mov a,Ammo
+// I: A=decimal, O: Filled DispL+DispR, D: A,B,R2
+DispDec: mov R2,a
+ clr c
+ subb a,#100
+ jnc 0f
+ mov a,MaxDecimal
+0: mov a,R2
+ mov B,#10
+ div aB
+ swap a
+ orl a,B
+// I: A=hexadecimal, O: Filled DispL+DispR, D: A,R2
+DispHex: mov dptr,#FontHex
+ mov R2,a
+ swap a
+ anl a,#0x0F
+ movc a,@a+dptr
+ mov DispL,a
+ mov a,R2
+ anl a,#0x0F
+PutFontR: movc a,@a+dptr
+ mov DispR,a
+Ret1: ret
+/******************************/
+InitLED4: orl MiscP,#BMM_LEDM
+ jb BBS_QuietL,Ret1
+ anl MiscP,#~BMM_LED0
+ jnb BBS_IsTeam,0f
+ jnb BBS_TeamN,0f
+ xrl MiscP,#BMM_LED0|BMM_LED1
+0: mov r0,#TimLED4
+ mov a,T_LED4
+/******************************/
+// I: R0=addr of byte, A=min time, O: @R0!=0, D:A
+StartTim: add a,Timer
+ jnz 0f
+ inc a
+0: mov @R0,a
+ ret
+/******************************/
+// I: R0=addr of byte, C=1->success, D:A
+QueryTim: mov a,@R0
+ clr c
+ jz 0f
+ subb a,Timer
+ mov c,acc.7
+ jnc 0f
+ clr a
+ mov @R0,a
+0: ret
+/******************************/
+RxBufInc2: dec r2
+// I: R0=RxAddr, O: R0=RxAddr+1
+RxBufInc: inc r0
+ cjne r0,#RxBuf+RxBufSiz,0f
+ mov r0,#RxBuf
+0: ret
+/******************************/
+// I: @R1/W=xsum, A=Byte, O: @R1/W=xsum+Byte, D:A,B,R3
+AddXSum: push 2 //r2
+ push acc
+ inc r1
+ inc @r1
+ mov a,@r1
+ dec r1
+ jnz 0f
+ inc @r1
+0: mov B,#XSum_Mul
+ mul aB
+ mov r2,a
+ mov r3,B
+ mov a,@r1
+ mov B,#XSum_Mul
+ mul aB
+ add a,r3
+ mov r3,a
+ pop acc
+ add a,r2
+ inc r1
+ mov @r1,a
+ dec r1
+ mov a,r3
+ addc a,#0
+ mov @r1,a
+ pop 2 //r2
+ ret
+// I: R0=SrcWord, O: R0=ConvDecW1, A=LOW [R0/W], D:R1,R2
+ConvDecW:
+ inc sp
+ mov r1,sp
+ inc sp
+ mov a,@r0
+ mov @r1,a
+ inc r0
+ inc r1
+ mov a,@r0
+ mov @r1,a
+ mov dptr,#CDW_Tab
+ mov r2,#4
+ mov r0,#ConvDecW1
+3: xchd a,@r0
+ swap a
+ mov @r0,a
+ inc r0
+ clr a
+ xchd a,@r0
+ swap a
+ mov @r0,a
+2: mov a,#1
+ movc a,@a+dptr
+ mov B,a
+ mov a,@r1
+ clr c
+ subb a,B
+ push acc
+ dec r1
+ clr a
+ movc a,@a+dptr
+ mov B,a
+ mov a,@r1
+ subb a,B
+ jc 1f
+ mov @r1,a
+ pop acc
+ inc r1
+ mov @r1,a
+ inc @r0
+ sjmp 2b
+
+1: dec sp
+ inc dptr
+ inc dptr
+ inc r1
+ mov a,@r0
+ dec r0
+ djnz r2,3b
+ dec sp
+ dec sp
+ ret
+/******************************/
+
+ScrBase: // Every text offset must >0 !!!
+FontHex: db Font_0,Font_1,Font_2,Font_3,Font_4,Font_5,Font_6,Font_7
+ db Font_8,Font_9,Font_A,Font_B,Font_C,Font_D,Font_E,Font_F
+ReloadS: db Font_R,Font_E,Font_L,Font_O,Font_A,Font_D,0
+CfgAS: db Font_C,Font_O,Font_N,Font_F,Font_I,Font_G
+ db Font_A,Font_N,Font_S,0
+CfgRS: db Font_C,Font_O,Font_N,Font_F,Font_I,Font_G
+ db Font_U,Font_R,Font_E,Font_D,0
+ if ($-ScrBase>=0x100) ScrBase equ 0
+/******************************/
+CDW_Tab: dw 1000,100,10,1
+
+LoadContn:
+ db 12 // Reload countdown
+ db 40 // Dead state countdown
+ db 15 // Maximum # of shots per one series
+ db 40 // Ammo # in one clip
+ db 40 // Remaining ammo in the current clip
+ db 4 // 4LED-Dead -> Dead cycle divisor
+ db 100 // Startup info cycle delay
+ db 48 // Reload cycle delay
+ db 8 // Laser firing
+ db 2 // Inter-Laser delay
+ db 24 // Additional series start delay period
+ db 32 // 1 of RY-LED switch period
+ db 25 // Scroll of one letter
+ db 50 // Scroll of 1st two letters
+ db 24 // 4LED-Dead (and Dead) cycle delay
+ db 110 // TimedDisp delay (temporary, non-scrolling)
+ if ($-LoadContn!=LoadPartS) LoadPartS equ 0