THE 128 MLM: BANK ON IT
In its favor, the Commodore 128 comes with a built-in machine language monitor (MLM) with many attractive features. If a program crashes, just hold down the Run key and press the reset button. The computer will recover into the MLM so you can investigate the cause of the problem. The BASIC SYS command allows values to be preset for the A, X, Y, and status registers. BLOAD and BSAVE are big BASIC improvements.
On the negative side, 128 BASIC can relocate. Also, special code and new system calls are needed to reach data or a subroutine across banks. The interrupt has so many jobs—such as graphics, animation, and sound—that it's easy for new code to conflict with built-in operations.
The bank system makes it hard to put code higher than location $3FFF. Beginners are advised to place ML programs below $4000 and stay in bank 15. That way, you can SYS to the ML program from BASIC and use a JSR to call subroutines in the Kernal.
What happens if you try to put code at higher addresses? Suppose you wish to locate a program at $6000. The trouble is that, if BASIC stays in its normal bank 15 state, a call to $6000 (SYS 24576) wouldn't take your program to RAM but to the overlaying ROM containing the BASIC interpreter. Bank 15 configures RAM from $0000 to $3FFF, ROM from $4000 to $CFFF, I/O chips from $D000 to $DFFF, and ROM from $E000 to $FFFF. The program at $6000 wouldn't be visible.
The obvious solution—enter the command BANK 0 before the SYS call—usually ends in disaster. The SYS gets to your program, but when your program calls a Kernal routine such as BSOUT at $FFD2 for printing, the ROM's gone! Instead, the program arrives at empty RAM in Bank 0 and gets lost. Even if you somehow transfer valid program code into that area, you can't achieve output since the I/O chips are no longer accessible.
What you need is a configuration that will give you RAM from $0000 to $BFFF, Kernal ROM from $C000 to $CFFF and $E000 to $FFFF, and I/O chips in the $D000 to $DFFF slot. No bank number gives you this; bank 12 is sometimes used to produce a similar effect, but it's not the best way.
You can produce the desired configuration by a direct store to address $FF00; a value of decimal 14 stored there will do the job. But you can't do that from BASIC. That powerful POKE to address $FF00 would make the BASIC interpreter itself disappear!
The solution is to use BASIC to select BANK 0 to make your program visible so you can SYS to it. Once the program starts, it puts $0E into address $FF00, reconfiguring to the desired map. It's a good idea to restore the configuration to Bank 0 just before the program returns to BASIC, so BASIC will be there waiting when control is returned to it, thus preventing a crash. Bank 0 can be restored by storing $3F into $FF00.
Here's a simple 128 program to print HELLO! to the screen just to show how a program may be positioned above the $4000 barrier. BASIC will have set up BANK 0 before the call to $6000 (the program's location). The program's first task is to make sure the Kernal ROM and I/O chips are accessible.
6000 LDA #$0E ;"special" config 6002 STA $FF00 6005 LDX #$00 6007 LDA $6018,X 600A JSR $FFD2 600D INX 600E CPX #$07 6010 BNE $6007
The string HELLO!, followed by a carriage return, is printed from a buffer to be established at $6018. Now restore the original configuration (bank 0, value $3F in $FF00).
6012 LDA #$3F ;restore config 6014 STA $FF00 ;("BANK 0")
You return to BASIC with the RTS command. It seems a little odd that you can go back to BASIC when the Bank 0 configuration has switched out the BASIC interpreter. Don't worry. The mechanism of the SYS call takes care of all the bank arrangements.
The text to be printed ("HELLO") must be stored in memory.
6018 48 45 4C 4C 4F 21 0D 00
It takes a while to get used to the architecture of the 128, but with careful planning it all works well.
You could enter the program using the built-in monitor, but here's a BASIC program to do the job.
100 DATA 169, 14, 141, 0, 255, 162, 0 110 DATA 189, 24, 96, 32, 210, 255 120 DATA 232, 224, 7, 208, 245 130 DATA 169, 63, 141, 0, 255, 96 140 DATA 72, 69, 76, 76, 79, 33, 13 150 BANK 0 160 FOR J = 24576 TO 24606 170 READ X : T = T + X 180 POKE J, X 190 NEXT J 200 IF T < > 3605 THEN STOP 210 BANK 15 300 BANK 0 310 SYS 24576 320 BANK 15