Z80 Space-Time Productions Single Board Computer
Using Assembly Language with BASIC
BASIC has a portal through which assembly language routines may be called from with a BASIC program. The VECTOR command allows you to set the starting address of your routine, then the USR(x) command will cause BASIC to suspend and call your routine.
When BASIC initializes this jump to the FCERR routine internal to BASIC, so if you execute a USR command without first setting some other VECTOR, you will get an "? Illegal Function Call Error" from BASIC.
Machine code executes many times faster than similar code in BASIC, because of all the conversion and processing that has to be done for each character in code, whereas in Machine Code ("assembled assembly language"), each byte IS the instruction or data, this is processessing at its most fundamental level. There are several reasons that you might want to incorporate machine code into BASIC:
The Steps to Use Assembly with BASIC:
1) Load your assembly language program.
- You may use the BASIC 'LOAD' command too bring in a previously assembled machine code program, provided it is saved in
Intel Hex format. You will need to have it stored on your host machine and use Hyperterminal to Send Text File to the Z80.
- You may convert all the bytes of your rrooutine into decimal and use BASIC's POKE to place the code into ram.
This is very time consuming, and unless your routine is very short, this will add tons to a BASIC program.
- Use the MONITOR to manually place the aacctual HEX code in memory, then go to BASIC.
2) Set the Vector
It is not necessary to calculate the memory value in decimal, since VECTOR can use hexadecimal, thanks to a routine I added to BASIC. However, if you prefer decimal, one way to calculate addresses over 32767 is to take the decimal equivalent of the desired address, (i.e. 32768) and subtract 65536 from it. Thus 32768-65536=-32768, VECTOR -32768. The actual USR 'JP' command ($C3) is stored at $3203 ($4203 in the expanded memory version), and the vector right after it at $3204 (LSB) and $3205 (MSB), in the typical Z80 (8080) address format (low address byte, high address byte). A VECTOR 32767 ($7FFF) will be stored as: 3) "Execute the Jump" - Command Adama (new Battlestar Galactica) PASSING PARAMETERS: In BASIC, the USR command requires a parameter and returns a passed parameter. This makes it convenient to hand off
a 16-bit signed integer to the machine language program, and to expect a 16-bit signed integer return. In order to properly pass parameters, your machine code needs to access a couple of BASIC internal functions:
DEINT is an internal routine that takes an Integer number from the Floating Point Register, converts and places this 16 bit value into
the register pair DE (hence the name). There is, for every version I release of this BASIC, a JP to DEINT located at $2FFA. Your routine will need to
make a CALL to this location to get the FP integer into registers DE. This will effectively give you the 'X' value of USR(X).
Since BASIC uses this function to return to BASIC whatever is in the Floating Point register, you will need to finish by making
a CALL to one more internal BASIC function before you execute your final RETurn. ABPASS is an internal BASIC routine that takes a 16-bit signed integer that is in registers A (MSB) and B (LSB).
While not a true 'register pair', this routine treats the number that way. There is, for every version I release of BASIC, a JP to ABPASS
located at address $2FFD. You will need to make a CALL to this location at the point where you have placed your results in A and B, prior
to your final RETurn to BASIC. Both DEINT and ABPASS must be run from within your Assembly program, you cannot call them from BASIC before switching the vector
command around to call your routine. BASIC operations will again alter your registers and parameters before you can get there to intercept them.
You may simply use the hex address with the VECTOR command as follows:
VECTOR $02BE
The decimal syntax for the vector command is VECTOR nnnnn, where nnnnn is the starting address of your machine language routine.
NOTE: The address is in signed 16-bit format from BASIC so the addresses range from 0 - 32767, -32768 - -1 as follows:
VECTOR 0 -------> $0000
VECTOR 32767 ---> $7FFF
VECTOR -32768 --> $8000
VECTOR -1 ------> $FFFF
An address like $FFFF (65535) would render 65535-65536=-1, VECTOR -1. This is a
pain in the rear, but that's how it works. Fortunately, the ROM and the parameter ram is
located below 32768, so you shouldn't have to resort to this strange math very often.
$3203 - $C3
$3204 - $FF
$3205 - $7F
Example:
120 VECTOR 32767
130 A=USR(E)
In the above example:
130 A=USR(E)
E is the variable you send to your assembly program, and A is the variable that is returned. If you do not modify the FP registers,
or if you do not care to pass parameters back and forth, you may use dummy arguments in these places. 'E' can also be any numeric expression.
(i.e. A=USR(R*2+13), BASIC will calculate the expression, and leave the result in its internal FP registers for your use.
If you don't alter the value in the FPREG, USR(E) will return E, unchanged. Bear in mind the parameter you send is in the same 16-bit signed format
as the VECTOR address.
The vectors at this table are:
$2FF4 - JP START (BASIC Cold Start) same as JP $1000
$2FF7 - JP WARMST (BASIC Warm Start) - You can use this to start BASIC and retain the program you had in Ram before you "EXIT"ted BASIC.
$2FFA - JP DEINT (Pass variable from FPREG into DEINT).
$2FFD - JP ABPASS (Pass 16-bit signed integer in registers A (MSB) and B (LSB) into the FPREG.
An alternate way to you may also pass parameters by placing them into ram and then having BASIC 'PEEK' those locations when you are done. This is a good secondary way to pass ASCII characters and other non-16-bit-integer data back into BASIC.
OTHER NOTES:
1) You may call monitor ROM routines with USR, provided VECTOR addresses them correctly.
2) An ? Illegal Function Call Error will result if you try to pass a parameter which is out of the 16-bit signed integer range.
3) When USR is called, BASIC sets up 8 levels (16 bytes) of stack storage area. The Stack area is quite large and should accomodate just about anything you can throw at it.
4) You should always remember that any exit condition to your program should leave the Stack unaltered, in other words you should POP off all the things you PUSHed onto the Stack before finishing up. Otherwise, you may crash BASIC, or some of your program may start acting very strange. Most likely it will crash.
5) You can change memory and registers at will with machine code, so be careful what you change.
The NASCOM BASIC manual suggests any interrupt handling save the Stack, all registers AF,BC,DE,and HL, and be sure to execute an "EI" before
you return if you ran a "DI" during your Assembly program.
WHERE TO PLACE YOUR CODE:
1) The Stack slides downward from $30FF to $3000 (2K version); this is quite a large area for a machine stack so most of the time there are a quite a few bytes near the bottom $3000 that are zero'd out that you may use, it is possible but unlikely that the SP will overwrite them.
2) At this point in time, the current MONITOR rom does not place any system parameters into the area I reserved, so you may use the entire area from $3100 to $315F, not much, but better than nothing and not likely to be disturbed by any other programs. (Again, this applies only to the 2K version).
3) If you have built a RAM expansion for your machine that presents itself from $4000 upward, the "large" version of BASIC will set $4300 as the starting place for all BASIC text programs. The good side to this is that it leaves the original configuration ram area from $3000 through $37FF TOTALLY VACANT for your usage (I am using a ROM in this block from $3000-$3FFF).
4) If $3xxx is not available on your machine for some reason, I would suggest you place your machine language code around $E000 or $F000 depending on how large it is. Basic sets it's string area at the TOP of available memory (250 bytes) so you will want to keep clear of this. The stack and other parameters are from $4010-$42FF, so don't get into this area unless you want a crash. There are parameters at $42xx (check the source code) that tell BASIC where the string area and stuff are, you can sample these before placing your code, but it will take some work.
Click HERE if you do not see a menu frame to the left.
This page created September 18, 2004.
All information contained herein that is generated by J.Owens ©2006.
Other information credited to its sources.
This Site is not affiliated with Space-Time Productions, Mr. M.Simon, or Mr. Ron Weiss, however I extend a grateful Thanks to those parties.
This site has a sole purpose to provide technical information, and is not intended to infringe any prior
copyrights nor to derive funds that would otherwise be the property of Microsoft, Space-Time Productions
or it affiliates, either past or present.
May the Force be with you.