| Lesson P1 - Basic Firmware Text functions
So we can make a start, we're going to create some quick functions... we'll use the firmware to save time where we can.
This lesson We're going to create the following routines... on 5 different Z80 Systems!
|CLS||Clear the screen.||All may have changed|
|Locate||Move the text cursor to a new (X,Y) location where H=X and L=0 and the top left corner of the screen is (0,0)||BC,HL,DE unchanged|
|NewLine||Move the cursor to the start of the next screen line||BC,HL,DE unchanged|
|PrintChar||Print the character in A to the screen||BC,HL,DE unchanged|
|WaitChar||Wait for a keypress, and store it's character in A when we get it||BC,HL,DE unchanged|
|PrintString||Print a string of characters from address HL ... string is CHR(255) terminated||BC and DE unchanged... HL now at end of string|
|Basic Text Functions on the Amstrad CPC:|
|The CPC version is pretty straight forward!
We use firmware call &BC14 to clear the screen (CLS).
PrintChar is done by a firmware call to &BB5A
WaitChar is done by firmware call &BB06 too...
When it comes to Locate - we have a firmware call, but it considers the top left to be (1,1) so we have to INC H and L by 1 to make it work the same as on all systems.
NewLine on the CPC is performed with Chr(13) (carriage return) and chr(10) (NewLine) - we just get the PrintChar call to do the work for us!
PrintString is also straight forward, using the PrintChar command to print each character to screen.
And that's it!
the Basic Series... the CPC is kind of the Benchmark for this
development series... and will continue to be unless someone builds a
better Z80 emulator with built in Assembler!
The CPC is fairly kind to us too.. making these simple jobs... well... simple!
|Basic Text Functions on the ZX Spectrum:|
|The ZX spectrum is a little more tricky!
Firstly it corrupts all the registers, so we need to use PUSH & POP to back things up and make sure it works the same as the Amstrad!
CLS is ok, we can Call &0dD6B to clear the screen
Locate is odd!
RST 2 (Call &0010) will send a character to the screen - and we move the text cursor by sending a special character to the screen!
The basic command 'AT' is Character 22 (yes the word 'AT' is a character!) we print this to the screen, then print the co-ordinates Y first, then X!... weird eh!
The Spectrum Firmware accesses hardware via Channels - we connect to a Channel device, and send to or read data from that channel.
The Spectrum Text screen is split into 2 bits, the main top part is Channel #2 - which we will use for the PrintChar command... we set A to 2 and Call &1601 (CHAN_OPEN) to open channel 2... then we use RST 2 to put char A on the screen
PrintString works in the same way, we open Channel 2, then send each character through it with RST 6
WaitChar opens a connection to Channel 0 (the bottom of the screen and Keyboard)... a Call to &15D4 will read in a character from the keyboard.
On the ZX spectrum a new line is achieved with just CHR(13) - we put our NewLine command just above PrintChar to save a call!... the Speccy is the odd one out here, Chr(13)+Chr(10) is more typical
|The spectrum is a bit tricky to work with! it has odd screen and key functions return strange values on 48k systems...
and it corrupts all the registers!
Still, it's perfectly usable, and later we'll write our own 'direct hardware' routines, and skip all these problems!
|Basic Text Functions on the MSX:|
|The Spectrum gave us a hard time, but the MSX is much kinder!
PrintChar is handled by firmware call &00A2
WaitChar is handled by firmware call &009F
CLS has a firmware call of &00C3... but it requires us to set A to Zero for it to work right.
Locate is also handled by a firmware call, and like the CPC, the top corner is (1,1) - so we INC H and L
NewLine on the MSX is Chr(13)+Chr(10) (Carriage return + NewLine)
PrintString is handled simply with the PrintChar firmware call....
and we're done! Simple!
|The MSX Operating system makes development really quick and easy!
It does have disadvantages in places.. with regards to speed and memory usage... but for this job of getting started, it's great!
|Basic Text Functions on the TI-83:|
|Being the most limited system, it's no surprise the the TI-83 has some strange stuff in store for us!
On the TI-83 we use RST 5 to call firmware functions - on the TI it's called BCALL - it pages in firmware rom and calls the address stored in the two bytes after the command... we're going to need it a lot!
That said, it's pretty easy to make it do what we need - we just need a lot of PUSH POP's to protect our registers!
CLS is handled by the firmware function called ClrScrnFull at &4546... notice we refer to it in a DW after the RST 5 ... this is how we make the TI-83 BCALL a function
Locate is unique on the TI too! The current cursor position is held in to memory addresses, we just load the new values into those addresses and we're done!
PrintChar is done by firmware function PutC at &4504
and WaitChar is handled by GetKey at &4972... we also use this for out PrintString command!
Newline is not done by any kind of character printing... the firmware has a special command for that too! NewLine function &452E does that nicely!
And that's it!... the firmware has handled all our requirements very nicely!
TI-83 is the most basic system we develop for... but if we can make
something work with the TI-83... we can probably do it with anything!
it's like our 'Canary'... if our code doesn't die on the TI... it's probably well designed!
|Basic Text Functions on the Enterprise:|
|The enterprise is quite similar
to the spectrum way of doing things! It uses Channels to connect to
hardware, and special Charcodes for Text functions
This code fragment relies on an INIT routine setting two channels up for us... it assumes a Screen has already been opened on Channel 10 , and Keyboard open on Channel 11... see the source downloads to see how it works!
On the Enterprise... RST 6 is the EXOS call... A will contain the Channel, and the command will appear in a single byte after the RST6
PrintChar is achieved by EXOS command 7 (see DB 7)... we load B with the character, A with the screen channel (10) and call RST 6
PrintString is the same, we use EXOS command 7 to print each character as needed
Newline on the Enterprise needs CHR 13 and CHR 10 - so we could use PrintChar... but instead we use WriteBlock EXOS command 8... which we need to tell it the number of bytes in BC, the memory address of the data in DE... and of course the channel in A
WaitChar reads from the keyboard Channel... which we've defined as 11... EXOS command 5 will wait for a character from the Channel (from the keyboard)... it's returned in B... so we need to move it back to A
CLS is done with some special control codes... CHR(27) (&1B) is defined as 'Escape' which tells the hardware special commands are coming!...CHR(26) (&1A) means "Clear the screen and reset the cursor position'... again we use a WriteBlock Command to save some commands
Locate is also done with Escape codes... the commands are 'Escape = Y X' where Y and X are the co-ordinates - strangely on the EP128 we have to add &21 to convert our 0,0 based co-ordinates to what the Enterprise wants... then we use WriteBlock to send the string!
Complex, but not bad... and EXOS doesn't alter the other registers... so at least no PUSH POPping!
'Channel' nature of the Enterprise means this takes a lot of code...
and while the Enterprise OS does not corrupt registers... we need
practically all of them to communicate with the OS!
Still it does the job nicely, and later we can use a slightly modified version of our Amstrad code to access the screen and keyboard directly!
| Lesson P2 - More Text Functions, Improvements... and the Sam Coupe!
We did some good stuff last week.. but our Spectrum and TI-83 getkey functions could have been better... we're going to fix that today... add a function to get the cursor position that we'll need in the future... and we're going to start learning the Sam Coupe!
Remember... the sourcecode to all of these are in the Sources.7z file - so download it if you want to try them out!
|WinApe can't do very advanced conditions,
We would like to do IF ScreenWIdth > 32 as a compiler definition, but Winape won't allow us!
So to work around it, we define ScreenWidth32 for IFDEF's, and ScreenWidth as 32 for ranged CP statements.
|Reading Key input on the ZX Spectrum:|
|On all of our systems, we're going to add some definitions to the header,
We'll need these in later lessons to allow our code to function differently depending on the different systems
We're defining screensize functions, and the Keys for Enter and Delete
|The WaitChar function we wrote on the Spectrum last time
wasn't great... it often returned 'Command Characters' rather than
letters... so this week we'll change it!
This version uses the Firmware updated Variable at &5C08... the firmware updates this each interrupt call.
We clear it to 0... then wait for something to be pressed and return it...
Of course this would wait forever if interrupts were already disabled... so we use the "PO trick" we learned in Lesson M1... if we LD A,I... PO will be set if interrupts were disabled!... this allows us to turn interrupts on... and back off again if needed!
|Here's the new command we're adding this week! GetCursorPos
will return the position text will print next... in the same HL format
as our Locate command!
On the speccy we can get these from memory locations &5C88 and &5C89
Unfortunately, for reasons best know to itself, the Speccy stores these relative to the bottom right corner, so we have to do some subtraction to get them in the 'Top-Left' relative format we want!
we're going to use IFDEF command, you should make sure the EQU
definitions appear at the top of your code.. or WinApe may get confused!
if the definition isn't BEFORE the first IFDEF.. During the first assemble scan, they don't exist, but on the second they do, and WinApe messes up all our labels!!...
To Fix it, just put them in the header, before other code, and things will be fine!
|Reading Proper letters and numbers on the TI-83:|
|As with the spectrum we define our Screen size, and Enter and Delete keys|
|On the TI-83 our GetChar command was returning all kind of weird things!
We need to get proper numbers and letters for future lessons, and a big lookup table seems wasteful!
Fortunately, even though they don't map to Ascii.. 1-9 and A-Z are at least consecutive!
We can fix these important ranges, just by checking if the keypress is within those ranges, and remapping them to the proper symbols... other keys will still return weird stuff.. but they're not important to us for now!
|The TI-83 may punish us when keyreading, but the GetCursorPos couldn't be easier!!!|
|Getting the Text Cursor Position on the MSX:|
|As with the other systems, the MSX needs some definitions.
However, we have no changes to make to our Keyreader!
|Our new GetCursorPos command can get the screen location from &F3DC... but it's (1,1) based... so we need to decrease H and L to get the (0,0) base we want!|
|Getting the Text Cursor Position on Enterprise 128:|
|The Enterprise uses a 40 char wide screen, and a weird key for Backspace, but that's about it for the definitions!|
|But it makes us work for our GetCursorPos!
To read cursor pos on the Enterprise, first we send " [ESC] ? " to the screen... then we read two bytes in FROM the screen!!!
Re first will be the Y pos, and the second will be the X pos... but like with our LOCATE command... the Enterprise adds &21 to the co-ordinates...
We have to subtract &21 from both to get the (0,0) based co-ordinate we want...
It's a bit of a 'hassle' but it works fine, so it's all good!
|Getting the Text Cursor Position on Amstrad CPC:|
|The CPC is pretty easy, so we've left it pretty much last... Here are the screen and key definitions !|
|&BB78 on the CPC is know as TXT_GET_CURSOR - we can
just call it and it will return the cursor position, but we need to
decrease H and L, to get the (0,0) based figures we want.
Not much work on the CPC this week!
|Basic Text functions on the Sam Coupe:|
|The Sam Coupe has a 32x24 screen in it's default text mode, so that's how we'll use it.|
|Our INIT routine will load 1 into address &5ABB... this will turn off the 'Scroll' message, the rest of our work will be done by the CLS routine|
|... and here it is!
&014E is know as JCLSBL... it will clear the whole screen if we set A to 0
next we call &015A .. known as JMODE... we just want text mode so we set A to 0 (Though basic actually calls this mode 1!!)
Finally we want our output to go to the screen, so we load A with &FE - known as channel 'S' - the main screen area...
A call to &0112 (JSETSTRM) will do the job!
|PrintChar can be handled by just calling RST 2... but we have to protect a lot of registers!|
|The Sam Coupe just needs a CHR(13) to start a new line - just like the spectrum!
|Our Locate command just needs to write it's values to memory addresses &5A6C, and &5A6D... and that's it|
|unfortunately, when we try to get it back for GetCursorPos.... the Sam Coupe firmware plays a trick on us!
When we do a NewLine... the X position will reset to &FE! How annoying...
To fix this, we just check if the Xpos is anything over &F0... and reset it to zero... and the problem is solved!
|We're going to call &0169 (JREADKEY) to get input from the Keyboard... this returns NZ when a key is pressed.
Unfortunately(?) it returns very quickly... so we need to pause a bit to make sure we don't instantly read in a load of letters...
We could do a HALT, but that would fail if interrupts were disabled, so instead we loop around a bunch of NOP's for a while.
Of course we could just wait until the key was lifted again... but we want it to repeat if it's held down long enough!
|There seem to be some strange people who consider the Sam Coupe to be a successor of the ZX spectrum!...
because Sam Coupe screen mode 1 is identical to a spectrum... and it's other functions are superior.
As it has more memory it can load in a fake ROM and simulate a 48k speccy pretty easily!
Fun Fact: the Sam Coupe clocks DOWN to 3mhz from it's usual 6 when in 'Spectrum screen mode'...weird eh!
|We'll use these in a later multiplatform lesson, but lets try a little test program now...
See LocateTest.ASM in the samples download!
This will show some locations to the screen, then read in text, clearing the screen when BACKSPACE is pressed... and starting a new line on ENTER
|Of course, this little test will work the same on every system, because it uses our common functions...
But lets see it on the Sam Coupe!
the two first lines dump HL from the Get Char Pos, H being the X pos, and L being Y
Then we can type our text onscreen, hit enter to start a new line, or press backspace to CLS.
We'll do some far better stuff soon using these functions in the Multiplatform Series!!!
|The content of this week's lesson may seem boring, but now we have enough to do some proper text reading, and we'll be using these in the Multiplatform series to make some really cool stuff!|