10 REM > AP6Count/src v0.05
   20 REM Count RAM on startup and display startup banner
   30 REM On unexpanded BBC B, SRAM banks will be seen duplicated
   40 REM 10-Oct-2014 v0.01 Initial working version
   50 REM 15-Oct-2014 v0.02 Works on Electron
   60 REM 16-Jan-2016 v0.02 Electron AP6 version
   70 REM 20-Jan-2016 v0.03 Compatible with EEPROMs
   80 REM 14-Feb-2016 v0.04 Checks for extra TURBO memory
   90 REM 29-Feb-2016       Displays Shadow or Turbo
  100 REM 20-May-2016 v0.05 Displays Electron 'Acorn' bitmap
  110 :
  120 PROCassem(0):CLEAR:PROCassem(2):PROCsm_table
  130 A$="*SAVE "+fname$+" "+STR$~(mcode%+M%)+" "+STR$~O%+" FFFF0000 FFFBBC00"
  140 PRINTA$;:OSCLIA$:PRINT
  150 END
  160 :
  170 DEFPROCassem(pass%)
  180 fname$="AP6Count"
  190 OSASCI=&FFE3:OSNEWL=&FFE7:OSWRCH=&FFEE:OSBYTE=&FFF4
  200 DIM mcode% 1024,L%-1:REM Enough space for two copies plus table
  210 :
  220 FOR pass%=pass% TO pass%+1
  230   opt%=FNsm_pass(pass%)+8+16
  240   [OPT opt%
  250   .ROMStart
  260   BRK:EQUW RelocTable
  270   JMP Service
  280   EQUB &82:EQUB Copyright-ROMStart
  290   EQUB &00:EQUS "RAMCountAP6"
  300   EQUB &00:EQUS "0.05 (20 May 2016)"
  310   .Copyright
  320   EQUB &00:EQUS "(C)J.G.Harston":EQUB &00
  330   :
  340   .Service
  350   PHA
  360   CMP #&01:BEQ RAMCount
  370   CMP #&2B:BEQ RAMCount
  380   .ServExit
  390   PLA:RTS
  400   :
  410   .RAMCount
  420   LDA &28D:BEQ ServExit        :\ Soft BREAK
  430   LDA &27A:BNE ServExit        :\ Tube active
  440   LDA &267:BPL ServExit        :\ Startup message already replaced
  450   AND #&7F:STA &267            :\ Suppress startup message
  460   TYA:PHA                      :\ Save Service1 Y register
  470   :
  480   LDA #2:PHA                   :\ Assume 2x16K main RAM
  490   LDA &27F:BMI FoundShadow     :\ Turbo 64K
  500   LDA #114:LDX #0:JSR OSBYTE   :\ Read Acorn Shadow RAM status
  510   JSR OSBYTE                   :\ Restore Acorn Shadow RAM status
  520   TXA:BPL FoundShadow          :\ Acorn Shadow RAM present
  530   :
  540   LDA #111:LDX #64:JSR OSBYTE  :\ Read status of non-Acorn Shadow RAM
  550   TXA:BMI CountSRAM            :\ No non-Acorn Shadow RAM present
  560   .FoundShadow
  570   PLA:CLC:ADC #2:PHA           :\ Add 2x16K Shadow RAM
  580   :
  590   .CountSRAM
  600   STA &FCD8:STA &FCDA          :\ Enable sideways RAM
  610   STA &FCDC:STA &FCDE
  620   PLA:TAY                      :\ Y=RAM count so far
  630   PHP:SEI                      :\ Prevent EEPROMs unexpectedly getting IRQs
  640   LDX #CodeEnd-CodeStart
  650   .CopyCountCode
  660   LDA CodeStart,X:PHA          :\ Copy SRAM count code to stack
  670   DEX:BPL CopyCountCode
  680   JSR CallStackCode            :\ Call routine on the stack
  690   TSX:TXA
  700   SEC:ADC #CodeEnd-CodeStart
  710   TAX:TXS:PLP                  :\ Restore stack, dropping stacked code, restore IRQs
  720   STA &FCD9:STA &FCDB          :\ Write protect sideways RAM
  730   STA &FCDD:STA &FCDF
  740   :
  750   TYA:PHA                      :\ Save RAM count
  760   LDX #0:JSR PrMsg             :\ Print <beep>'Electron'
  770   :
  780   LDA &FFFC:STA &F6            :\ &F6/7=>start of RESET code
  790   LDA &FFFD:STA &F7
  800   .FindAcorn
  810   LDY #10                      :\ Offset to code to check for
  820   LDA (&F6),Y:CMP #&13:BNE FindAcornNext  :\ Not #&13
  830   DEY
  840   LDA (&F6),Y:CMP #&A0:BEQ FindAcornFound :\ Found LDY #&13
  850   .FindAcornNext
  860   INC &F6:BNE FindAcorn
  870   INC &F7:BNE FindAcorn
  880   .FindAcornFound
  890   LDA #&60:BNE AcornCopyByte   :\ Put RTS at end of copied code
  900   .AcornCopyLp
  910   LDA (&F6),Y                  :\ Get byte from MOS ROM
  920   .AcornCopyByte
  930   STA &100,Y                   :\ Copy to stack
  940   DEY:BPL AcornCopyLp          :\ Copy Acorn drawing code
  950   JSR &100                     :\ Draw the Acorn
  960   LDA #9:JSR OSWRCH:JSR OSWRCH
  970   :
  980   LDX #MsgSha-MsgBase          :\ Point to 'Shadow'
  990   LDA &27F:BMI PrExtra         :\ Print 'Shadow' if b7=1
 1000   LSR A:BCC PrNoExtra          :\ If b0=0, not Turbo
 1010   LDX #MsgTub-MsgBase          :\ Point to 'Turbo'
 1020   .PrExtra
 1030   JSR PrMsg                    :\ Print 'Shadow' or 'Turbo'
 1040   .PrNoExtra
 1050   :
 1060   PLA:TAY:LDA RAMhigh-1,Y      :\ Get RAM size high digits
 1070   BEQ P%+5:JSR PrNyb           :\ Print if non-zero
 1080   LDA RAMlow-1,Y:JSR PrHex     :\ Print RAM size low digits
 1090   LDA #ASC"K":JSR OSWRCH       :\ Print "K" suffix
 1100   JSR OSNEWL:JSR OSNEWL
 1110   :
 1120   PLA:TAY:LDX &F4              :\ Restore registers
 1130   PLA:RTS                      :\ And return unclaimed
 1140   :
 1150   .CallStackCode                 :\ Cy=Elk, A=??,   X=??,   Y=count, SP=>ret.lo, ret.hi, code...
 1160   LDA #1:PHA                     :\ Cy=Elk, A=&01,  X=??,   Y=count, SP=>&01, ret.lo, ret.hi, code...
 1170   TSX                            :\ Cy=Elk, A=&01,  X=SP,   Y=count, SP=>&01, ret.lo, ret.hi, code...
 1180   INX:INX:INX                    :\ Cy=Elk, A=&01,  X=SP+2, Y=count, SP=>&01, ret.lo, ret.hi, code...
 1190   TXA:PHA                        :\ Cy=Elk, A=SP+3, X=SP+2, Y=count, SP=>SP+3, &01, ret.lo, ret.hi, code...
 1200   SEC:ADC #romselect-CodeStart   :\ Calculate low byte of SelectRom
 1210   STA &102+loop-CodeStart,X      :\ Insert JSR SelectRom
 1220   ADC #(romselect2-romselect)    :\ Calculate low byte of SelectRom2
 1230   STA &104+romselect-CodeStart,X :\ Insert JSR SelectRom2
 1240   LDX #15                        :\ Start at X=ROM 15
 1250   LDA &F4                        :\ Get current ROM number
 1260   RTS                            :\ Jump to code on stack
 1270   :
 1280   \ Code run from stack so can access other sideways ROM/RAM banks
 1290   \ This will count duplicate RAM banks on BBC
 1300   .CodeStart
 1310   PHA                          :\ save current ROM
 1320   .loop
 1330   JSR &100:\romselect          :\ page in a bank
 1340   LDA &8008:EOR #&AA           :\ modify version byte
 1350   STA &8008:NOP:CMP &8008:PHP  :\ EQ=RAM or ROM/EEPROM
 1360   EOR #&AA:STA &8008           :\ Restore byte
 1370   .toggle
 1380   LDA &8008:CMP &8008:BNE toggle :\ Toggling, must be EEPROM
 1390   PLP:BNE rom                  :\ NE from earlier, ROM or EEPROM
 1400   INY                          :\ increment number of RAM banks
 1410   .rom
 1420   DEX:BPL loop                 :\ loop for all 16 banks
 1430   PLA:TAX                      :\ restore ROM and return
 1440   .romselect
 1450   LDA #12:JSR &100:\romselect2 :\ do Electron pre-select
 1460   TXA
 1470   .romselect2
 1480   STA &F4:STA &FE05:RTS        :\ select ROM bank
 1490   .CodeEnd
 1500   :
 1510   \ Print messages offset from X
 1520   \ ----------------------------
 1530   .PrMsg
 1540   LDA MsgBase,X:BEQ MsgDone
 1550   JSR OSASCI:INX:BNE PrMsg
 1560   .MsgDone
 1570   RTS
 1580   :
 1590   \ Banner messages and RAM sizes
 1600   \ -----------------------------
 1610   .MsgBase
 1620   .MsgElk:EQUB 13:EQUB 7:EQUS "Acorn Electron ":EQUB 0
 1630   .MsgSha:EQUS "Shadow ":EQUB 0
 1640   .MsgTub:EQUS "Turbo ":EQUB 0
 1650   :
 1660   .RAMlow
 1670   EQUD &64483216               :\ Low BCD of RAM count
 1680   EQUD &28129680
 1690   EQUD &92766044
 1700   EQUD &56402408
 1710   EQUD &20048872
 1720   .RAMhigh
 1730   EQUD &00000000               :\ High BCD of RAM count
 1740   EQUD &01010000
 1750   EQUD &01010101
 1760   EQUD &02020202
 1770   EQUD &03030202
 1780   :
 1790   .PrHex
 1800   PHA:LSR A:LSR A:LSR A:LSR A
 1810   JSR PrNyb:PLA
 1820   .PrNyb
 1830   AND #15:CMP #10:BCC P%+4:ADC #6
 1840   ADC #ASC"0":JMP OSWRCH
 1850   :
 1860   \ Relocation table to make *SMLoad-able
 1870   \ -------------------------------------
 1880   ]:RelocTable=P%
 1890 NEXT:ENDPROC
 1900 :
 1910 DEFFNsm_pass(pass%)
 1920 IFpass%=0:M%=0
 1930 IFpass%=1:M%=O%-mcode%
 1940 P%=&8100-128*(pass%AND2)
 1950 O%=mcode%+M%*(pass%AND2)DIV2
 1960 IFpass%=1:IF O%+M%*2.125>L%:PRINT"Code overrun":END
 1970 =VALMID$("4647",pass%+1,1)
 1980 :
 1990 DEFPROCsm_table
 2000 base80%=mcode%+M%:base81%=mcode%:byte%=0:count%=0:off%=0:REPEAT
 2010   byte80%=base80%?off%:byte81%=base81%?off%:IF off%>=M%:byte80%=&80:byte81%=&80
 2020   IF ((byte81%-byte80%) AND &FE)<>0 THEN PRINT "ERROR: Offset by more than one page at &";~&8000+off%
 2030   IF (byte80% AND &C0)=&80:byte%=byte%DIV2+128*(byte81%-byte80%):count%=count%+1
 2040   IF count%=8:?O%=byte%:O%=O%+1:byte%=0:count%=0
 2050 off%=off%+1:UNTILoff%>=M% AND count%=0
 2060 ENDPROC