CBM 5/6/700 - Basic 4+ ROM Chart
The ROM chart gives the addresses for the three ROM sets that I had in my possession in the 1980s. They were for the 500 and the 128K and 256K versions of the 6/700 - my 600 possessed the 128K version ROMs and I was later sent a dump of the 256K version. There were various other early versions of the 6/700 128/256K set which contained the coding for cassette operation plus countless bugs.
It is also possible that 64K and even 192K versions could have existed as the original source code could be compiled for these memory sizes (the 500 was originally specified as having only 64K). Of the three listed here, the 500 is the oldest and has several bugs - of the 6/700 ROMs the 256K appears slightly older as it has a couple of patches missing that appear in the 128K version. Note that all were in EPROM though the early versions for the 700 that allowed cassette operation were, I believe, made as mask-programmed ROMs.
Nowadays a quick search of the Internet will provide links to various other ROM sets. A good selection can be obtained from funet.fi.
500 | 128K | 256K | Description |
---|---|---|---|
8000 | 8000 | 8000 | Cold Start entry point |
8003 | 8003 | 8003 | Warm Start entry point |
8006 | 8006 | 8006 | CBM8 in ASCII |
POINTERS AND KEYWORDS | |||
500 | 128K | 256K | Description |
800A | 800A | ---- | SPACE and then pointers to various ROM routines such as EVAL, New statement etc. (128K systems only) |
8027 | 8027 | 800A | Addresses (-1) of END to NEW |
806D | 806D | 8050 | Addresses (-1) of GO to PUDEF |
80A3 | 80A3 | 8086 | Addresses of SGN to MID$ |
80D1 | 80D1 | 80B4 | Addresses (-1) and hierarchy of operators |
80EF | 80EF | 80D2 | Table of keywords with last byte of each + 128 |
828F | 828F | 8272 | Pointers (addresses) of error messages at $82E7 onwards |
82E7 | 82E7 | 82CC | Table of error (and other) messages. 256K version has extra message OUT OF ARRAY SPACE |
LINE INPUT AND BASIC PROCESSING | |||
500 | 128K | 256K | Description |
8550 | 8550 | 8548 | ?OUT OF MEMORY error |
8555 | 8555 | 854D | If TRAP is on then jump to TRAP routine else print error message (indicated by .X register) and then... |
85AB | 85AB | 85A3 | Print IN plus line number and then... |
85C0 | 85C0 | 85B8 | Print READY. and then... |
85CA | 85CA | 85C2 | Await next entry (via RAM vector at $0282) |
85F3 | 85F3 | 85EB | Process new BASIC line |
869B | 869B | 8693 | Rechain BASIC and await next entry |
86A4 | 86A4 | 869C | Rechain BASIC subroutine |
86E3 | 86E3 | 86DB | Input line into BASIC buffer (160 characters maximum) |
871F | 871F | 8717 | Find a line number (compare with $1B/C) |
8751 | 8751 | 8749 | Process next BASIC statement (with STOP key check) |
8763 | 8763 | 875B | Move to next BASIC line (with check for end of program) |
877B | 877B | 8773 | Do end of line/statement checks |
87A8 | 87A8 | 87A0 | Process BASIC keyword - if no keyword then assume LET |
87D1 | 87D1 | 87C9 | Check for end of statement |
87DB | 87DB | 87D3 | Check the stack for a FOR entry |
8815 | 8815 | 880D | Open up a space in memory (enter with carry clear for bank 1 else bank 2 (500 is bank 0 and bank 1 respectively) |
8866 | 8866 | 885C | Check space available on the stack |
8877 | 8877 | 886D | Check for overlap in variable memory |
88A6 | 88A6 | 887C | Get the bank and pointer to a variable and then... |
88A9 | 88A9 | 887F | ...store in FOR/NEXT pointer area |
88B0 | 88B0 | 8886 | Check memory in program bank (?OUT OF TEXT error if none left) |
---- | ---- | 8895 | Check memory in array bank (256K only) and give OUT OF ARRAY SPACE error if none left |
88BF | 88BF | 88A6 | Tokenise a BASIC line |
893F | 893F | 8926 | Shift down contents of BASIC buffer by .Y bytes after each keyword has been tokenised |
8957 | 8957 | 893E | Tokenise a keyword into a single byte |
PROCESS KEYWORDS | |||
500 | 128K | 256K | Description |
898D | 898D | 8974 | LIST |
89F1 | 89F1 | 89D8 | LIST vector jump via $0286 |
8A29 | 8A29 | 8A10 | NEW and then... |
8A45 | 8A45 | 8A2C | CLR and then... |
8A72 | 8A72 | 8A5D | Reset RESTORE pointer and stack |
8A90 | 8A90 | 8A7B | Table of PUDEF default values (Space, comma, dot, dollar) |
8A94 | 8A94 | 8A7F | FOR |
8AE7 | 8AE7 | 8AD2 | Check for STEP value |
8B06 | 8B06 | 8AF1 | NEXT |
8B79 | 8B79 | 8B64 | RESTORE |
8B97 | 8B97 | 8B82 | Reset RESTORE pointer to the start of the program |
8BA8 | 8BA8 | 8B93 | STOP entry |
8BAA | 8BAA | 8B95 | END entry |
8BAF | 8BAF | 8B9A | BREAK entry |
8BE9 | 8BE9 | 8BD4 | CONT |
8C07 | 8C07 | 8BF2 | RUN |
8C25 | 8C25 | 8C10 | GOSUB |
8C42 | 8C42 | 8C2D | IF |
8C4F | 8C4F | 8C3A | Check for GOTO and THEN |
8C68 | 8C68 | 8C53 | Check for ELSE |
8C77 | 8C77 | 8C62 | Code for REM and ELSE to ignore the rest of the line |
8C7C | 8C7C | 8C6A | GO (checks for TO following) and then does... |
8C84 | 8C84 | 8C6F | GOTO |
8CB8 | 8CB8 | 8CA3 | RETURN |
8CDF | 8CDF | 8CCA | DATA when come across during normal execution (not via READ) and so ignores all characters up to either the next statement or line. This routine is also used as the final part of RETURN so that after the GOSUB pointers have been restored from the stack the TXTPTR is incremented past the actual GOSUB itself ready for the next statement or line |
8CED | 8CED | 8CD8 | Search for next BASIC statement |
8CF0 | 8CF0 | 8CDB | Search for next BASIC line |
8D16 | 8D16 | 8D01 | TRAP |
8D2B | 8D2B | 8D16 | ON |
8D4E | 8D4E | 8D39 | Get line number from BASIC in $1B/C |
8D88 | 8D88 | 8D73 | LET (default entry to $8D8A/8D8A/8D75 if no keyword found from process BASIC keyword routine) |
8DC4 | 8DC4 | 8DAF | RESUME |
8DFF | 8DFF | 8DEA | Restore current line number and TXTPTR |
8E24 | 8E24 | 8E0F | DISPOSE |
8E7A | 8E7A | 8E65 | PRINT# (does CMD and then PRINT) |
8E80 | 8E80 | 8E6B | CMD |
8E97 | 8E97 | 8E82 | |
8E9D | 8E9D | 8E88 | PRINT initial entry point |
8EC8 | 8EC8 | 8EB3 | Print CRLF (part of PRINT) |
8F15 | 8F15 | 8F00 | GET and GET# |
8F4B | 8F4B | 8F36 | INPUT# |
8F59 | 8F59 | 8F44 | Restore normal I/O |
8F66 | 8F66 | 8F51 | INPUT |
8FA8 | 8FA8 | 8F93 | Routine to get a line (from any device) into the input buffer |
8FB5 | 8FB5 | 8FA0 | Move to next line during READ |
8FEA | 8FEA | 8FD5 | READ (parts also used by GET and INPUT) |
8FF1 | 8FF1 | 8FDC | INPUT entry into READ routine |
8FF3 | 8FF3 | 8FDE | GET entry into READ routine |
906B | 906B | 9056 | Get TXTPTR (then add carry flag) into .A/Y and bank number into .X |
9077 | 9077 | 9062 | READ continued |
90E7 | 90E7 | 90D2 | SYS (allows jumps to any bank 600/700 - bank 15 only on the 500 as this has a small routine missing compared to the 6/700 - it is a coincidence that the addresses for the 500 correspond to those of the 256K version from this point onwards until the BLOAD command) |
90F4 | 9109 | 90F4 | DIM |
9101 | 9116 | 9101 | DEF |
9131 | 9146 | 9131 | POKE |
913D | 9152 | 913D | WAIT |
9160 | 9175 | 9160 | Set bank for POKE, WAIT etc. |
916A | 917F | 916A | KEY (checks for following parameter and does assignment if it exists else prints all current definitions) |
91A1 | 91B6 | 91A1 | Input a string expression from BASIC (such as KEY definition) |
I/O AND DISK HANDLING KEYWORDS | |||
500 | 128K | 256K | Description |
91A7 | 91BC | 91A7 | VERIFY |
91B3 | 91C8 | 91B3 | LOAD |
91B8 | 91CD | 91B8 | Does rechain BASIC and CLR after LOAD else flags errors into ST |
91E4 | 91F9 | 91E4 | Common LOAD/VERIFY coding |
9206 | 921B | 9206 | SAVE |
922E | 9243 | 922E | OPEN |
9266 | 927B | 9266 | Get filename parameters and then... |
9269 | 927E | 9269 | Clear channels and do OPEN |
9272 | 9287 | 9272 | Get the current character (via CHRGOT) and check for end of line and, if not, then... |
927C | 9291 | 927C | Get the next parameter as an integer into .X |
9282 | 9297 | 9282 | CLOSE |
928C | 92A1 | 928C | CATALOG and DIRECTORY |
933B | 9350 | 933B | Clear channels and then set output device |
9346 | 935B | 9346 | Open channel 14 to device 8 for disk commands |
9358 | 936D | 9358 | DOPEN (Note that all the disk commands use general parameter handling routines that start at B514/B540/B4A2) |
9369 | 937E | 9369 | APPEND |
9379 | 938E | 9379 | Check entered line and then look for an unused secondary address to use to send the command to the disk |
9394 | 93A9 | 9394 | DCLOSE |
93A8 | 93BD | 93A8 | Get device number in .A and close all open files on that device (via $FFE7 close all files call) |
93AE | 93C3 | 93AE | DSAVE |
93B9 | 93CE | 93B9 | DLOAD |
93C9 | 93DE | 93C9 | BANK |
93D7 | 93EC | 93D7 | BSAVE |
93F9 | 940E | 93F9 | BLOAD. The coding for the 500 differs and appears to be of an older (possibly bugged) format - take care with this command! |
941D | 9427 | 9412 | HEADER |
945A | 9464 | 944F | SCRATCH |
9494 | 949E | 9489 | RECORD |
9500 | 950A | 94F5 | DCLEAR (this command is not mentioned in some manuals and is the equivalent to OPEN15,8,15,'I0' to initialise, not format, the disk in drive 0. Use DCLEAR D1 for drive 1) |
9509 | 9513 | 94FE | COLLECT |
9520 | 952A | 9515 | COPY |
953C | 9546 | 9531 | CONCAT |
9548 | 9552 | 953D | RENAME |
9556 | 9560 | 954B | BACKUP |
9567 | 9578 | 955C | Set up DOS buffer and send DOS command |
957B | 9585 | 9570 | Checksum byte ($19, $22 and $C0) |
---- | 9586 | 9571 | Clear DS and ST and then set output device (patch) |
---- | 958C | 9577 | Clear DS and ST and then set input device (patch) |
---- | 9592 | ---- | Close files on device held in .A (patch) |
957C | 9596 | 957D | Unused ROM area |
MATHS HANDLING ROUTINES | |||
500 | 128K | 256K | Description |
95AD | 95C1 | 95AC | Evaluate expression (via vector at $028C) |
9632 | 9646 | 9631 | Recursive entry for evaluate expression |
9645 | 9659 | 9644 | Save the rounded value of FAC#1 on the stack |
966E | 9682 | 966D | Pull FAC#1 from stack |
969A | 96AE | 9699 | Get number or variable from BASIC (also check for PI) |
96A9 | 96BD | 96A8 | Check for PI (tokenised as $FF) |
96B7 | 96CB | 96B6 | PI in floating point format |
96DC | 96F0 | 96DB | Check for NOT |
96F3 | 9707 | 96F2 | Check for FN |
96FA | 970E | 96F9 | Check for a valid function token |
9710 | 9724 | 970F | Evaluate expression in brackets |
9716 | 972A | 9715 | Check for right bracket ')' else SYNTAX ERROR |
9719 | 972D | 9718 | Check for left bracket '(' else SYNTAX ERROR |
971C | 9730 | 971B | Check for comma else SYNTAX ERROR |
971E | 9732 | 971D | Check for character in .A else SYNTAX ERROR |
973B | 974F | 973A | Error message SYNTAX ERROR |
9740 | 9754 | 973F | Get the value of a variable |
975A | 976E | 9759 | Check for TI$ and then DS$ |
9786 | 979A | 9785 | Get DS$ from disk (if not already found) |
978D | 97A1 | 978C | Get integer/floating point variable value |
97A5 | 97B9 | 97A4 | Get floating point variable value |
97B3 | 97C7 | 97B2 | Check for ST, ER, EL and DS variables |
980D | 9821 | 980C | Execute functions via jump (JSR) to $0061 |
9857 | 986B | 9856 | OR |
985A | 986E | 9859 | AND |
9894 | 98A8 | 9893 | Do comparisons (<, >, =, <=, >=, <>) |
9918 | 992C | 9917 | Get the name and pointer to a variable |
99AB | 99BF | 99AA | Check that .A holds 'A' to 'Z' |
99B5 | 99C9 | 99B4 | Variable not found so if called from $9740/$9754/$973F then use dummy value of zero else... |
99CA | 99DE | 99C9 | Set up variable (with checks for TI$, ST, ER, EL, DS and DS$). The coding for the 256K version is a lot smaller as there is no need for checks on the other variable boundaries as they are in the other banks |
9AE1 | 9AF5 | 9A3B | Calculate the pointer to an array body |
9AF2 | 9B06 | 9A4C | Convert a string to an integer value |
9AFF | 9B13 | 9A59 | Convert a floating point value to an integer |
9B14 | 9B28 | 9A6E | Get the pointer to an array variable |
9B90 | 9BA4 | 9AEA | BAD SUBSCRIPT error |
9B93 | 9BA7 | 9AED | ILLEGAL QTY error |
9BB2 | 9BC6 | 9B0C | Set .X to length of array element (length depends on array type) |
9BBC | 9BD0 | 9B16 | Allocate array |
9CB0 | 9CC4 | 9C0A | Calculate the length for an array with a check for enough memory |
9CE1 | 9CF5 | 9C3B | FRE (return 0 for all except program or variable banks) |
9CF4 | 9D08 | 9C4E | Calculate free memory in bank 1 (500 bank 0) |
---- | ---- | 9C5F | Calculate free memory in bank 3 |
9D05 | 9D19 | 9C72 | Calculate free memory in bank 2 (500 bank 1) |
---- | ---- | 9C85 | Calculate free memory in bank 4 |
9D1A | 9D29 | 9C95 | Set value to 0 (for all other banks for FRE) |
9D1D | 9D2C | 9C98 | Print .A/Y as a value of 0 to 65535 |
9D24 | 9D33 | 9C9F | POS |
9D28 | 9D37 | 9CA3 | Print value in .Y |
9D2A | 9D39 | 9CA5 | Print .A/Y as value -32768 to 32767 |
9D30 | 9D3F | 9CAB | Put .A/Y into FAC#1 (ready for printing as a value) |
9D3B | 9D4A | 9CB6 | Check for direct mode and, if so, do ILLEGAL DIRECT error |
9D43 | 9D52 | 9CBE | UNDEF'D FUNCTION error |
9D48 | 9D57 | 9CC3 | Check for direct mode |
9D4D | 9D5C | 9CC8 | Do FN functions |
9D62 | 9D71 | 9CDD | Expand FN call |
9DF8 | 9E07 | 9D73 | PEEK |
9E18 | 9E27 | 9D93 | Load .A/Y with the address of the floating point to integer conversion number |
9E1E | 9E2D | 9D99 | Move memory to FAC#2 and then... |
9E21 | 9E30 | 9D9C | Change FAC#1 sign and do addition |
9E2D | 9E3C | 9DA8 | Set .X/Y to the top of the program bank (-1) as a pointer to the BASIC input buffer |
9E36 | 9E45 | 9DB1 | Do addition |
9ECB | 9EDA | 9E46 | Zero FAC#1 exponent and sign |
9ED2 | 9EE1 | 9E4D | Add FAC#2 to FAC#1 (result in FAC#1) |
9EF1 | 9F19 | 9E6C | Shift FAC#1 right one bit |
9F1B | 9F2A | 9E96 | Twos complement FAC#1 |
9F40 | 9F4F | 9EBB | Increment FAC#1 by one bit |
9F4F | 9F5E | 9ECA | OVERFLOW error |
9F54 | 9F63 | 9ECF | Multiply |
9F8D | 9F9C | 9F08 | Table of floating point values (1 and LOG constants) |
9FBB | 9FCA | 9F36 | LOG |
9FF9 | A008 | 9F74 | Continue multiplication |
A04D | A05C | 9FC8 | Move memory (pointer is $22/3) to FAC#2 |
A07F | A08E | 9FFA | Multiply exponents overflow check |
A09C | A0AB | A017 | Handle under/overflow |
A0AA | A0B9 | A025 | Multiply FAC#1 by 10 |
A0C1 | A0D0 | A03C | Value 10 in floating point format |
A0C6 | A0D5 | A041 | Divide FAC#1 by 10 |
A0CF | A0DE | A04A | Divide FAC#2 by memory (pointer is $22/3) |
A0D7 | A0E6 | A052 | Division |
A139 | A148 | A0B4 | DIVISION BY ZERO error |
A14B | A15A | A0C6 | Move $28-B (multiply area) into FAC#1 |
A157 | A166 | A0D2 | Move memory (pointer $22/3) to FAC#1 |
A182 | A191 | A0FD | Move FAC#1 to memory (variable bank) |
A1C4 | A1D3 | A13F | Move FAC#2 to FAC#1 |
A1D4 | A1E3 | A14F | Round FAC#1 and then move it to FAC#2 |
A1E3 | A1F2 | A15E | Round FAC#1 |
A1F3 | A202 | A16E | Find sign of FAC#1 |
A201 | A210 | A17C | SGN |
A220 | A22F | A19B | ABS |
A223 | A232 | A19E | Compare FAC#1 to memory (bank 15 - pointer is $25/6) |
A269 | A278 | A1E4 | Get a byte from bank 15 (pointer is $25/6) |
A271 | A280 | A1EC | Convert FAC#1 to integer |
A2A2 | A2B1 | A21D | INT |
A2C9 | A2D8 | A244 | Convert an ASCII string to a number in FAC#1 |
A340 | A34F | A2BB | Add the next ASCII numeral to FAC#1 mantissa |
A354 | A363 | A2CF | Add .A to FAC#1 |
A396 | A3A5 | A311 | Table of string conversion constants |
A3A5 | A3B4 | A320 | Print .A/X as a number (0 - 65535) - usually a line number |
A3B4 | A3C3 | A32F | Print error message (.X is index to error type) |
A3D3 | A3E2 | A34E | Convert FAC#1 to an ASCII string at $0200 |
A4FE | A50D | A479 | Second table of string constants |
A528 | A537 | A4A3 | SQR |
A532 | A541 | A4AD | Do power '^' |
A576 | A585 | A4F1 | LOG Constants table |
A5A4 | A5B3 | A51F | EXP |
A5F6 | A605 | A571 | SIN/ATN function evaluation |
A60C | A61B | A587 | SIN/COS/LOG function evaluation |
A642 | A651 | A5BD | RND constants table |
A64A | A659 | A5C5 | RND |
A697 | A6A6 | A612 | COS |
A69E | A6AD | A619 | SIN |
A6E9 | A6F8 | A664 | TAN |
A713 | A722 | A68E | Do Cosine of FAC#1 |
A717 | A726 | A692 | SIN/COS/TAN constants table |
A745 | A754 | A6C0 | ATN constants table |
A782 | A791 | A6FD | ATN |
STRING HANDLING ROUTINES | |||
500 | 128K | 256K | Description |
A7B1 | A7C0 | A72C | PUDEF |
A7CC | A7DB | A747 | STR$ |
A7F6 | A805 | A771 | Allocate area for string |
A810 | A81F | A78B | Get the descriptor of a string into FAC#1 and set up string in memory |
A85D | A86C | A7D8 | Save string descriptor to descriptor stack |
A89C | A8AB | A817 | Store string in high RAM in string Bank |
A8D7 | A8E6 | A852 | De-allocate temporary string if possible from the given descriptor |
A921 | A930 | A89C | Set up descriptor values from string pointed to by $22/3 |
A940 | A94F | A8BB | If descriptor pointer is at the top of the descriptor stack then remove it. |
A964 | A973 | A8DF | Assign string to a variable (with check for Bank 15 in which case we are trying to assign TI$) |
A96D | A97C | A8E8 | Assign normal string to a variable (coding is simpler in 256K version) |
A9AE | A9BD | A91F | Copy a string (from the program into the string Bank) |
A9ED | A9FC | A95E | Set the pointer at the end of the actual string back to the descriptor area |
AA03 | AA12 | A974 | Check if there is an old value of the string and mark it as garbage if so |
AA24 | AA33 | A998 | Return the descriptor values of a string (if DS$ or string has a length of zero then do nothing) |
AA5D | AA6C | A9CE | Set up the index for a descriptor (get pointer and bank no. into $22-4) |
AA6B | AA7A | A9DC | Concatenate two strings |
AAB9 | AAC8 | AA2A | De-allocate temp string |
AAC2 | AAD1 | AA33 | CHR$ |
AADC | AAEB | AA4D | LEFT$ |
AB09 | AB18 | AA7A | Add .A to text pointer |
AB13 | AB22 | AA84 | RIGHT$ |
AB33 | AB42 | AAA4 | MID$ |
AB7F | AB8E | AAF0 | LEN |
AB85 | AB94 | AAF6 | Get 8-bit value for LEN |
AB8E | AB9D | AAFF | ASC. This routine has an annoying feature in that it returns an ILLEGAL QTY error instead of 0 for a null string. This was fixed on the later C128 OS as Commodore Guru Jim Butterfield complained several times about it! The fix is easy for those with EPROM programmers - change the branch in the second instruction of the routine from F0 09 to F0 06 (a BEQ to the previous JMP) |
AB9F | ABAE | AB10 | VAL |
ABE4 | ABF3 | AB55 | Restore TXTPTR (values saved in $82-4) |
ABF1 | AC00 | AB62 | ERR$ |
AC4D | AC5C | ABBE | Put 6526 clock value into TI$ |
ACC7 | ACD6 | AC38 | Put TI$ into 6526 clock registers (500 code differs) |
AD20 | AD3D | AC9F | Packing subroutine for TI$ to 6526 regs. |
GARBAGE COLLECTION ROUTINES | |||
500 | 128K | 256K | Description |
AD36 | AD53 | ACB5 | Allocate .A bytes for a string (and may force a Garbage collection if space is low) |
AD8E | ADA5 | AD07 | Do Garbage collection or OUT OF MEMORY error depending on space available |
AD9B | ADB5 | AD17 | Do Garbage collection (again the 500 code differs significantly from that of the later 128K/256K 6/700 - there is a complete piece of code added in the 6/700 which includes setting the correct bank and suggests that the 500 could get into difficulties when it runs out of string space) |
AE08 | AE43 | ADA5 | Skip over a string |
AE1B | AE56 | ADB8 | Check for top of strings else set up pointers for a string movement (i.e. move valid strings over old defunct strings in order to clear out old strings) |
---- | AE85 | ADE7 | Mark temporary strings as garbage |
---- | AEAF | AE11 | Set pointer to string back pointer (the back pointer is located at the end of each string in high RAM which points back to the variable name in low RAM) |
AE4A | ---- | ---- | The 500 combines the two previous routines into one with completely different coding |
AE9C | AEC8 | AE2A | Add .A to garbage pointer at $5B |
AEAB | AED7 | AE39 | Add .A to garbage pointer at $6D |
INSTR & DELETE | |||
500 | 128K | 256K | Description |
AEBD | AEE9 | AE4B | INSTR |
AF71 | AF9D | AEFF | DELETE (There is a small bug at the end of DELETE which returns the system to the wrong point afterwards without giving the READY message - it doesn't affect the DELETE operation itself) |
AFC8 | AFF4 | AF56 | Get parameters for LIST/DELETE |
PRINT USING + ASSOCIATED ROUTINES | |||
500 | 128K | 256K | Description |
AFFA | B026 | AF88 | USING |
B082 | B0AE | B010 | Check for comma and semicolon (exit USING routines if semicolon) |
B0BB | B0E7 | B049 | Output a number to format |
B0F3 | B11F | B081 | Handle 'E' exponent |
B155 | B181 | B0E3 | If no exponent then adjust decimal point. Also check if room for output and if not then print asterisks instead |
B1AD | B1D9 | B13B | Add extra 0 before decimal point if less than 1 |
B1BD | B1E9 | B14B | Shift decimal point and adjust exponent |
B1E2 | B20E | B170 | Add leading zeroes if necessary |
B202 | B22E | B190 | Adjust exponent subroutine |
B20E | B23A | B19C | Check for overflow |
B229 | B255 | B1B7 | Check for underflow |
B240 | B26C | B1CE | Reverse the sign of the exponent |
B253 | B27F | B1E1 | Get a digit from the exponent and set carry flag if overflow (checks for a '9') |
B279 | B2A5 | B207 | Initialise the counters and flags |
B294 | B2C0 | B222 | Round a number (checks digit to be chopped off for whether it is '5'. If lower then rounds down) |
B2C4 | B2F0 | B252 | Add 1 for rounding |
B2D6 | B302 | B264 | Delete leading zeroes |
B2F7 | B323 | B285 | Check for end of number reached |
B30C | B338 | B29A | Check for dollar and comma flags and make room if dollar flag set, add a comma if comma flag set. |
B333 | B35F | B2C1 | Check if decimal point required |
B33D | B369 | B2CB | Print leading zeroes and dollar (or whatever has been set by PUDEF) |
B352 | B37E | B2E0 | Check for USING symbols +, - and ^, and output sign if needed |
B38C | B3B8 | B31A | Print '-' if negative else print blank (or '*' if number will not fit) |
B397 | B3C3 | B325 | Print blanks (or '*') plus a sign if needed |
B3B7 | B3E3 | B345 | Output a character and decrement the count of available character spaces left |
B3BE | B3EA | B34C | Get next format character and print next printable character |
B41C | B448 | B3AA | If dollar found in format then set dollar flag |
B42F | B45B | B3BD | If 4 up arrows (^) found then set exponent flag |
B449 | B475 | B3D7 | If '+' found then set sign flag |
B466 | B492 | B3F4 | If '-' found then set sign flag |
B472 | B49E | B400 | Compare .A with USINGs special characters (+, -, ., =, > and #) |
GENERAL BASIC ROUTINES | |||
500 | 128K | 256K | Description |
B48C | B4B8 | B41A | Reset TXTPTR to start of BASIC and set Bank to 1 (0 in 500) |
B49E | B4CA | B42C | Get a positive integer |
B4A7 | B4D3 | B435 | Get integer from BASIC into .X |
B4B9 | B4E5 | B447 | Get 16-bit value from BASIC into .A/Y and $1B/C |
B4D2 | B4FE | B460 | ILLEGAL QTY Error (USR vector is set up by transferring this JMP into location 2, bank 15) |
B4D5 | B501 | B463 | Get and evaluate expression from BASIC |
B4E4 | B510 | B472 | TYPE MISMATCH error |
B4E9 | B515 | B477 | Print string ($22/3 points to it - Bank in $24) |
B4FF | B52B | B48D | Set to Bank 1 (500 = Bank 0) |
B502 | B52E | B490 | Print CRSR Right or SPACE if keyboard is input file |
B506 | B532 | B494 | Print a SPACE |
B509 | B535 | B497 | Print cursor right |
B50C | B538 | B49A | Print a '?' |
GENERAL DISK ROUTINES | |||
500 | 128K | 256K | Description |
B514 | B540 | B4A2 | DOS table containing 4 bytes set to $FF and then the default disk channel, device and secondary address ($0E $08 and $6F - 500 has first two bytes set to 02 and 00) |
B51B | B547 | B4A9 | Set up DOS area |
B546 | B572 | B4D4 | Check disk syntax bytes |
B554 | B580 | B4E2 | Get disk primary parameters (#, W, L or R) |
B56A | B596 | B4F8 | Process ON in disk command |
B570 | B59C | B4FE | Process U device parameter |
B575 | B5A1 | B503 | Process B Bank parameter |
B57A | B5A6 | B508 | Check for D, ON, B, U, P and I parameters |
B594 | B5C0 | B522 | Get file number after # |
B5AA | B5D6 | 5538 | DOPEN parameters L and W |
B5D6 | B602 | B564 | Check D drive parameter |
B5EF | B61B | B57D | Check for ID already got |
B5F6 | B622 | B584 | Process P address parameters |
B61E | B64A | B5AC | Get ID |
B635 | B661 | B5C3 | Process first file name or parameter in brackets |
B66E | B69A | B5FC | Process secondary parameters |
B6A5 | B6D1 | B633 | Get second D drive number |
B6BE | B6EA | B64C | Get U device (via $B6FF/B72B/B68D) |
B6C3 | B6EF | B651 | Process second file name or parameter in brackets |
B6E1 | B70D | B66F | More secondary parameters check |
B6F2 | B71E | B680 | Handle U or B after ON |
B6FF | B72B | B68D | Main routine to get U device number |
B710 | B73C | B69E | Main routine to get B Bank number |
B72B | B757 | B6B9 | Main routine to get file name with check for @ (Save-with-replace flag) |
B759 | B785 | B6E7 | STRING TOO LONG error |
B75E | B78A | B6EC | Get integer value into .X (possibly inside brackets) |
B771 | B79D | B6FF | Get address into .A/Y (possibly inside brackets) |
B789 | B7B5 | B717 | Check first disk syntax byte - if error then SYNTAX ERROR |
B78E | B7BA | B71C | Check second disk syntax byte - if error then SYNTAX ERROR |
B793 | B7BF | B721 | DISK command parameter checking table |
B7DF | B80B | B76D | Put parameters in DOS buffer |
B83E | B86A | B7CC | Set pointer to DOS buffer at $0226, Bank 15 |
B851 | B87D | B7DF | Put RECORD number in DOS buffer |
B856 | B882 | B7E4 | Check if @ (Save-with-replace) wanted |
B860 | B88C | B7EE | Put ID in DOS buffer |
B86C | B898 | B7FA | Default to SEQuEntial if L record parameter not present |
B875 | B8A1 | B803 | Set SEQuential and W write flags in buffer |
B87E | B8AA | B80C | Put address in buffer |
B888 | B8B4 | B816 | Put first filename in DOS buffer |
B89C | B8C8 | B82A | Put second filename in buffer |
B8C7 | B8F3 | B855 | Check parameters set up correctly for HEADER, DLOAD and SCRATCH |
B8CE | B8FA | B85C | Check for filename set up for DSAVE |
B8D9 | B905 | B867 | Check COLLECT parameters set up |
B8DE | B90A | B86E | Check parameters set up for COPY, CONCAT and |
B8E4 | B910 | B872 | ....RENAME |
B8ED | B919 | B87B | Check DOPEN, APPEND parameters |
B8F6 | B922 | B884 | Send command in buffer to disk and check returned disk error channel |
B92F | B95B | B8BD | ARE YOU SURE? checks for YES or just Y |
B968 | B994 | B8F6 | Clear DS and ST |
B970 | B99C | B8FE | Get filename pointer and Bank for LOAD, SAVE etc. |
B986 | B9B2 | B914 | Check parameters for LOAD, SAVE and VERIFY |
B9CD | B9F9 | B95B | Get filename |
CHRGET AND BANK ROUTINES | |||
500 | 128K | 256K | Description |
B9D5 | BA01 | B963 | Check for comma and then get next character |
B9E0 | BA0C | B96E | Check if variable is in BASIC (exits with carry set if variable is from Bank 15) |
B9F2 | BA1E | B980 | Convert floating point to integer (result in .A/Y) |
B9FA | BA26 | B988 | CHRGET routine entry - get next character from BASIC. This is via a RAM vector at $0290. |
B9FD | BA29 | B98B | CHRGOT routine entry - reget current character from BASIC - via RAM vector at $028E. |
BA00 | BA2C | B98E | Actual CHRGOT routine. |
BA06 | BA32 | B997 | Actual CHRGET routine. Unlike earlier machines, CHRGxT is all in ROM apart from the actual pointer into the BASIC program. The PET/Vic/64 transferred the entire routine from ROM into RAM (zero page). |
BA24 | BA50 | B9B2 | Routine used by CHRGET to set Z and C flags depending on character input. Z is set if character is either a colon ($3A) or end of line ($00). C is clear when the character is numeric (0-9) |
BA2E | BA5A | B9BC | Set text Bank (1 in 6/700, 0 in 500) |
BA38 | BA64 | B9C6 | ORA with byte in set bank (using pointer in $22/3) |
BA3D | BA69 | B9CB | Set to bank ($73) |
BA42 | BA6E | B9D0 | Set to bank ($60) |
BA47 | BA73 | B9D5 | Set to bank ($24) |
BA4C | BA78 | B9DA | Set to bank 15 |
BA51 | BA7D | B9DF | Set to string bank |
BA56 | BA82 | B9E4 | Set to array bank |
BA5B | BA87 | B9E9 | Set to variable bank |
BA60 | BA8C | B9EE | Set to text bank |
BA67 | BA93 | B9F5 | Set up buffer areas in various banks (for RND, Input, DS etc.) when BASIC is initialised |
BAF5 | BB21 | BA83 | Table of RNDs initial seed |
BAFB | BB27 | BA89 | BASIC Cold Start routine. Set up vectors, call buffer set up routine, print power up message and reset start up vector so that when reset button pressed it now points to warm start instead. |
BB55 | BB81 | BAEE | Power up message in ASCII |
BB7A | BBA6 | BB13 | Table of vectors for $0280 onwards |
BB90 | BBBC | BB29 | Set up vectors at $0280 |
BB9C | BBC8 | BB35 | LDA $FFFF/RTS routine. This is transferred to $025A on power up and used by various routines. The $FFFF address is changed to suit the routine |
BBA0 | BBCC | BB39 | BASIC Warm start. Resets I/O, clears screen and then jumps to READY. |
BBB1 | BBDD | BB4A | Set ST error with contents of .A |
BBB5 | BBE1 | BB4E | Do OPEN (via $FFC0) and check for error |
BBBC | BBE8 | BB55 | Do GETCHR (via $FFE4) and check for error |
BBC2 | BBEE | BB5B | Do I/P CHR (via $FFCF) and check for error |
BBC8 | BBF4 | BB61 | Do O/P CHR (via $FFD2) and check for error |
BBCE | BBFA | BB67 | Set input device (via $FFC6) and check for error |
BBD4 | BC00 | BB6D | Set output device (via $FFC9) and check for error |
BBDA | BC06 | BB73 | Do LOAD (via $FFD5) and check for error |
BBE0 | BC0C | BB79 | Do SAVE (via $FFD8) and check for error |
BBE6 | BC12 | BB7F | Do CLOSE (via $FFC3) |
BBEA | BC16 | BB83 | Do CLOSE ALL FILES (via $FFE7) |
BBEE | BC1A | BB87 | Error handling routine for above calls - closes the open file and then prints the error message indicated in .A |
---- | BC28 | BB95 | Checksum byte ($B5 in 128K, $CE in 256K) |
BBFC | BC29 | BB96 | Empty space (values of $FF) from here to the end of the BASIC ROM ($BFFF) in 128K/256K - to $BFFE in the 500 |
BFFF | ---- | ---- | 500 checksum byte (value $6B) |
RESET MONITOR ENTRY | |||
500 | 128K | 256K | Description |
E000 | E000 | E000 | Reset entry points here when BASIC ROM not installed (jumps into monitor instead) |
SCREEN EDITOR JUMP TABLE | |||
500 | 128K | 256K | Description |
E004 | E004 | E004 | Initialise screen and keyboard |
E007 | E007 | E007 | Get a character from the keyboard (or function key definition if f-key has been pressed) |
E00A | E00A | E00A | Input from screen |
E00D | E00D | E00D | Print a character to the screen |
E010 | E010 | E010 | Return screen size into .X (columns) and .Y (rows) |
E013 | E013 | E013 | IRQ entry to flash the cursor (500 only) and then scan the keyboard |
E016 | E016 | E016 | Set the cursor position in the video chip (6/700 only - 500 points to RTS) |
E019 | E019 | E019 | Read/Set screen x/y co-ordinates |
E01C | E01C | E01C | Set .X/Y to start of I/O area ($DC00) |
E01F | E01F | E01F | Do ESC function (on entry .A should hold 'A' to 'Z' in ASCII) |
E022 | E022 | E022 | Print/set function keys |
SCREEN EDITOR | |||
500 | 128K | 256K | Description |
E025 | E025 | E025 | Read/Set screen x/y co-ordinates (Carry clear upon entry to set co-ords) |
E03A | E03A | E03A | Set .X/Y to start of I/O area ($DC00) |
E03F | E03F | E03F | Set .X/Y to screen size (.X = columns, .Y = rows) |
E044 | E044 | E044 | Initialise the screen and keyboard |
E0C5 | E0B3 | E0B3 | Clear the screen and then... |
E0D3 | E0C1 | E0C1 | Home the cursor and then... |
E0DF | E0CD | E0CD | Set the screen line address |
---- | E0DA | E0DA | Set the cursor position in the VDC chip |
E0F4 | E0FE | E0FE | Get a character from either the keyboard buffer or a function key definition |
E0F8 | E102 | E102 | Get a character from a function key definition |
E10A | E114 | E114 | Get a character from the keyboard buffer |
E11F | E129 | E129 | Await screen entry. Echoes each character typed into the keyboard onto the screen until RETURN is pressed |
E174 | E179 | E179 | Input from screen main routine |
E1B9 | E1BE | E1BE | Check if character entered is PI and convert it from $DE to $FF |
E1C8 | E1CD | E1CD | Check for quotes character and swap quote flag if so (unless there are inserts outstanding - 6/700 only) |
E1D5 | E1DE | E1DE | Set bit 7 of character if RVS flag on |
E1E2 | E1EB | E1EB | Check for Auto-Insert flag on (ESC A) and if so then insert a space first and then... |
E1F0 | E1F9 | E1F9 | Output the character to the screen and then... |
---- | E1FC | E1FC | Check if on the 70th column of the screen and ring the bell if so (and the bell flag has not been turned off) and then... |
E1F6 | E206 | E206 | Exit from screen print routine |
E207 | E21A | E21A | Load .A with a space and then... |
E207 | E21C | E21C | POKE .A onto the screen at the current position - 500 also sets the corresponding colour memory byte |
E224 | E227 | E227 | Clear a screen line |
E23F | E242 | E242 | Read the character at the current position into .A - 500 also reads the colour at the current position |
E251 | E24D | E24D | Set text/graphic mode (enter with carry clear for text mode) |
---- | E260 | E260 | Set up the 6845 VDC chip. There are three possible set ups, a 700 with a built in monitor screen and 14 by 9 pixel character ROM, and either a 50Hz or 60Hz setting for the 6/700 using an external monitor. Bit 7 of $DF02 is set for an internal screen and bit 6 is set when the system is on 60Hz. Each set up has its own table of values to be sent to the VDC |
---- | E27D | E27D | Set to bank 15 for text screen |
E267 | E282 | E282 | Set to new bank saving the original bank setting and preserving .A |
E26E | ---- | ---- | Set to text screen bank (this is usually bank 15 but can be altered to use bank 0) |
E27C | E291 | E291 | Restore original bank |
E284 | E299 | E299 | Print a character to the screen (main routine) |
E2C5 | E2B4 | E2B4 | Check if last character was an ESC and jump to ESC routine if so |
E2D2 | E2C1 | E2C1 | Convert ASCII to screen value |
E2E0 | E2CF | E2CF | Check for control codes (RETURN, INSERT etc.) |
E317 | E306 | E306 | Jump to control code function (pushes address-1 onto the stack and then does a RTS to get to it) |
E322 | E311 | E311 | Vector for extra control code functions (via $0322) |
E325 | E314 | E314 | Handle cursor up/down |
E327 | E316 | E316 | Cursor down |
E334 | E323 | E323 | Cursor up |
E342 | E331 | E331 | Handle cursor left/right |
E344 | E333 | E333 | Cursor right |
E34A | E339 | E339 | Cursor left |
E355 | E344 | E344 | Swap the RVS flag (does EOR #$80 so there could be a possibility that it may accidently swap it the wrong way - the C128 sets or clears it as two separate options) |
E35B | E34A | E34A | Handle CLR/HOME |
E360 | E34F | E34F | Check for two HOME keys and, if so, then resets the screen window to full size |
E36B | E35A | E35A | Handle the TAB key |
E36F | E35E | E35E | Move to next TAB position or to end of screen line if no more positions set |
E381 | E370 | E370 | Set or clear a TAB at the current cursor position |
E38B | E37A | E37A | Check if a screen scroll is needed and scroll if so (unless scrolling has been turned off in which case move cursor to the top line in the current window) |
E3A5 | E394 | E394 | Handle RETURN and then... |
E772 | E3A2 | E3A2 | Cancel quotes, inserts and RVS flags (ESC O comes here) - the 500 has this routine out of sequence compared to the 6/700 |
E3B6 | E3B4 | E3B4 | Move a screen line |
E3DF | E3CD | E3CD | Routine used by reverse scrolling and insert a blank line (ESC I) to move part or all of the current window down a line |
E408 | E3F6 | E3F6 | Scroll the current window |
E43F | E42D | E42D | Screen scroll subroutine and then... |
E459 | E447 | E447 | Check if CTRL key held down and do a short delay (slows screen scroll) and then... |
E479 | E45F | E45F | Check if CBM key held down (halts screen scroll) |
E49A | E480 | E480 | Check if key pressed subroutine |
E675 | E48D | E48D | Ring the bell (CTRL-G) - 500 is out of sequence here |
E6A3 | E4BA | E4BA | Handle the CE key. Delete either one alpha character or all numeric (including +,-,E and .) characters until a non numeric character is found - 500 is out of sequence here |
E4A6 | E4F5 | E4F5 | Get a bit from the screen wrap table (if zero then carry is cleared) |
E4B2 | E501 | E501 | Set a bit in the screen wrap table according to carry flag |
E4CF | E51E | E51E | Get bit position subroutine |
E4E3 | E532 | E532 | Move to the start of the line (ESC J). If this is a wrapped line (i.e. the second screen line of a BASIC line that starts on the previous screen line) then move back until the start of a non-wrapped line |
E4F7 | E544 | E544 | Move to the last non-space character on the line (ESC K). Note that ESC K was changed slightly on the C128 in that the cursor is positioned one character past the last character on the line (the C16 & Plus/4 are the same as the 5/6/700) |
E521 | E574 | E574 | Cursor right subroutine - move to the next character (on the next line if at the end of the current screen line) |
E534 | E587 | E587 | Cursor left subroutine - move back to the previous character (on the previous line if at the start of a screen line) |
E552 | E5A5 | E5A5 | Save current screen row and column into temporary store |
E55B | E5AE | E5AE | Handle INST/DEL |
E55D | E5B0 | E5B0 | Delete a character |
E591 | E5E4 | E5E4 | Insert a space |
E5C9 | E61C | E61C | Handle CHR$(131) (Shift RUN/STOP). Put 'dL"* + run' into the keyboard buffer |
E5DB | E62E | E62E | Move to next character position. Insert a blank line if the end of the line has been reached and the next line isn't part of the current wrap |
E602 | ---- | ---- | Set the current text colour |
E612 | ---- | ---- | Store a value in the VIC chip. Some values are checked or ANDed with $0F |
E632 | ---- | ---- | Table of masks for values sent to Vic chip |
E641 | ---- | ---- | Subroutine to store a value onto the screen. It can handle the screen in either bank 0 or bank 15. This loops until it is sure that the value is stable on the screen and is one reason for the very slow screen update - the following routine has similar coding |
E650 | ---- | ---- | Subroutine to store a value in the colour memory in bank 15 |
E669 | ---- | ---- | Vector jump (via $03BB). This is used to intercept normal print characters on their way to the screen - normally points to a RTS so that no action is taken |
E66C | ---- | ---- | Vector jump (via $03BD). This used to intercept the screen/keyboard IRQ routine and normally points to a RTS |
E675 | ---- | ---- | Ring the bell (see E48D in the 128K sequence) |
E6A3 | ---- | ---- | Handle the CE key (see E4BA in the 128K sequence) |
E6DE | E655 | E655 | Vector for function keys (via $0320) |
E6E1 | E658 | E658 | Insert a blank line (ESC I points here) |
E6F6 | E66D | E66D | Delete a line (ESC D) |
E71F | ---- | ---- | Handle erase to start/end of line (common entry point 500 only) |
E727 | E694 | E694 | Erase characters up to the end of the current screen wrap (ESC Q) |
E739 | E6A9 | E6A9 | Erase characters from current cursor position back to the start of the current screen wrap (ESC P) |
E74A | ---- | ---- | Handle scroll up/down (common entry point - 500 only) |
E752 | E6BD | E6BD | Scroll up (ESC V) |
E75D | E6CB | E6CB | Scroll down (ESC W) |
E772 | ---- | ---- | ESC O turn off various flags (see E3A2 in the 128K sequence) |
E77F | E6E3 | E6E3 | Enable scrolling (ESC L) |
E782 | E6E5 | E6E5 | Disable scrolling (ESC M) |
E78A | ---- | ---- | Turn off Auto Insert mode (never called) |
E78D | ---- | ---- | Turn on Auto Insert mode (never called). These two routines are not used at all, the ones that are used are located at EAA8/EAAB |
E795 | E6ED | E6ED | Disable logical scrolling |
E798 | E6F0 | E6F0 | Enable logical scrolling. This and the above routine are never actually called via any CTRL or ESC key presses and the flag really has to be POKEd to change the setting. When bit 7 is set then a complete set of wrapped screen lines will disappear off the top of the screen when the first is scrolled off. When cleared then the wrapped bits are ignored and a set of wrapped lines will disappear one by one with a scroll needed for each one. The flag is temporarily set by the ESC D routine so that it always deletes a complete set of screen wrapped lines |
E7A0 | ---- | ---- | Routine called by CTRL-F. Purpose unknown at the time of writing |
E7A9 | E6F8 | E6F8 | Either print the current function key definitions (if .Y is either 0 or >126) else set up a new definition for function key .Y |
E7AF | E6FF | E6FF | Print function key definitions (there are several bugs in this routine - all of which were removed for the Plus/4 and C128 - where strange things happen if the first character is a quote plus the ESC character is never printed if it is part of the definition. The 500 version doesn't recognise the shifted return CHR$(141) either |
E83C | E781 | E781 | Subroutine to print either 'KEY' or '+CHR$(' and a number |
E856 | E7A6 | E7A6 | KEY and various CHR$ values for printing the function definitions (held as ASCII but all in reverse) |
E86C | E7BE | E7BE | Set up a new function key definition |
E90C | ---- | ---- | IRQ entry (500). Flash the cursor and then... |
E933 | E865 | E865 | IRQ entry (6/700). Set up the keyboard ready to be scanned and, if a key is pressed then... |
E949 | E87E | E87E | Set .Y to an index into the keyboard tables depending on the key pressed and then... |
E974 | E8A9 | E8A9 | Store the .Y index and, depending on the state of the CTRL and Shift keys (and whether the machine is in graphic or text mode AND the shift key is pressed) then get the final actual key value from one of four keyboard tables |
E995 | E8C9 | E8C9 | Check for a function key (any value >=$E0) and set up a pointer to its definition |
E9B1 | E8E5 | E8E5 | Check for the '00' key and store '0' twice in the keyboard buffer |
E9CE | E902 | E902 | Handle key repeats |
E9EA | E91E | E91E | Subroutine to get a debounced key value |
E9F3 | E927 | E927 | Function key IRQ routine vector (via $03B5) to set the pointer to the specified function key definition and set its length in $D6 |
EA15 | E949 | E949 | Set .A/X to the start of the specified function key definition |
EA26 | E95A | E95A | Get a TAB bit position subroutine |
EA3C | E970 | E970 | Do an ESC function (.A must be set to 'A' to 'Z' else the routine exits) |
EA51 | E985 | E985 | Table of ESC addresses (-1) |
EA85 | E9B9 | E9B9 | Do ESC T - set window top |
EA87 | E9BB | E9BB | Do ESC B - set window bottom |
EA93 | E9C7 | E9C7 | Set the window to full screen size (used by 2 x HOME as well as initialisation) |
EAA2 | E9D6 | E9D6 | Bell on (ESC G) |
EAA4 | E9D8 | E9D8 | Bell off (ESC H) provided .A holds a non-zero value upon entry |
---- | E9DC | E9DC | Set underline cursor mode (ESC U) |
---- | E9E6 | E9E6 | Set flashing cursor mode (ESC F) |
---- | E9EC | E9EC | Set solid block cursor mode (ESC S) |
---- | E9EF | E9EF | Set non-flashing cursor mode (ESC E) |
---- | E9F6 | E9F6 | Reverse screen on (ESC R) |
---- | E9F9 | E9F9 | Set to alternative character set (ESC Z) |
---- | EA05 | EA05 | Set to normal (un-reversed) screen (ESC N) |
---- | EA08 | EA08 | Set to normal character set (ESC Y) |
EAA8 | EA20 | EA20 | Auto insert mode off (ESC C) |
EAAB | EA23 | EA23 | Auto insert mode on (ESC A) |
EAB1 | EA29 | EA29 | Normal keyboard table (no Shift or CTRL keys pressed) |
EB11 | EA89 | EA89 | Shifted keyboard table (text mode only) |
EB71 | EAE9 | EAE9 | Shifted keyboard table (graphic mode only) |
EBD1 | EB49 | EB49 | CTRL keyboard table |
EC31 | EBA9 | EBA9 | 'dL"* + run' in ASCII |
EC3A | EBB2 | EBB2 | Screen line address table (lo) |
EC53 | EBCB | EBCB | Screen line address table (hi) |
EC6C | EBE4 | EBE4 | Addresses (-1) of CTRL and cursor functions |
ECAC | EC24 | EC24 | Function key lengths for... |
ECB6 | EC2E | EC2E | Initial function key definitions |
ECEF | EC67 | EC67 | Bit table |
---- | EC6F | EC6F | VDC table for 700 with built in monitor |
---- | EC81 | EC81 | VDC table for 60Hz system |
---- | EC93 | EC93 | VDC table for 50Hz system |
ECF7 | ---- | ---- | Table of VIC chip initial values |
ED08 | ---- | ---- | Table of vectors for $03B5 to $03BE |
ED12 | ---- | ---- | Table of ASCII colour keyboard codes |
ED22 | ECA5 | ECA5 | Screen editor checksum byte |
ED23 | ECA6 | ECA6 | Unused ROM area |
---- | ED00 | ED00 | Patch to pull return address if the window bottom and top lines are the same |
MONITOR | |||
500 | 128K | 256K | Description |
EE00 | EE00 | EE00 | Monitor startup entry point (resets all I/O) |
EE09 | EE09 | EE09 | Monitor entry point when BASIC not installed |
EE21 | EE21 | EE21 | Break monitor entry point |
EE29 | EE29 | EE29 | Pull registers from stack and store in zero page. Also save a copy of IRQ vector, bank number and stack pointer for register display |
EE4C | EE4C | EE4C | Load .A with 'R' in order to register display command |
EE50 | EE50 | EE50 | Print ? for monitor errors and then... |
EE55 | EE55 | EE55 | Normal return point after each command and then... |
EE69 | EE69 | EE69 | Await next command. The 500 only checks for a space to see if a command has been entered as it doesn't print a '.' on each line |
EE70 | EE74 | EE74 | Do entered command (via RAM vector at $031E) |
EE7F | EE83 | EE83 | Check command against table and, when found, jump to it |
EE94 | EE98 | EE98 | Loop for next command in table. If not found then store command in buffer and assume its a filename and try loading it from the specified device (default 8) |
EED1 | EED5 | EED5 | Table of monitor commands and addresses. Each single byte command is followed by the appropriate two byte address |
EEF5 | EEF9 | EEF9 | Do the X command and jump back to (normally) BASIC via RAM vector at $03F8 |
EEFB | EEFF | EEFF | Save address bytes in reversed format in PC address area |
EF04 | EF08 | EF08 | Set up to print registers from $B0 onwards |
EF13 | EF17 | EF17 | Print CR and '.', then character in .A finally a space (500 misses the '.') |
---- | EF27 | EF27 | Subroutine to print CR and '.' |
EF26 | EF31 | EF31 | Headings for register display |
EF41 | EF4C | EF4C | R command - print registers |
EF67 | EF72 | EF72 | Common routine to print .Y bytes starting at ($B9) used by the R and M commands |
EF84 | EF8F | EF8F | M command to display a memory dump |
EFC5 | EFCB | EFCB | ; command to read new register values. The 500 has an extra error check at the start of this and the next few routines which accounts for the slightly longer length of each - the 6/700 handle these checks at $F03A/F040 |
EFDF | EFE1 | EFE1 | V command to View a different bank |
EFEB | EFEB | EFEB | U command alters the default device number |
EFF7 | EFF5 | EFF5 | : command to read new values for memory dump |
EFFE | EFFA | EFFA | Common routine reads .A bytes for M and R commands |
F014 | F010 | F010 | G command jumps to machine code routine (bank 15 only) |
---- | F03A | F03A | Get a two character hex byte into .A with an error check to see if it is valid |
---- | F040 | F040 | Get a four character hex address into $B9/A |
F043 | F04A | F04A | Do L and S commands. Sets up default I/O (device set to tape!), gets filename, device number, optional load address/start save address and end address. Again the 500 version is slightly longer as it does its own error checking on the addresses instead of using $F03A/F040 |
F0F9 | F0F6 | F0F6 | Print .X/Y as hex address |
F116 | F113 | F113 | Swap $B9/A and $BB/C. Used when two addresses entered for M command to store one safely while the other is entered |
F126 | F123 | F123 | Get a hex address into $B9/A |
F133 | F130 | F130 | Get two hex characters into .A |
F157 | F154 | F154 | Convert ASCII hex character to $0-$F |
F162 | F15F | F15F | Get a character and check if its a CR |
F168 | F165 | F165 | Do @ command to send a disk command to the current device (set by the U command) |
F18B | F188 | F188 | Send disk command |
F19D | F19A | F19A | Return disk status |
KERNAL MESSAGES | |||
500 | 128K | 256K | Description |
F1CA | F1C3 | F1C3 | Table of (error) messages |
F223 | F21C | F21C | Print message from above table - .Y must be pointing to the first character of the wanted message |
IEEE HANDLING | |||
500 | 128K | 256K | Description |
F237 | F230 | F230 | Send IEEE Talk |
F23B | F234 | F234 | Send IEEE Listen |
F23E | F236 | F236 | Send byte in .A to IEEE |
F27B | F274 | F274 | Send secondary address after Listen |
F287 | F280 | F280 | Send secondary address after Talk |
F29E | F297 | F297 | Send deferred byte to IEEE |
F2B2 | F2AB | F2AB | Send IEEE Untalk (from $FFAB Kernal call) |
F2B6 | F2AF | F2AF | Send IEEE Unlisten |
F2C0 | F2B9 | F2B9 | Subroutine to send byte on IEEE and check for device not present (timeout check) |
F311 | F30A | F30A | Input a byte on IEEE with timeout checks |
F376 | F36F | F36F | Set timer for 65mS (values differ between 1MHz 500 and the 2MHz 6/700) |
RS232 HANDLING | |||
500 | 128K | 256K | Description |
F388 | F381 | F381 | Open an RS232 channel. Sets 6551 from the first two control characters (the 3rd and 4th, if they exist, are ignored). Also sets up RS232 input buffer if this is the first time it has been accessed |
F3CE | F3C7 | F3C7 | Converts proper ASCII to Commodore ASCII (sometimes called PETSCII as the first implementation of Commodore ASCII was on the PET) |
F3E3 | F3DC | F3DC | PETSCII to ASCII |
F3F8 | F3F1 | F3F1 | Turn on transmitter (but no interrupts) |
F403 | F3FC | F3FC | Set up registers for creating the RS232 input buffer and then... |
F407 | F400 | F400 | Allocate a buffer. The size of the allocation is held in the .X/Y registers (.Y is the high byte). This routine has not been completely implemented as .A should indicate the type of set wanted (in high memory, low memory etc) but it is ignored and discarded |
F435 | F42E | F42E | Reset the RS232 DCD and DSR status |
GENERAL I/O | |||
500 | 128K | 256K | Description |
F444 | F43D | F43D | Get a byte (from $FFE4 Kernal call). If not keyboard or RS232 then does Input Byte (via $FFCF) |
F45B | F454 | F454 | Get a byte from RS232 |
F4A3 | F49C | F49C | Input a byte (from $FFCF Kernal call) |
F4D7 | F4D0 | F4D0 | Input a byte from RS232 |
F4F5 | F4EE | F4EE | Output a byte (from $FFD2 Kernal call) |
F518 | F511 | F511 | Output a byte to RS232 |
F550 | F549 | F549 | Set the current Input device (from $FFC6 Kernal call) |
F569 | F562 | F562 | Set RS232 as the Input device |
F591 | F58A | F58A | Set the IEEE Input device (send Talk and secondary address, and then check ST) |
F5AA | F5A3 | F5A3 | Set the current Output device (from $FFC9 Kernal call) |
F5C6 | F5BF | F5BF | Set RS232 as the Output device |
F5DC | F5D5 | F5D5 | Set the IEEE Input device (send Listen and secondary address, and then check ST) |
F5F4 | F5ED | F5ED | Close a file (from $FFC3 Kernal call). Check that it is actually open first |
F621 | F61A | F61A | Send Close on IEEE and then... |
F624 | F61D | F61D | Remove file entry from tables |
F645 | F63E | F63E | Check for file open |
F657 | F650 | F650 | Get file parameters from file tables and set up as current file (.X must be set up as the index into the file tables upon entry) |
F667 | F660 | F660 | Find the file parameters (put into .A/X/Y). .Y must be set to the required secondary address upon entry |
F67F | F678 | F678 | Check if file (in .A) is open and, if it is, then set up file parameters |
F686 | F67F | F67F | Close all files. This routine was improved over the PET which used to abort the files - e.g. would leave the disk unit thinking a file was still open while the PET considered it closed) |
F6C6 | F6BF | F6BF | Open a file (from $FFC0 Kernal call). If carry set then jump to Transmit (see below) else checks to see if file is already open and gives an error if so, otherwise... |
F6D5 | F6CE | F6CE | Check if 10 files already open and, if less, then... |
F6DF | F6D8 | F6D8 | Store new file parameters in the file table (adds file number, device number and secondary address) |
F70E | F707 | F707 | Do IEEE Open (send Listen plus secondary address and then checks ST for any errors) |
F72B | F724 | F724 | Send the filename to the IEEE (if there is one) |
F741 | F73A | F73A | Transmit command (Open jumps here if carry is set). This routine only appears on the 5/6/700, neither the earlier or later machines have it. All it does is send a listen and a secondary address. It assumes that all relevant file parameters have already been set up. |
F74D | F746 | F746 | LOAD entry from $FFD5 Kernal call (this also handles verify) |
F764 | F75D | F75D | Trap LOADs from tape and RS232 (give DEVICE NOT PRESENT) and screen/keyboard give ILLEGAL DEVICE NUMBER |
F76D | F766 | F766 | Do IEEE load. First check file name is present (if not then give an error) |
F7C1 | F7BA | F7BA | Main loop to input characters for IEEE load/verify. There is a check to make sure that locations 0 and 1 of any bank are NOT loaded with anything so that loading goes from $FFFF on one bank to $0002 on the next - SAVE is handled in a similar fashion. Depending on the load/verify flag each byte is either stored or compared. There appears to be a strange instruction that reads LDA $9691 (or AD 91 96) which is really the store instruction when entered at the second byte in (91 96 = STA ($96),Y) |
F81A | F813 | F813 | Exit from load with the .A holding the bank and .X/Y holding the final address of the load so that, if required, the end address may be set (for BASIC) |
F822 | F81B | F81B | Print 'SEARCHING' and optionally 'FOR' and the filename |
F847 | F840 | F840 | Print either 'LOADING' or 'VERIFYING' depending on the Load/Verify flag |
F853 | F84C | F84C | SAVE entry (from $FFD8 Kernal call). This must be entered with .X as an index to the first of three zero page bytes holding the address and bank of the start address and .Y as a similar index to the end address |
F87A | F873 | F873 | Do IEEE save (checks for filename, writes start address and loops to send each character) |
F8E0 | F8D9 | F8D9 | Print 'SAVING' plus filename |
F8ED | F8E6 | F8E6 | Routine to read the TOD (Time Of Day) clock from the 6526 into the .A/X/Y registers |
F915 | F90E | F90E | Set the TOD clock from the .A/X/Y registers |
F940 | F939 | F939 | Do I/O ERROR #1 or TOO MANY FILES |
F943 | F93C | F93C | Do I/O ERROR #2 or FILE OPEN |
F946 | F93F | F93F | Do I/O ERROR #3 or FILE NOT OPEN |
F949 | F942 | F942 | Do I/O ERROR #4 or FILE NOT FOUND |
F94C | F945 | F945 | Do I/O ERROR #5 or DEVICE NOT PRESENT |
F94F | F948 | F948 | Do I/O ERROR #6 or NOT INPUT FILE |
F952 | F94B | F94B | Do I/O ERROR #7 or NOT OUTPUT FILE |
F955 | F94E | F94E | Do I/O ERROR #8 or MISSING FILE NAME |
F958 | F951 | F951 | Do I/O ERROR #9 or BAD DEVICE NUMBER |
F95A | F953 | F953 | Save error number, restore default I/O, check error message type and print 'I/O ERROR #n' if in Monitor |
F972 | F96B | F96B | Check for STOP key pressed (from $FFE1 Kernal call) |
F980 | F979 | F979 | IRQ code for setting STOP key pressed flag |
RESET CODE | |||
500 | 128K | 256K | Description |
F99C | F995 | F995 | 'BM' in ASCII. This is used to check against either BASIC or a cartridge at $x009 (where x is any valid cartridge startup point in bank 15 - i.e. 1 to 8). If found then a jump is made to $x000 |
F99E | F997 | F997 | Reset entry (from reset vector at $FFFC/D). First check for cartridges or BASIC present |
F9D8 | F9D5 | F9D5 | Set reset RAM vector to use $E000 as startup point (monitor) as no BASIC or cartridges were found |
F9DB | F9D8 | F9D8 | Set reset RAM vector use $x000 as startup point |
F9E3 | F9E0 | F9E0 | Set up system (unless cartridge found) |
F9FB | F9F8 | F9F8 | Jump to BASIC/Cartridge/Monitor via vector ($03F8) |
F9FE | F9FB | F9FB | Set up I/O chips. Checks 50/60 Hz and sets TOD clock accordingly. Sets up Co-processor workspace whether its there or not |
FA94 | FA88 | FA88 | Clear zero page, page 2 and 3 in Bank 15. Then check the RAM bank memory from bank 1 (bank 0 on 500). Each byte is non-destructively tested by saving the value, writing $55 and then checking $55 is read back, doing the same with $AA and finally re-writing the original value back. This is mainly what the system is doing after power up and before the power up message is displayed |
FAE3 | FAD7 | FAD7 | Once a bank has been discovered to contain no RAM (or Bank 15 has been reached) then this routine sets the top bank and the top of memory (always set to $FDFF so that $FE00-FFFF remain free for bank switching routines if they need to be installed) |
FB09 | FAFD | FAFD | Table of vectors for $0300 onwards |
FB3D | FB31 | FB31 | NMI vector jump via RAM vector at $0304. This normally points to the RTI (ReTurn from Interrupt) instruction at the end of the IRQ routine |
MISC. KERNAL ROUTINES | |||
500 | 128K | 256K | Description |
FB40 | FB34 | FB34 | Set the filename parameters (from $FFBD Kernal call) |
FB4F | FB43 | FB43 | Set the file parameters (from $FFBA Kernal call) |
FB56 | FB4A | FB4A | Read or Set ST error status (from $FFB7 Kernal call). Carry must be set to store else read is performed. RS232 errors are also stored by this routine |
FB6E | FB5F | FB5F | ORA bits in .A with ST and store in ST |
FB83 | FB74 | FB74 | Set IEEE timeout byte (from $FFA2 Kernal call) |
FB87 | FB78 | FB78 | Read/set top of memory including bank (from $FF99 Kernal call). Carry must be clear to perform read |
FB9C | FB8D | FB8D | Read/set bottom of memory (from $FF9C Kernal call) |
FBB1 | FBA2 | FBA2 | From $FF87 Kernal call. Point .X/Y to table of vectors for $0300 (.A holds bank number), clear carry and then... |
FBB8 | FBA9 | FBA9 | Read/set up vectors at $0300-0333 from .A/X/Y (from $FF84 Kernal call). Carry must be set to read from $0300 |
FBD9 | FBCA | FBCA | Set reset vector from .X/Y and set the 'Initialisation complete' flag |
IRQ HANDLING | |||
500 | 128K | 256K | Description |
FBE5 | FBD6 | FBD6 | IRQ routine. Push registers onto the stack and check for normal interrupt or BRK and jump (via vectors at $0300 and $0302) to either normal IRQ handling or the monitor |
FBF8 | FBE9 | FBE9 | Normal IRQ handling entry from $0300 vector. Save indirection bank (location $01) and then check for what has initiated the IRQ |
FC0B | FBFC | FBFC | Handle RS232 IRQs and add byte to input buffer if byte has been received |
FC69 | FC5B | FC5B | Check for internal disk IRQ |
FC77 | FC69 | FC69 | Check for timer IRQ and store a copy of the 6526 IRQs in case they are needed later |
FC88 | FC7A | FC7A | Check for IEEE SRQ line IRQs (but don't do anything about them!) |
FC8F | FC81 | FC81 | If we've got this far then it must be a normal 50/60 Hz interrupt so scan the keyboard and then check if the STOP key has been pressed. Finally check the cassette keys and turn the cassette motor on or off as required (this is the only thing that these versions of the operating systems have to do with actually handling the cassette!) |
FCAD | FC9F | FC9F | Return from IRQ routine (NMI vector points at the RTI instruction at the end of this routine) |
SECOND PROCESSOR CODE | |||
500 | 128K | 256K | Description |
FCB9 | FCAB | FCAB | Send a request to the IPC (Inter Process Communicator) for the second processor (2P) |
FD56 | FD48 | FD48 | Service a 2P request |
FDA7 | FD99 | FD99 | Send bytes back to 2P |
FDD1 | FDC3 | FDC3 | Push return address and get back bus control if 2P finished with it and then jump (via vector at $0801) to next process |
FDDD | FDCF | FDCF | Give up bus and then send request to 2P |
FDF4 | FDE6 | FDE6 | Wait until 2P flag is low (flag is in I/O at $DB01 bit 2) |
FDFC | FDEE | FDEE | Wait until 2P flag is high |
FE04 | FDF6 | FDF6 | 6509 acknowledge to 2P by putting 6509 flag high ($DB01 bit 3) |
FE0D | FDFF | FDFF | Put 6509 flag low |
FE16 | FE08 | FE08 | Free bus so 2P can have it |
FE1F | FE11 | FE11 | Await bus free and then claim it for 6509 |
FE2F | FE21 | FE21 | Get number of i/o bytes from table at $0910 (indexed by .Y) |
FE41 | FE33 | FE33 | Relinquish control to 2P. Loop while awaiting requests from 2P |
VARIOUS BANK HANDLING AND MISC. | |||
500 | 128K | 256K | Description |
FE68 | FE5A | FE5A | All tape routines come here which is a jump to a RAM vector ($036A) which normally points to the next small piece of code. To implement tape cassette routines the user would have to pull the address off the stack to determine which routine was being used and then handle the tape with new code in RAM |
FE6B | FE5D | FE5D | Pull return address and throw it away and then do DEVICE NOT PRESENT for all tape routines |
FE70 | FE62 | FE62 | Put SAVE start address in temp and set the start address bank in the 6509 bank indirection register ($01) |
FE7F | FE71 | FE7F | Check if end address reached for SAVE |
FE8D | FE7F | FE7F | Increment SAVE address and, if it was $FFFF, then move to next bank jumping over locations $00 and $01 |
FEA0 | FE92 | FE92 | Get byte pointed at by ($90) + .Y, bank in $92. This is used to get the filename from any bank |
FEAB | FE9D | FE9D | Move to any bank. This routine allows a jump to any bank while preserving all registers (which are all passed via each banks stack). The 500 has part of this routine missing which accounts for its inability to use the SYS command to jump to another bank |
FEFD | FF04 | FF04 | Return to calling bank |
FF11 | FF19 | FF19 | Initialise pointer to $0100 for bank move and get stack pointer stored at $01FF |
FF1C | FF24 | FF24 | Store .A/X in another stack ready for move |
FF26 | FF2E | FF2E | Restore registers after move to next bank |
FF2D | FF35 | FF35 | Push the processor status and do an NMI (via $FFFA) |
FF31 | FF39 | FF39 | Do BRK, NOP and RTS |
FF34 | FF3C | FF3C | Do CLI and RTS |
FF36 | FF3E | FF3E | Unused area |
KERNAL TABLE | |||
500 | 128K | 256K | Description |
---- | FF6C | FF6C | SYS to any bank |
FF6F | FF6F | FF6F | Set power on reset vector |
FF72 | FF72 | FF72 | Jump to second processor (also monitors Z command) |
FF75 | FF75 | FF75 | Set/Print Function keys |
FF78 | FF78 | FF78 | Send second processor request |
FF7B | FF7B | FF7B | Set up I/O chips |
FF7E | FF7E | FF7E | Screen/keyboard initialisation |
FF81 | FF81 | FF81 | Set up buffer in high memory |
FF84 | FF84 | FF84 | Read/Set I/O vectors at $0300 |
FF87 | FF87 | FF87 | Restore I/O vectors to standard settings |
FF8A | FF8A | FF8A | Set up device and file number from given secondary address in .A |
FF8D | FF8D | FF8D | Set up device an sec address given file number |
FF90 | FF90 | FF90 | Control operating system messages mode |
FF93 | FF93 | FF93 | Send secondary address after listen |
FF96 | FF96 | FF96 | Send secondary address after talk |
FF99 | FF99 | FF99 | Read/Set top of memory |
FF9C | FF9C | FF9C | Read/Set bottom of memory |
FF9F | FF9F | FF9F | Scan keyboard |
FFA2 | FFA2 | FFA2 | Set IEEE timeout byte with .A |
FFA5 | FFA5 | FFA5 | Input byte on IEEE |
FFA8 | FFA8 | FFA8 | Output byte on IEEE |
FFAB | FFAB | FFAB | Send Untalk on IEEE |
FFAE | FFAE | FFAE | Send Unlisten on IEEE |
FFB1 | FFB1 | FFB1 | Send Listen on IEEE |
FFB4 | FFB4 | FFB4 | Send Untalk on IEEE |
FFB7 | FFB7 | FFB7 | Read/Set ST error |
FFBA | FFBA | FFBA | Set file parameters |
FFBD | FFBD | FFBD | Set filename parameters |
FFC0 | FFC0 | FFC0 | Open a logical file |
FFC3 | FFC3 | FFC3 | Close a logical file |
FFC6 | FFC6 | FFC6 | Set the Input device |
FFC9 | FFC9 | FFC9 | Set the Output device |
FFCC | FFCC | FFCC | Restore default I/O channels |
FFCF | FFCF | FFCF | Input a byte from current input channel |
FFD2 | FFD2 | FFD2 | Output a byte to the current output channel |
FFD5 | FFD5 | FFD5 | Load from device |
FFD8 | FFD8 | FFD8 | Save to device |
FFDB | FFDB | FFDB | Set the clock |
FFDE | FFDE | FFDE | Read the clock |
FFE1 | FFE1 | FFE1 | Check for STOP key pressed |
FFE4 | FFE4 | FFE4 | Get a character |
FFE7 | FFE7 | FFE7 | Close all files |
FFEA | FFEA | FFEA | IRQ routine to check for STOP key pressed (in other machines this routine also updates the software clock which is handled by hardware in these machines) |
FFF0 | FFF0 | FFF0 | Read/Set screen X/Y co-ordinates |
FFF3 | FFF3 | FFF3 | Set .X/Y to start of I/O |
FFF6 | FFF6 | FFF6 | Set (.A) as the current bank |
FFF9 | FFF9 | FFF9 | Kernal checksum byte |
FFFA | FFFA | FFFA | NMI hardware vector |
FFFC | FFFC | FFFC | Reset hardware vector |
FFFE | FFFE | FFFE | IRQ hardware vector |