10 REM > RAMCount/src v0.02
   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 :
   70 DIM mcode% 1024,L%-1:REM Need enough space for two copies plus table
   80 OSASCI=&FFE3:OSNEWL=&FFE7:OSWRCH=&FFEE:OSBYTE=&FFF4
   90 :
  100 FOR pass%=0 TO 3
  110   opt%=FNsm_pass(pass%)
  120   [OPT opt%
  130   .ROMStart
  140   BRK:EQUW RelocTable
  150   JMP Service
  160   EQUB &82:EQUB Copyright-ROMStart
  170   EQUB &00:EQUS "RAMCount"
  180   EQUB &00:EQUS "0.02 (15 Oct 2014)"
  190   .Copyright
  200   EQUB &00:EQUS "(C)J.G.Harston":EQUB &00
  210   :
  220   .Service
  230   PHA
  240   CMP #&01:BEQ RAMCount
  250   CMP #&2B:BEQ RAMCount
  260   .ServExit
  270   PLA:RTS
  280   :
  290   .RAMCount
  300   LDA &28D:BEQ ServExit        :\ Soft BREAK
  310   LDA &27A:BNE ServExit        :\ Tube active
  320   LDA &267:BPL ServExit        :\ Startup message already replaced
  330   AND #&7F:STA &267            :\ Suppress startup message
  340   TYA:PHA                      :\ Save Service1 Y register
  350   :
  360   LDA #0:LDX #1:JSR OSBYTE     :\ Get machine type
  370   TXA:PHA                      :\ Save machine type for banner
  380   LDY #2                       :\ Assume 2x16K main RAM
  390   CPX #1:BNE CountShadow       :\ Not BBC, always 2x16K main RAM
  400   LDA &28E:BMI CountShadow     :\ BBC with 32K
  410   DEY                          :\ BBC with 16K, decrement to 1x16K
  420   :
  430   .CountShadow
  440   TYA:PHA                      :\ Save amount of main RAM
  450   LDA #114:LDX #0:JSR OSBYTE   :\ Read Acorn Shadow RAM status
  460   JSR OSBYTE                   :\ Restore Acorn Shadow RAM status
  470   TXA:BPL FoundShadow          :\ Acorn Shadow RAM present
  480   :
  490   LDA #111:LDX #64:JSR OSBYTE  :\ Read status of non-Acorn Shadow RAM
  500   TXA:BMI CountSRAM            :\ No non-Acorn Shadow RAM present
  510   .FoundShadow
  520   PLA:CLC:ADC #2:PHA           :\ Add 2x16K Shadow RAM
  530   :
  540   .CountSRAM
  550   PLA:TAY                      :\ Y=RAM count so far
  560   PLA:PHA:CMP #1               :\ Get machine type, Cy=CC if Electron
  570   LDX #CodeEnd-CodeStart
  580   .CopyCountCode
  590   LDA CodeStart,X:PHA          :\ Copy SRAM count code to stack
  600   DEX:BPL CopyCountCode
  610   JSR CallStackCode            :\ Call routine on the stack
  620   TSX:TXA
  630   SEC:ADC #CodeEnd-CodeStart
  640   TAX:TXS                      :\ Restore stack, dropping stacked code
  650   :
  660   PLA:TAX                      :\ X=machine type, Y=RAM count
  670   LDA MsgOffset,X:TAX          :\ X=>Banner message
  680   .MsgLoop
  690   LDA MsgBase,X:BEQ MsgDone    :\ Print banner message
  700   JSR OSASCI:INX:BNE MsgLoop
  710   .MsgDone
  720   :
  730   LDA RAMhigh-1,Y              :\ Get RAM size high digits
  740   BEQ P%+5:JSR PrNyb           :\ Print if non-zero
  750   LDA RAMlow-1,Y:JSR PrHex     :\ Print RAM size low digits
  760   LDA #ASC"K":JSR OSWRCH       :\ Print "K" suffix
  770   JSR OSNEWL:JSR OSNEWL
  780   :
  790   PLA:TAY:LDX &F4              :\ Restore registers
  800   PLA:RTS                      :\ And return unclaimed
  810   :
  820   .CallStackCode                 :\ Cy=Elk, A=??,   X=??,   Y=count, SP=>ret.lo, ret.hi, code...
  830   LDA #1:PHA                     :\ Cy=Elk, A=&01,  X=??,   Y=count, SP=>&01, ret.lo, ret.hi, code...
  840   TSX                            :\ Cy=Elk, A=&01,  X=SP,   Y=count, SP=>&01, ret.lo, ret.hi, code...
  850   INX:INX:INX                    :\ Cy=Elk, A=&01,  X=SP+2, Y=count, SP=>&01, ret.lo, ret.hi, code...
  860   BCS CallStackNotElk            :\ Not Electron
  870   LDA #&05:STA &104+romselect2-CodeStart,X
  880   .CallStackNotElk
  890   TXA:PHA                        :\ Cy=Elk, A=SP+3, X=SP+2, Y=count, SP=>SP+3, &01, ret.lo, ret.hi, code...
  900   SEC:ADC #romselect-CodeStart   :\ Calculate low byte of SelectRom
  910   STA &102+loop-CodeStart,X      :\ Insert JSR SelectRom
  920   ADC #(romselect2-romselect)    :\ Calculate low byte of SelectRom2
  930   STA &104+romselect-CodeStart,X :\ Insert JSR SelectRom2
  940   LDX #15                        :\ Start at X=ROM 15
  950   LDA &F4                        :\ Get current ROM number
  960   RTS                            :\ Jump to code on stack
  970   :
  980   \ Code run from stack so can access other sideways ROM/RAM banks
  990   \ This will count duplicate RAM banks on BBC
 1000   .CodeStart
 1010   PHA                          :\ save current ROM
 1020   .loop
 1030   JSR &100:\romselect          :\ page in a bank
 1040   LDA &8008:EOR #&AA:STA &8008 :\ modify version byte
 1050   CMP &AAAA:CMP &8008:BNE rom  :\ didn't change, is ROM
 1060   EOR #&AA:STA &8008           :\ restore byte
 1070   INY                          :\ increment number of RAM banks
 1080   .rom
 1090   DEX:BPL loop                 :\ loop for all 16 banks
 1100   PLA:TAX                      :\ restore ROM and return
 1110   .romselect
 1120   LDA #12:JSR &100:\romselect2 :\ do Electron pre-select
 1130   TXA:STA &FF30,X              :\ WERAM write enable
 1140   .romselect2
 1150   STA &F4:STA &FE30:RTS        :\ select ROM bank
 1160   .CodeEnd
 1170   :
 1180   \ Banner messages and RAM sizes
 1190   \ -----------------------------
 1200   .MsgOffset
 1210   EQUB MsgElk-MsgBase          :\ 0=Electron
 1220   EQUB MsgBBC-MsgBase          :\ 1=BBC A/B
 1230   EQUB MsgBBC-MsgBase          :\ 2=BBC B+
 1240   EQUB MsgMst-MsgBase          :\ 3=Master
 1250   EQUB MsgMst-MsgBase          :\ 4=Master ET
 1260   EQUB MsgCmp-MsgBase          :\ 5=Compact
 1270   .MsgBase
 1280   .MsgElk:EQUB 13:EQUB 7:EQUS "Acorn Electron ":EQUB 0
 1290   .MsgBBC:EQUB 13:EQUB 7:EQUS "BBC Computer ":EQUB 0
 1300   .MsgMst:EQUB 13:EQUB 7:EQUS "Acorn Master ":EQUB 0
 1310   .MsgCmp:EQUB 13:EQUB 7:EQUS "Master Compact ":EQUB 0
 1320   :
 1330   .RAMlow
 1340   EQUD &64483216               :\ Low BCD of RAM count
 1350   EQUD &28129680
 1360   EQUD &92766044
 1370   EQUD &56402408
 1380   EQUD &20048872
 1390   .RAMhigh
 1400   EQUD &00000000               :\ High BCD of RAM count
 1410   EQUD &01010000
 1420   EQUD &01010101
 1430   EQUD &02020202
 1440   EQUD &03030202
 1450   :
 1460   .PrHex
 1470   PHA:LSR A:LSR A:LSR A:LSR A
 1480   JSR PrNyb:PLA
 1490   .PrNyb
 1500   AND #15:CMP #10:BCC P%+4:ADC #6
 1510   ADC #ASC"0":JMP OSWRCH
 1520   :
 1530   \ Relocation table to make *SMLoad-able
 1540   \ -------------------------------------
 1550   .RelocTable
 1560 ]:NEXT
 1570 PROCsm_table
 1580 PRINT"*Save RAMCount ";~(mcode%+mclen%);" ";~O%;" FFFF0000 FFFBBC00"
 1590 END
 1600 :
 1610 DEFFNsm_pass(pass%)
 1620 IFpass%=0:mclen%=0
 1630 IFpass%=1:mclen%=O%-mcode%
 1640 P%=&8100-128*(pass%AND2)
 1650 O%=mcode%+mclen%*(pass%AND2)DIV2
 1660 IFpass%=1:IF O%+mclen%*2.125>L%:PRINT"Code overrun":END
 1670 =VALMID$("4647",pass%+1,1)
 1680 :
 1690 DEFPROCsm_table
 1700 base80%=mcode%+mclen%:base81%=mcode%:byte%=0:count%=0:off%=0:REPEAT
 1710   byte80%=base80%?off%:byte81%=base81%?off%:IF off%>=mclen%:byte80%=&80:byte81%=&80
 1720   IF ((byte81%-byte80%) AND &FE)<>0 THEN PRINT "ERROR: Offset by more than one page at &";~&8000+off%
 1730   IF (byte80% AND &C0)=&80:byte%=byte%DIV2+128*(byte81%-byte80%):count%=count%+1
 1740   IF count%=8:?O%=byte%:O%=O%+1:byte%=0:count%=0
 1750 off%=off%+1:UNTILoff%>=mclen% AND count%=0
 1760 ENDPROC