Programming Techniques - BASIC on the 6502 Second Processor =========================================================== J.G.Harston, 25-Nov-1997 Covers: HiBASIC, 6502Tube, BASIC filename just loaded, utilising memory, menu prompting. A 6502 second processor gives you an extra 64K of memory, but not all programs take advantage of this. When BASIC is entered, it is copied over to the second processor and runs from there. If you have HiBASIC, it is assembled to run at &B800 giving you memory from &800 to &B800 giving 44K available. However, this means losing a ROM socket, as you need HiBASIC to run on the second processor and BASIC (assembled to run at &8000) when running with the second processor turned off. Most people end up just having BASIC at &8000 as this runs on both sides. Unfortunately, this means that the spare memory at &C000 to &F800 in the second processor is wasted. FFFF +-----------+ FFFF +-----------+ | CoPro MOS | | CoPro MOS | F800 +-----------+ F800 +-----------+ | HiBASIC | | Spare RAM | B800 +-----------+ HIMEM C000 +-----------+ | | | BASIC | | | 8000 +-----------+ HIMEM | | | | |/\/\/\/\/\/| |/\/\/\/\/\/| | Variables | | Variables | +-----------+ LOMEM=TOP +-----------+ LOMEM=TOP | BASIC | | BASIC | | program | | program | 0800 +-----------+ PAGE 0800 +-----------+ PAGE 6502 CoPro running HiBASIC 6502 CoPro running BASIC The second processor introductory guide suggests putting LOMEM=&C000 and storing variables above BASIC. This works perfectly well, but it implies that your program is always going to be massively larger than the variables it uses. You have 30K for the program but only 14K for variables. What would be more useful it to put the BASIC program above BASIC at &C000 and put the variables in &800-&8000, giving more space for variables than for the program. FFFF +-----------+ FFFF +-----------+ | CoPro MOS | | CoPro MOS | F800 +-----------+ HIMEM F800 +-----------+ | | | | | | +-----------+ TOP |/\/\/\/\/\/| | BASIC | | Variables | | program | B800 +-----------+ LOMEM C000 +-----------+ PAGE | BASIC | | BASIC | 8000 +-----------+ 8000 +-----------+ HIMEM | | | | +-----------+ TOP | | | BASIC | |/\/\/\/\/\/| | program | | Variables | 0800 +-----------+ PAGE 0800 +-----------+ LOMEM Variables in high memory Program in high memory Initially, it would seem that you would do this with: PAGE=&C000:LOMEM=&800 Unfortunately, it is not quite that simple. BASIC gets confused if PAGE is higher than HIMEM, you keep getting 'No room' errors whenever you try to do something as simple as listing the program. Also, you can't just stick a PAGE move at the start of a program. The program has to be moved to the new PAGE position. The easiest way of doing this is to load it again. This then raises the problem of knowing what name the program was saved as. Most programs that reload themselves like this hard-wire the name into the program giving something like this: PAGE=&xxxx:CHAIN "MyName" However, this doesn't work if you have called it with something like CHAIN "$.Users.Jim.Progs1.MyName" Fortunately, there's a way of finding this out. When BASIC does a CHAIN, it passes a string to OSFILE to load the program. This string is stored in BASIC's string buffer which is at &0600 in 6502 BASIC, and if you don't do any string operations that filename will still be there. Caution - string operations include printing numbers! So, to reload the current program, we can do something like: CHAIN $&600 as long as we haven't done anything to disturb the string buffer. So, bearing this in mind, we can construct a program to hold its variables below its code. To start with, we need to see if we are running 6502-BASIC on a second processor, and change PAGE, HIMEM and LOMEM to suit and reload if necessary. HIMEM cannot be changed inside a PROCedure or FuNction as you loose the return address, so the best thing to do is to return a value to set HIMEM to at the start of the program: HIMEM=FNhimem0 If the program needs to end with the program still in a condition where it can be LISTed, or you want to load another program in the same space, HIMEM needs to be set above PAGE otherwise 'No room' errors will occur: DEFPROCend:HIMEM=FNhimem1:END and HIMEM=FNhimem1:CHAIN "Program" And finally, you may want to exit or chain a program into the 'normal' memory arrangement: HIMEM=FNhimem2:CHAIN "Program" As LOMEM will not be at the end of the program, TOP should not be used to find out how much memory is available - this is sloppy programming practice anyway. The following should be used in all cases anyway: maxmem%=HIMEM-LOMEM Now that the structure of the program has been described, here are the three support functions. They are in the 'HiBASIC' BASIC Library. FNhimem0 -------- Called to initialise the memory arrangement and reload the program if necessary. This function will normally actually be called twice on the second processor, first with PAGE set to &800 when it reloads the program to &C000, and then with PAGE set to &C000 when LOMEM and HIMEM are re-arranged. DEFFNhimem0:IF HIMEM=&B800 OR HIMEM>&FFFF:=HIMEM REM If we are already running HiBASIC, or a large memory system REM which won't be a 6502, just return current HIMEM. A%=130:IF((USR&FFF4)AND&FFFF00)=&FFFF00 OR ?&FFF7<>&6C:=HIMEM REM If running in I/O memory or not running on a 6502, just REM return current HIMEM. IF PAGE=&C000:LOMEM=&800:=&8000 REM At this point we must be running on a 6502 second processor. REM If we've just been loaded above BASIC, set LOMEM to bottom REM of memory and return to set HIMEM to bottom of BASIC ROM code. PAGE=&C000:HIMEM=&F800:CHAIN$&600 REM At this point we must be running in 'normal' memory, so move REM PAGE up, put HIMEM above it and reCHAIN the name stored in REM the string buffer. FNhimem1 -------- Called to ensure HIMEM is above the program in memory. This is needed if you want to END and LIST the program, or load another program over the current program without overwriting any data in the variable space. DEFFNhimem1:IF HIMEM HiDemo REM Demostates running above BASIC on 6502 CoPro : HIMEM=FNhimem0 ONERRORIFFNerr:PROCend PRINT"Program is at &";~PAGE PRINT"Data space is at &";~LOMEM;" to &";~HIMEM PRINT"Available memory &";~HIMEM-LOMEM;" (";HIMEM-LOMEM;" bytes)" REPEATUNTILFNmenu:PROCend:END : DEFPROCend:HIMEM=FNhimem1:END : DEFFNerr:REPORT:PRINT:=INKEY-1 : DEFFNhimem0:IFHIMEM=&B800 OR HIMEM>&FFFF:=HIMEM A%=130:IF((USR&FFF4)AND&FFFF00)=&FFFF00 OR ?&FFF7<>&6C:=HIMEM IFPAGE=&C000:LOMEM=&800:=&8000 PAGE=&C000:HIMEM=&F800:CHAIN$&600 DEFFNhimem1:IFHIMEM