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