mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
546 lines
15 KiB
546 lines
15 KiB
TITLE "B/P Bios RAM size display"
|
|
;************************************************************************
|
|
;* S I Z E R A M *
|
|
;* Determine size and location of (banked) Memory *
|
|
;* by Harold F. Bower and Cameron W. Cotrill *
|
|
;*----------------------------------------------------------------------*
|
|
;* Disassembly: jxl Dec 2024 *
|
|
;* public release 1.0 Apr 2025 *
|
|
;* see remarks at the end *
|
|
;*----------------------------------------------------------------------*
|
|
;* LINK with Version 4 libraries: VLIB, Z3LIB, SYSLIB *
|
|
;* *
|
|
;* A>Z80ASM SIZERAM/RS *
|
|
;* A>SLRNK SIZERAM/N,/A:100,/D:0750,SIZERAM,VLIBS/S,Z3LIBS/S,SYSLIBS/S,/E *
|
|
;************************************************************************
|
|
|
|
VER EQU 12
|
|
REV EQU ' '
|
|
|
|
DATE MACRO
|
|
DEFB '30 Aug 01'
|
|
ENDM
|
|
|
|
|
|
BEL EQU 07H ; Bell character
|
|
LF EQU 0AH ; Line Feed character
|
|
CR EQU 0DH ; Carriage Return character
|
|
|
|
CPMBIOS EQU 0 ; CP/M BIOS warm boot (JP)
|
|
CPMBDOS EQU 5 ; CP/M BDOS entry point (JP)
|
|
CPMFCB EQU 5CH ; CP/M standard FCB #1 (+1 filename, +9 filetype)
|
|
|
|
|
|
; From Z3LIB Get..
|
|
EXTRN GETNAME, PRTNAME, Z3INIT, WHRENV
|
|
|
|
; From SYSLIB Get..
|
|
EXTRN EPRINT, CRLF, PAFDC, PHLFDC, COUT, CODEND
|
|
|
|
|
|
;::::: PROGRAM START
|
|
|
|
ORG 100H
|
|
CSEG
|
|
|
|
|
|
SIZERAM: JP START ; bypass header
|
|
DEFB 'Z3ENV' ; this is a ZCPR3 utility
|
|
DEFB 1 ; show external environment
|
|
|
|
ENVADR: DEFW 0 ; addr of Z3 environment
|
|
DEFW SIZERAM ; type 4 filler
|
|
|
|
DEFB 'SIZERAM ',0 ; configuration name
|
|
|
|
START: LD (STACK),SP
|
|
LD SP,STACK
|
|
CALL EPRINT
|
|
DEFB 'B/P Banked RAM Sizing Utility V',VER/10+'0','.'
|
|
DEFB VER MOD 10 + '0',REV,' '
|
|
DATE
|
|
DEFB CR,LF
|
|
DEFB 0
|
|
CALL CHKZ3E ; check if Z3 Environment is valid
|
|
CALL GETNAME ; get actual program name
|
|
CALL CHKHELP ; check cmdline for help request
|
|
CALL CHKSYS ; check if running under B/P Bios
|
|
CALL M$BVER ; display version # msg
|
|
LD HL,(BPCNFG) ; get addr of config area
|
|
INC HL ; move ptr fwd
|
|
INC HL
|
|
LD A,(HL) ; get OPTF1 (option flag at CONFIG+2)
|
|
AND 00000001b ; mask bit 0
|
|
LD (BPBNKD),A ; ..and store it
|
|
JP NZ,BNKDSYS ; if banked, jump to continue
|
|
|
|
|
|
;::::: NON-BANKED SYSTEM
|
|
|
|
NBNKSYS: INC HL ; move ptr to TPABNK in config area
|
|
INC HL
|
|
CALL EPRINT
|
|
DEFB CR,LF,LF,'Non-Banked System using TPA Banks = '
|
|
DEFB 0
|
|
LD A,(HL) ; get value
|
|
PUSH AF
|
|
CALL PAFDC ; ..and display
|
|
LD A,'/'
|
|
CALL COUT
|
|
POP AF ; restore value
|
|
INC A ; increase it
|
|
CALL PAFDC ; ..and display
|
|
CALL CRLF
|
|
JP EXIT
|
|
|
|
|
|
;::::: BANKED SYSTEM
|
|
|
|
BNKDSYS: INC HL ; move ptr to UABNK in config area
|
|
LD DE,UABNK ; ..and make local copies
|
|
LD BC,5 ; (5 bytes, UABNK..MAXBNK)
|
|
LDIR
|
|
CALL CODEND ; get first available page after code end
|
|
LD (WSPCBEG),HL ; and store it
|
|
EX DE,HL ; swap regs
|
|
|
|
; memory read/write tests for all ram banks at addr 0x0000
|
|
; building a map in WSPC area: b1= zero if no bank found, b2= initially read byte
|
|
|
|
; test #1: 0x00/0xFF byte - iterate over banks in forward order
|
|
LD HL,0 ; set addr 0x0000
|
|
LD C,0 ; start with bank #0 (TPA)
|
|
MEMRW: CALL GETFRB ; get byte
|
|
LD B,A ; store in B
|
|
CPL ; invert (complement) byte
|
|
CALL SETINB ; write it back
|
|
CALL GETFRB ; read again
|
|
CPL ; ..and invert
|
|
XOR B ; xor'd with initially read byte
|
|
JR NZ,MEMRW0 ; ..if no match, skip over
|
|
LD A,B ; get initially read byte
|
|
CALL SETINB ; write it
|
|
CALL GETFRB ; and read again
|
|
SUB B ; subtract initially read byte
|
|
JR NZ,MEMRW0 ; ..if not zero, skip over
|
|
|
|
; injected opcode 0xF6 (OR n) to skip following XOR A
|
|
DEFB 0F6h ; = OR 0AFH (write non-zero)
|
|
MEMRW0: XOR A ; nullify A
|
|
LD (DE),A ; store in WSPC area
|
|
INC DE ; move ptr fwd
|
|
LD A,B ; get initially read byte
|
|
LD (DE),A ; store it, too
|
|
INC DE ; move ptr fwd
|
|
INC C ; bank # +1
|
|
JR NZ,MEMRW ; ..loop till all possible (256 / 0x100) banks tested
|
|
|
|
; test #2: write no. in each bank (iterate backward), then read and compare (forward)
|
|
DEC C ; correct bank # (loop was 1 ahead)
|
|
MEMWRB: DEC DE ; move ptr back
|
|
DEC DE
|
|
LD A,(DE) ; get byte
|
|
OR A ; check if bank exists
|
|
JR Z,MEMWRB0 ; ..if not, skip over
|
|
LD A,C ; else, get bank #
|
|
CALL SETINB ; and write in bank
|
|
MEMWRB0: LD A,C ; get bank #
|
|
SUB 1 ; -1
|
|
LD C,A ; set bank #
|
|
JR NC,MEMWRB ; ..if not below zero, loop
|
|
INC C ; correct bank #
|
|
|
|
MEMRDB: LD A,(DE) ; get byte from WSPC area
|
|
OR A ; check if bank exists
|
|
JR Z,MEMRDB0 ; ..if not, skip over
|
|
CALL GETFRB ; read byte from bank
|
|
CP C ; compare to bank #
|
|
JR Z,MEMRDB0 ; ..if match, skip over
|
|
XOR A ; else, set <NUL> as indicator
|
|
LD (DE),A ; that bank doesn't exist
|
|
MEMRDB0: INC DE ; move ptr fwd
|
|
INC DE
|
|
INC C ; bank # +1
|
|
JR NZ,MEMRDB ; ..loop till all possible (256 / 0x100) banks tested
|
|
|
|
; restore bytes initially read in all banks
|
|
LD DE,(WSPCBEG) ; set ptr to start of WSPC addr
|
|
MEMRST: LD A,(DE) ; get byte
|
|
OR A ; check bank exists
|
|
JR Z,MEMRST0 ; ..if not, skip over
|
|
INC DE ; move ptr fwd
|
|
LD A,(DE) ; get initially read byte
|
|
CALL SETINB ; ..and restore it
|
|
INC DE ; ptr fwd
|
|
JR MEMRST1 ; skip over
|
|
MEMRST0: INC DE ; ptr fwd
|
|
INC DE
|
|
MEMRST1: INC C ; bank # +1
|
|
JR NZ,MEMRST ; loop till done
|
|
; ..then fall through to display collected data
|
|
|
|
|
|
; display information for Banked System
|
|
; detect ranges of continuous ram banks
|
|
;
|
|
; HL= ptr in WSPC area
|
|
; C= counter (up) bank #, B= counter (down) for outer loop
|
|
; D= bank # begin of range, E= bank # end of range
|
|
LD BC,0
|
|
LD HL,(WSPCBEG) ; set ptr to start of WSPC addr
|
|
BRANGLP: LD A,(HL) ; get byte
|
|
OR A ; check bank exists
|
|
JR NZ,BRANGE ; ..if so, skip over
|
|
INC HL ; else, use a shorter loop
|
|
INC HL ; ..move ptr fwd
|
|
INC C ; ..and bank #
|
|
JR NZ,BRANGLP ; loop until max. reached (256 / 0x100)
|
|
JR PCNFIG ; else, display Bios config report
|
|
|
|
BRANGE: LD D,C ; store start of range (bank # in D)
|
|
BRANG0: INC HL ; ptr fwd
|
|
INC HL
|
|
INC C ; bank # +1
|
|
JR NZ,BRANG1 ; ..if not max., skip over
|
|
DEC B
|
|
JR PBRANG ; else, display bank ranges
|
|
|
|
BRANG1: LD A,(HL) ; get byte
|
|
OR A ; check bank exists
|
|
JR NZ,BRANG0 ; ..if so, loop
|
|
; else, fall through
|
|
|
|
; display collected information
|
|
PBRANG: LD E,C ; get current bank # in E
|
|
DEC E ; loop is ahead, so -1
|
|
CALL EPRINT
|
|
DEFB CR,LF,'RAM Banks '
|
|
DEFB 0
|
|
LD A,D ; get begin of range
|
|
CALL PAFDC ; ..and display it
|
|
CALL EPRINT
|
|
DEFB ' - '
|
|
DEFB 0
|
|
LD A,E ; get end of range
|
|
CALL PAFDC ; ..and display it
|
|
CALL EPRINT
|
|
DEFB ' ('
|
|
DEFB 0
|
|
LD A,E ; get end of range
|
|
INC A ; adjust for correct calc
|
|
SUB D ; calc difference of begin/end
|
|
PUSH HL
|
|
LD L,A ; get value in L
|
|
LD H,0 ; ..and multiply for display
|
|
ADD HL,HL ; *2
|
|
ADD HL,HL ; *4
|
|
ADD HL,HL ; *8
|
|
ADD HL,HL ; *16
|
|
ADD HL,HL ; *32 (fixed bank size of 32k assumed)
|
|
CALL PHLFDC ; ..and display
|
|
POP HL
|
|
CALL EPRINT
|
|
DEFB 'k Bytes)'
|
|
DEFB 0
|
|
LD A,B ; check if more to go
|
|
OR A
|
|
JR Z,BRANGLP ; loop till done
|
|
|
|
; display information as stored in B/P Bios config area
|
|
PCNFIG: CALL EPRINT
|
|
DEFB CR,LF,LF,'Bios Reports:',CR,LF
|
|
DEFB ' TPA Banks = '
|
|
DEFB 0
|
|
LD A,(TPABNK) ; get TPA bank #
|
|
PUSH AF ; save regs
|
|
CALL PAFDC ; and display it
|
|
LD A,'/'
|
|
CALL COUT
|
|
POP AF ; restore value
|
|
INC A ; +1 (TPA bank is build by 2 consecutive banks)
|
|
; fixed size of 32k per bank is assumed
|
|
CALL PAFDC ; and display it
|
|
CALL EPRINT
|
|
DEFB CR,LF,' System Bank = '
|
|
DEFB 0
|
|
LD A,(SYSBNK) ; get SYSTEM bank #
|
|
CALL PAFDC ; and display it
|
|
CALL EPRINT
|
|
DEFB CR,LF,' User Bank = '
|
|
DEFB 0
|
|
LD A,(UABNK) ; get # of USER banks
|
|
OR A
|
|
JR NZ,PCNFIG0 ; ..if not zero, skip over
|
|
CALL EPRINT
|
|
DEFB '(None)'
|
|
DEFB 0
|
|
JR PCNFIG1
|
|
PCNFIG0: CALL PAFDC ; display # of USER banks
|
|
PCNFIG1: CALL EPRINT
|
|
DEFB CR,LF,' RAM Disk Start = '
|
|
DEFB 0
|
|
LD A,(RAMBNK) ; get # of begin RAM Disk
|
|
CALL PAFDC
|
|
CALL EPRINT
|
|
DEFB CR,LF,' Last Used Bank = '
|
|
DEFB 0
|
|
LD A,(MAXBNK) ; get max. available bank #
|
|
CALL PAFDC
|
|
CALL EPRINT
|
|
DEFB CR,LF,LF,' -- Scan Complete.',CR,LF
|
|
DEFB 0
|
|
JP EXIT
|
|
|
|
|
|
;::::: SUPPORT FUNCTIONS
|
|
|
|
; get first token from command line (in FCB #1)
|
|
; and check if help was requested
|
|
CHKHELP: LD HL,CPMFCB+1
|
|
LD A,(HL) ; get byte
|
|
CP '/' ; is this a help request ?
|
|
RET NZ ; ..if not, return
|
|
INC HL ; else, move ptr fwd
|
|
LD A,(HL) ; and get next byte
|
|
CP '/' ; is it also '/' ?
|
|
RET NZ ; ..if not, return
|
|
; else, fall through and display help
|
|
|
|
|
|
;::::: HELP SCREEN
|
|
|
|
HELP: CALL EPRINT
|
|
DEFB CR,LF,' '
|
|
DEFB 0
|
|
CALL PPRGNAM
|
|
CALL EPRINT
|
|
DEFB ' Determines location and Size of Banked Memory.',CR,LF
|
|
DEFB ' (Only TPA Banks printed if Non-Banked)',CR,LF,LF
|
|
DEFB ' Syntax:',CR,LF
|
|
DEFB ' '
|
|
DEFB 0
|
|
CALL PPRGNAM
|
|
CALL EPRINT
|
|
DEFB ' - Print 32k RAM banks present and B/P Allocations',CR,LF
|
|
DEFB ' '
|
|
DEFB 0
|
|
CALL PPRGNAM
|
|
CALL EPRINT
|
|
DEFB ' // - display this screen',CR,LF
|
|
DEFB 0 ; fall through and exit
|
|
|
|
|
|
;::::: EXIT PROGRAM
|
|
|
|
EXIT: CALL CRLF
|
|
LD SP,(STACK) ; restore stack pointer
|
|
RET ; ..and return to system
|
|
|
|
|
|
;::::: SUPPORT FUNCTIONS
|
|
|
|
; check if running under ZCPR3 and status of wheel byte
|
|
; terminate program if not succesful
|
|
CHKZ3E: LD HL,(CPMBDOS+1)
|
|
CALL WHRENV ; find Z3 Environment Descriptor
|
|
LD (ENVADR),HL ; store ENV ptr
|
|
LD A,H ; check if invalid (= zero)
|
|
OR L
|
|
JP Z,E$BPBIO ; ..if so, jump error and terminate
|
|
CALL Z3INIT ; else, init for Z3LIB routines
|
|
LD A,41 ; offset to addr of wheel byte (Z3WHL)
|
|
CALL ADDHLA ; adjust ptr
|
|
LD E,(HL) ; get addr in DE
|
|
INC HL
|
|
LD D,(HL)
|
|
EX DE,HL ; swap regs
|
|
LD A,(HL) ; get value of wheel byte
|
|
AND A ; check if zero
|
|
RET NZ ; ..if not (wheel on), return
|
|
CALL EPRINT ; else, display message and exit
|
|
DEFB BEL,CR,LF,'Must be wheel to Execute !',CR,LF
|
|
DEFB 0
|
|
JR EXIT
|
|
|
|
|
|
; check if running under B/P Bios
|
|
; if not, program is terminated
|
|
CHKSYS: LD HL,(CPMBIOS+1) ; get warm boot addr (BIOS fn #1)
|
|
LD L,30*3 ; adjust ptr to fn #30
|
|
LD A,(HL) ; check byte at ptr location
|
|
CP 0C3H ; is it opcode 0xC3 (JP) ?
|
|
JR NZ,E$BPBIO ; ..if not, jump error and terminate
|
|
CALL JUMPHL ; else, "call" B/P Bios fn #30 (RETBIO)
|
|
LD (BPVERS),A ; store version of B/P Bios
|
|
LD (BPADDR),BC ; " base addr
|
|
LD (BPCNFG),DE ; " config area addr
|
|
LD HL,-6 ; move ptr 6 bytes backward
|
|
ADD HL,DE ; (signature string)
|
|
LD A,(HL) ; get byte
|
|
CP 'B' ; is it 'B' ?
|
|
JR NZ,E$BPBIO ; ..if not, jump error and exit
|
|
INC HL ; ptr fwd
|
|
LD A,(HL) ; get byte
|
|
CP '/' ; is it '/' ?
|
|
JR NZ,E$BPBIO ; ..if not, jump error and exit
|
|
INC HL ; ptr fwd
|
|
LD A,(HL) ; get byte
|
|
CP 'P' ; is it 'P' ?
|
|
RET Z ; ..if so, return
|
|
; else, fall through (error and exit)
|
|
|
|
|
|
; msg aborting
|
|
E$BPBIO: CALL EPRINT
|
|
DEFB CR,LF,BEL,'Not B/P Bios, aborting...!',CR,LF
|
|
DEFB 0
|
|
RST 0
|
|
|
|
|
|
; print program name on CON: device
|
|
; (either the actual name, or fallback to default)
|
|
; only used by HELP
|
|
PPRGNAM: LD A,(ENVADR+1) ; get high byte of ENVPTR
|
|
OR A ; check if valid (<> zero)
|
|
JP NZ,PRTNAME ; ..if so, display actual name
|
|
; ..and let return from there
|
|
CALL EPRINT ; else, display default
|
|
DEFB 'SIZERAM'
|
|
DEFB 0
|
|
RET
|
|
|
|
|
|
; msg B/P Bios Vers x.x
|
|
M$BVER: CALL EPRINT
|
|
DEFB ' (B/P Bios Vers '
|
|
DEFB 0
|
|
LD A,(BPVERS) ; get version #
|
|
RRCA ; reverse nybbles in A
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
AND 00001111b ; mask lower nybble
|
|
ADD A,'0' ; make it ascii
|
|
CALL COUT ; ..and display
|
|
LD A,'.'
|
|
CALL COUT
|
|
LD A,(BPVERS) ; get version #
|
|
AND 00001111b ; mask lower nybble
|
|
ADD A,'0' ; make it ascii
|
|
CALL COUT ; ..and display
|
|
CALL EPRINT
|
|
DEFB ')',CR,LF
|
|
DEFB 0
|
|
RET
|
|
|
|
|
|
; add A to HL (result in HL)
|
|
ADDHLA: ADD A,L ; add L
|
|
LD L,A ; store result in L
|
|
RET NC ; ..if no overflow, return
|
|
INC H ; else, increment H
|
|
RET
|
|
|
|
|
|
; the following routines rearrange Top of Stack by injecting an
|
|
; intermediate return addr, and putting the Bios fn call on top
|
|
; so that HL regs are preserved
|
|
; order of steps:
|
|
; [1] HL (= addr) is pushed onto stack
|
|
; [2] intermediate return addr is swapped to Top of Stack
|
|
; [3] HL (= addr) is pushed onto stack again
|
|
; [4] Bios fn JP addr is swapped to Top of Stack
|
|
; [5] Bios is "called" through RET, and returns to intermediate addr
|
|
|
|
; get byte from ram bank - in the form LD A,(HL)
|
|
; in: C= bank #, HL= addr
|
|
; out: A= byte
|
|
GETFRB: PUSH BC
|
|
PUSH HL ; save addr
|
|
LD HL,GETFRB0 ; load return addr
|
|
EX (SP),HL ; put it on stack
|
|
PUSH HL ; save HL again (previous top of stack)
|
|
LD HL,(BPADDR) ; get B/P Bios base addr
|
|
LD L,35*3 ; adjust ptr to fn #35 (FRGETB)
|
|
EX (SP),HL ; put addr on stack
|
|
RET ; ..and "call" Bios fn through stack
|
|
|
|
GETFRB0: POP BC ; restore regs
|
|
RET ; ..and finally return
|
|
|
|
; set byte in ram bank - in the form LD (HL),A
|
|
; in: C= bank #, HL= addr, A= byte to set
|
|
SETINB: PUSH BC
|
|
PUSH HL ; save addr
|
|
LD HL,GETFRB0 ; load return addr
|
|
EX (SP),HL ; put it on stack
|
|
PUSH HL ; save HL again (previous top of stack)
|
|
LD HL,(BPADDR) ; get B/P Bios base addr
|
|
LD L,37*3 ; adjust ptr to fn #37 (FRPUTB)
|
|
EX (SP),HL ; put addr on stack
|
|
RET ; ..and "call" Bios fn through stack
|
|
|
|
|
|
; "called" as a pseudo-routine that returns to caller
|
|
; in: HL= target addr
|
|
JUMPHL: JP (HL) ; jump to addr in HL regs
|
|
|
|
|
|
;::::: LOCAL DATA (not in DSEG)
|
|
|
|
WSPCBEG: DEFW 0 ; addr begin of workspace area
|
|
; (first available page, returned by CODEND)
|
|
|
|
; data retrieved from running system
|
|
BPVERS: DEFB 0 ; B/P Bios version
|
|
BPADDR: DEFW 0 ; B/P Bios base addr
|
|
BPCNFG: DEFW 0 ; addr of Config Area
|
|
BPBNKD: DEFB 0 ; indicator banked system (bit 0 of OPTF1) --> not used
|
|
|
|
; local copies of RAM bank configuration
|
|
UABNK: DEFB 0 ; beginning of User Bank(s)
|
|
TPABNK: DEFB 0 ; TPA Bank
|
|
SYSBNK: DEFB 0 ; beginning of System Bank(s)
|
|
RAMBNK: DEFB 0 ; base bank # for Ram Disk
|
|
MAXBNK: DEFB 0 ; highest permissible Bank #
|
|
|
|
|
|
DEFS 30H ; room for stack
|
|
STACK: DEFW 0 ; stack storage location
|
|
|
|
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; Z3LIB - 0x05ae
|
|
; SYSLIB - 0x065c
|
|
; end addr 0x0750 (begin DSEG)
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
|
|
;::::: RAM STORAGE
|
|
|
|
DSEG
|
|
|
|
END
|
|
|
|
|
|
;************************************************************************
|
|
; Remarks jxl:
|
|
; SIZERAM.COM, included in available B/P Bios package(s), was dis-
|
|
; assembled and extensively commented. Labels are up to seven chars long
|
|
; to comply with M-REL standards. However, it is recommended to use SLR
|
|
; tools that support labels up to sixteen chars.
|
|
; In its current state, the compiled/linked file matches exactly the
|
|
; original INITRAM.COM, i.e. no changes to the source were made.
|
|
;
|
|
; The program uses an interesting technique to read and write data in
|
|
; alternative ram banks utilizing B/P Bios functions no. 35 FRGETB and
|
|
; no. 37 FRPUTB. Top of Stack is manipulated to keep registers intact
|
|
; and "call" functions through a RET statement (instead of CALL.)
|
|
; Another specialty which is worth mentioning: Routine MEMRW (memory
|
|
; read/write) contains an "injected" opcode to alter the behaviour at
|
|
; runtime. Otherwise a more complex logic and/or additional routine
|
|
; would have been necessary.
|
|
; Storage of local data is in CSEG (code segment), not DSEG. There
|
|
; seems to be no particular reason for this. So, it can be assumed that
|
|
; this just happened by mistake.
|
|
;************************************************************************
|
|
|