Machine Code Made Easy - Part 3
Author
Publisher
Description
From Fred 8
Machine Code Made Easy - Part 3
Bonjour! Mes petits choufleurs, et bienventure.
Yes, ‘tis I again with part 3 (yup, THREE!) of the series. Today
we shall be looking at somethings I hope will be of relevance to
all you budding coders out there. After a short bit on ports,
we’ll head straight into building a program.
But first in this 15 page bumper issue…
PORTS
======
Ports are the vital parts of your coup‚ that allow you to talk to it from the keyboard, joystick, mouse etc. They also allow your coupe to talk back to a printer, tape recorder etc.
So, as you can see we need a way in machine code to control
what goes in (INPUT) and comes out (OUTPUT) from them.
Your coupe can address 64k (that’s 65536) of ports, and the
commands for doing so are pretty simple:
IN (xx),A ; ( must be A )
OUT (xx),A ; ( or B or C or D etc )
xx can be any 8-bit port number.
“Hmmm,”I hear you cry.”How do we get a 16 bit number into an 8 bit one?”
Well, the way in which it works is quite complicated, but to make matters easier I shall present a simple method: Firstly,
most of the useful ports lie between 0 and 255, so this ain’t a problem.
For the ones that don’t we simply use:
LD BC,xxxx ; Port number
IN (C),A
or OUT (C),A ; ( or B or C or D etc )
OK?
For example, to set the border colour to 3:
LD A,3
OUT (254),A ; 254 is the BORDER port
Simple eh?
MEMORY PAGING
===============
So, where is all this getting us? Well, the answer is simple:
To help us page memory.
Now, before I go an—.y further, I will suggest that if you are
keen to do some coding you should get the SAM Coupé Technical Manual. It can explain the paging process in more detail than I
have time or space for. But simply, there are 3 ports to choose
which parts of the 256k (or 512k) memory to wish to have present
in the CPU’s 64k addressing range. Think of it like a TV -
although there are 4 (or more!) channels always going, you
select the one you want to see. In the same way, the coup‚
always has its 256/512k memory there, but the processor can only
‘see’ 64k at a time. OK?
Well, in order to manage this memory, the 256/512k is split
into 16/32 PAGES each 16k long. You choose which two ADJACENT
pages go into low memory (0-7FFF) and which go into high memory
(8000-FFFF). Two ports are used to do this:
* LMPR (250 dec) - the number in this port equals the page
number in 0-3FFF. The page following this ( 0&1, 1&2 etc ) goes
in at 4000-7FFF.
* HMPR (251 dec) - just as above, except that the pages go in
at 8000 and C000
* VMPR (250 dec) - this chooses which page(s) the current
screen is held in.
However, the ports don’t just control the RAM pages in memory
The coupe has 2 16k pages of ROM - ROM0 & ROM1. ROM0 is present
in 0-3FFF if BIT 5 of LMPR is reset. ROM1 is present in
C000-FFFF if BIT 6 of LMPR is set. Also, BITS 5 & 6 of VMPR
select the screen mode (0-3). To sumarise:-
* LMPR | D0 to D4 | - page number 0-31 |
D5 | - ROM0 present if 0 | |
D6 | - ROM1 present if 1 | |
D7 | - prevents writing to RAM in 0-3FFF if 1
|
|
* HMPR |
D0 to D4 | - page number 0-31 |
* VMPR | D0 to D4 | - page number (0-31) |
D5 , D6 | - MODE number (0-3) |
There is one thing to note about VMPR - with modes 1 and 2
screens, only 1 16k page is needed, but with modes 3 and 4 a
whopping 24k is required. This means 2 pages must be set aside
and VMPR holds the number of the first one. BUT this MUST be an
even number (0-31)
For example:
LD A,%00100000
OUT (250),A
This puts page 0 into 0-3FFF and page 1 into 4000-7FFF. It
also freezes out ROM0 to make way for the RAM pages.
OK? Good, then lets’s do….a program!!!
; SPRITE & MASK PROGRAM BY STEVE TAYLOR |
; ===================================== |
; |
ORG #6000 | ; Start address | |
SPRITE | IN A,(HMPR) | ; Get the current contents of |
LD (HMPRSTORE),A | ; HMPR and store them. | |
LD (SPSTORE),SP | ; Store where the stack was | |
; in case we page it out. | ||
LD SP,STACKSPACE | ; Use a temporary stack. | |
LD A,L | ; L contains the sprite’s page. | |
OUT (HMPR),A | ; Put it into 8000-BFFF | |
LD L,0 | ; H contains the sprite number. | |
CP A | ; Clear the carry flag. | |
RL H | ; HL now holds the sprite | |
; no x 512 : 512 bytes / sprite | ||
SET 7,H | ; Setting bit 7 of H is like | |
; adding #8000 to HL. This | ||
; makes sure the sprite data | ||
; is in 8000-FFFF | ||
LD A,L | ; Make A=0 | |
RR D | ; A bit of maths here - the Y | |
RRA | ; coord is in D with the X | |
OR E | ; coord in E. Because each | |
LD E,A | ; line on a mode 3/4 screen is | |
; 128 bytes long we simply | ||
; divide D by 2 to find the | ||
; line’s address. We then | ||
; merge the spare bit with E | ||
; for the final address in DE | ||
LD B,32 | ; 32 pixels length | |
SP1 | LD A,D | ; This bit will check if |
AND %11000000 | ; the sprite will go off the | |
CP %11000000 | ; bottom of the screen | |
JR Z,SP6 | ||
PUSH BC | ||
LD B,16 | ; 32 pixels width = 16 bytes | |
SP2 | LD C,0 | ; We shall use C as a mask byte |
LD A,(HL) | ; Get the byte to print | |
AND %11110000 | ; Check the first nibble | |
JR NZ,SP3 | ||
LD C,%11110000 | ; Set the MSN* of the mask | |
SP3 | LD A,(HL) | |
AND %00001111 | ; Check the second nibble | |
JR NZ,SP4 | ||
LD A,%00001111 | ; Set the LSN* of the mask | |
OR C | ||
LD C,A | ||
SP4 | LD A,(DE) | ; Get the screen byte |
AND C | ; Cut out the mask | |
OR (HL) | ; Merge in the sprite | |
LD (DE),A | ; Put it on the screen | |
INC HL | ; Move on the counters | |
INC DE | ||
LD A,E | ||
AND %01111111 | ; Test for off-screen | |
JR Z,OFFSCREEN | ||
DJNZ SP2 | ; Loop back | |
SP5 | PUSH HL | ; We add 112 to DE to move down |
LD HL,112 | ; a line. The result goes into | |
ADD HL,DE | ; HL but EX DE,HL switches | |
EX DE,HL | ; round the registers again. | |
POP HL | ||
POP BC | ||
DJNZ SP1 | ; Loop back | |
SP6 | LD A,(HMPRSTORE) | ; Restore everything to what |
OUT (HMPR),A | ; it was on entry | |
LD SP,(SPSTORE) | ||
RET | ; Go bye-bye | |
OFFSCREEN | DEC B | ; We’ve already done INCs for |
JR Z,SP5 | ; this part of the loop | |
OFF1 | INC HL | ; Move on the counters without |
INC DE | ; touching the screen for as | |
DJNZ OFF1 | ; many times as necessary. | |
JR SP5 | ||
HMPRSTORE | DB 0 | ; * NB. MSN and LSN stand for |
SPSTORE | DW 0 | ; MOST significant and |
DS 14 | ; LEAST significant | |
STACKSPACE | DW 0 | ; nibbles. |
HMPR | EQU 251 | ; ( 1 nibble = 4 bits ) |
Phew! Don’t worry, it doesn’t take long to type in. In fact,
I’m so generous I’ve supplied it already coded ( PRESS ‘D’ FOR
THE DEMO ). It is located at #6000 when you assemble it, but you
should make sure you put in it the space after the second page
of the screen. ALSO, when you call it, do this first :-
1. Disable interrupts by using the command DI
2. Page the screen into 0-7FFF so that the sprite routine will
be at 6000
3. Make sure the page no. (0-15) of your sprite data is in L
4. Make sure the sprite no. (0-64) is in H
5. Make sure the X coord (0-127) is in E
6. Make sure the Y coord (0-191) is in D
OK?
Your sprites should be 3232 pixels in size (1632 bytes).
You can use any colours for them except palette 0. Any nibble
that is 0 is not printed; instead the background is shown
through. This effect is called MASKING and prevents a horrible
block appearing around your graphic.
To prepare your sprites I suggest you draw them with FLASH.
Once you’ve saved your screen, write a small B™.ASIC program to
load in the screen and then GRAB all the sprites in turn. Once a
sprite has been GRABbed into a$, POKE a$(3 TO) into memory. Then
save this data.
That’s about it for this month folks. If you have any queries
problems ( preferably m/c related ) or a routine to blow my mind
feel free to write to me at :-
29 Murray Crescent,
Perth PH2 OHN.
and I’ll try to reply on screen.
DEMO
——
This is just a (very!) simple demonstration of my sprite
routine. If you want to use the routine in your own programs
feel free, but note that it MUST be located in the spare 8k in a
page after the screen which must be paged in from 8000 onwards.
The demo uses 2 screens - the one we can see and another back
or dummy screen. For every frame it clears the dummy screen,
adds on the sprites and the logo and switches VMPR to point to
this screen ( the other screen is now the dummy ). Although this
uses twice the memory, it is a useful trick if you need fast,
flicker-free animation.
If you fancy disassembling the program code, it lies at #8000
and works without interupts, so be careful if you use
breakpoints - don’t enable them before continuing.
#———————————————#
I PRESS ANY KEY FOR THE DEMO I
#———————————————#