Zero-page memory maps of the PET that I've found claim that the zero page address range$00C2..$00D9
are used for static data, e.g. http://www.classiccmp.org/dunfield/pet/petmem.txt says:
RIDATA 00C2 Cassette Temp (64#00AA) read flags: 0=scan,
1-15=count, $40=load, $80=end of tape marker
RIPRTY 00C3 Cassette Short Cnt (64#00AB): counter of seconds
before tape write / checksum
PNT 00C4-00C5 Pointer: Current Screen Line Address
PNTR 00C6 Cursor Column on Current Line
SAL 00C7-00C8 Pointer: Tape Buffer/ Screen Scrolling
EAL 00C9-00CA Tape End Addresses/End of Program
CMP0 00CB-00CC Tape Timing Constants
QTSW 00CD Flag: Editor in Quote Mode, $00 = NO
BITTS 00CE Cassette Temp (64#00B4): Tape read timer flag
=IRQ enabled for Timer 1
00CF End of tape read
00D0 Read character error
FNLEN 00D1 Length of Current File Name
LA 00D2 Current Logical File Number
SA 00D3 Current Secondary Address
FA 00D4 Current Device Number
LNMX 00D5 Physical Screen Line Length
00D5 4.80: right side of window
TAPE1 00D6-00D7 Pointer: Start of Tape Buffer
TBLX 00D8 Current Cursor Physical Line Number
DATAX 00D9 Current Character to Print
However, looking at the ROM disassembly, one can find places where the address $00C2
is jumped to, e.g. http://www.zimmers.net/anonftp/pub/cbm/firmware/computers/pet/d/rom-1.html#C70A :
C70A 4C C2 00 JMP iC2
Looking at a disassembly starting at $00C2
after booting up a PET, I can see reasonable-looking code:
.C:00c2 E6 C9 INC $C9
.C:00c4 D0 02 BNE $00C8
.C:00c6 E6 CA INC $CA
.C:00c8 AD 00 04 LDA $0400
.C:00cb C9 3A CMP #$3A
.C:00cd B0 0A BCS $00D9
.C:00cf C9 20 CMP #$20
.C:00d1 F0 EF BEQ $00C2
.C:00d3 38 SEC
.C:00d4 E9 30 SBC #$30
.C:00d6 38 SEC
.C:00d7 E9 D0 SBC #$D0
.C:00d9 60 RTS
What is this area used for? Where is the code that assembles this program into this area? What's this code supposed to do? (It seems to be scanning the area starting at $0400
for :
and characters?)
It's part of the BASIC interpreter loop. It reads one byte of the tokenized BASIC program, setting zero flag if it's a colon or a zero byte and clearing the carry if it's a number. You can see it used in the main part of the interpreter loop at address C6B5.
I'm not sure why this routine was placed in zero page. It's a cycle (or rarely two) faster to use LDA $0400
over LDA ($C9),Y
, but I can't see it actually making much difference.
I should also note that the ROM disassembly you're looking at appears to be for a BASIC 1.0 ROM, while the memory map you've referenced is for versions 2.0 and 4.0.
Here's what Mapping the Commodore 64 by Sheldon Leemon says about the equivalent C64 routine:
115-138 $73-$8A CHRGET
Subroutine: Get Next BASIC Text Character...
CHRGET is a crucial routine which BASIC uses to read text characters, such as the text of the BASIC program which is being interpreted. It is placed on zero page to make the routine run faster. Since it keeps track of the address of the character being read within the routine itself, the routine must be in RAM in order to update that pointer. The pointer to the address of the byte currently being read is really the operand of a LDA instruction. When entered from CHRGET, the routine increments the pointer by modifying the operand at TXTPTR (122, $7A), thus allowing the next character to be read.
Entry at CHRGOT (121, $79) allows the current character to be read again. The CHRGET routine skips spaces, sets the various flags or the status register (.P) to indicate whether the character read was a digit, statement terminator, or other type of character, and returns with the retrieved character in the Accumulator (.A).
...
As this is such a central routine, a disassembly listing is given below to provide a better understanding of how it works.
115 $73 CHRGET INC TXTPTR ; increment low byte of TXTPTR 117 $75 BNE CHRGOT ; if low byte isn't 0, skip next 119 $77 INC TXTPTR+1 ; increment high byte of TXTPTR 121 $79 CHRGOT LDA ; load byte from where TXTPTR points ; entry here does not update TXTPTR, ; allowing you to readl the old byte again 122 $7A TXTPTR $0207 ; pointer is really the LDA operand ; TXTPTR+1 points to 512-580 ($200-$250) ; when reading from the input buffer ; in direct mode 124 $7C POINTB CMP #$3A ; carry flag set if > ASCII numeral 9 126 $7E BCS EXIT ; character is not a numeral--exit 128 $80 CMP #$20 ; if it is an ASCII space... 130 $82 BEQ CHRGET ; ignore it and get next character 132 $84 SEC ; prepare to subtract 133 $85 SBC #$30 ; ASCII 0-9 are between 48-57 ($30-$39) 135 $87 SEC ; prepare to subtract again 136 $88 SBC #$D0 ; if < ASCII 0 (57, $39) then carry is set 138 $8A EXIT RTS ; carry is clear only for numeral on return
The Accumulator (.A register) holds the character that was read on exit from the routine. Status register (.P) bits which can be tested for on exit are:
Carry Clear if the character was an ASCII digit 0-9. Carry Set, otherwise. Zero Set only if the character was a statement terminator 0 or an ASCII colon, 58 ($3A). Otherwise, Zero Clear.
It's self modifying code, notice the embedded pointer at $C9
. The source for it is at $E0B4
, and it's copied to the zero page by code at $E0E5
.
Looks like it is indeed scanning text, and classifying the current character. It will set ZF
if the character is a space, and CF
will be clear if it is a digit. As such it seems useful for converting string to number, but that's just a guess.
Update: An example routine that uses this code is at $C863
. It is certainly doing some string-to-number conversion, you can recognize the pattern that calculates result = result * 10 + (current_char - '0')
in a loop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With