Machine Code Made Easy - Part 3

Machine Code Made Easy | 1 | 2 | 3 | 4

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 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 )


For example, to set the border colour to 3:

LD A,3
OUT (254),A ; 254 is the BORDER port

Simple eh?


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 SAMCO’s Advanced 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:-

* LMPRD0 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


D0 to D4- page number 0-31
* VMPRD0 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!!!

; =====================================

 ORG #6000; Start address
SPRITEIN 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
SP1LD A,D; This bit will check if
 AND %11000000; the sprite will go off the
 CP %11000000; bottom of the screen
 LD B,16; 32 pixels width = 16 bytes
SP2LD C,0; We shall use C as a mask byte
 LD A,(HL); Get the byte to print
 AND %11110000; Check the first nibble
 LD C,%11110000; Set the MSN* of the mask
 AND %00001111; Check the second nibble
 LD A,%00001111; Set the LSN* of the mask
SP4LD 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
 AND %01111111; Test for off-screen
 DJNZ SP2; Loop back
SP5PUSH 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.
 DJNZ SP1; Loop back
SP6LD A,(HMPRSTORE); Restore everything to what
 OUT (HMPR),A; it was on entry
 RET; Go bye-bye
OFFSCREENDEC B; We’ve already done INCs for
 JR Z,SP5; this part of the loop
OFF1INC HL; Move on the counters without
 INC DE; touching the screen for as
 DJNZ OFF1; many times as necessary.
HMPRSTOREDB 0; * NB. MSN and LSN stand for
SPSTOREDW 0; MOST significant and
 DS 14; LEAST significant
STACKSPACEDW 0; nibbles.
HMPREQU 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 interupts 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


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.


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.