Using the XML instruction

The GPL instruction XML is used to eXecute Machine Language
procedures.
You can call up to 256 different procedures, divided in 16 tables of
upto
16 procedures each. The XML instruction requires a one byte immediate
operand
in the form >XY, where >X is the table number, and >Y the
procedure
number in that table.

The address of the procedure itself is fetched from the proper table
and branched at by the interpreter.

Example: XML >1B call the 12th procedure in the second table
(numbers
start from zero).

The locations of the 16 tables are pre-defined:

Table

Address

Memory

>0

>0D1A

Console ROM

>1

>12A0

"

>2

>2000

Low memory expansion

>3

>3FC0

"

>4

>3FE0

"

>5

>4010

Peripheral card ROM (or RAM)

>6

>4030

"

>7

>6010

Cartridge ROM/ Rambo bank (RAM)

>8

>6030

"

>9

>7000

Cartridge bank / Rambo bank

>A

>8000

Decoded as >8300 on most machines

>B

>A000

High memory expansion

>C

>B000

"

>D

>C000

"

>E

>D000

"

>F

>8300

Scratch-pad memory

The first two tables being in ROM memory, their content is
predefined.
The others might be filled by the user, allowing for combination of GPL
and machine language.

Cassette operations

It's probably easier and safer to access cassettes with a PAB,
having
CS1 or CS2 as a filename. However if you insist on doing it yourself,
here
are some clues:

I/O 4,dest readI/O 5,dest writeI/O 6,dest verify

The motor should first be turned on (1), then off (0) with cru bits
>0016 for CS1 and >0017 for CS2.

dest contains the first of 4 consecutive bytes in cpu memory
(! even address !)

1 word number of bytes to read/write/verify

1 word address of data buffer, in vdp memory

In case you're curious to know how the data are encoded on the
magnetic
tape, look-up my page on cassette tape
operations.

Using the COINcidence instruction

The COIN instruction checks for coincidence between two objects on
screen.
These objects can be anything, including sprites, characters, or even
exist
only in the programmer's mind! The instruction returns with cnd bit set
if coincidence was detected, and reset if it wasn't.

The source argument must contain the screen coordinates of object 1,
as 2 bytes (pixel row, pixel column). Similarly, the destination
argument
should contain the coordinates of object 2.

The COIN instruction must be followed by some data:

1 byte indicating the grain of the checking (mapping value)

2 bytes that contain the address of a coincidence table.

The header of this table contains indications on the size of the
considered
objects. The interpreter uses them, together with objects coordinates,
to quickly decide whether objects are in contact. If that's the case,
the
remainder of the table is used to determine if there is coincidence or
not.

This way, the definition of 'coincidence' is up to the user.

The draw back is that you must supply coincidence table for each
pair
of objects that you intend to check.

If you find difficult to generate such tables, you may use the small
extended Basic program included in my GPL package: it's awfully slow,
and
limited to 8x8 pixels objects but that's all I could come with in one
week-end.
Please feel free to improve it, for instance by writing a GPL or 9900
version
of it...

Building a coincidence table

In a coincidence table, you consider all possible positions in which
the two objects could touch or overlap each other, and for each
position
you tell the interpreter if you regard it as coincident or not.

For instance, let's consider the following two objects:

++ is a 2x3 characters object, xx is a 3x3 chars object+++xxxxxx

Note: the size to consider is the size of a putative rectangle
circumscribing
the object. For instance, this object is 2 by 4:

ooooo

There are 42 positions in which the 2 objects touch/overlap, let's
view
them in order, from top-left touching to bottom-right touching:

To get a complete coincidence table, we need four more bytes, that
serves
as a header. These are:

Height of object 1 plus height of object 2 (here: 3+2 = 5)

Width of object 2 plus width of object 2 (here: 3+3 = 6)

Height of object 1 (here 2)

Width of object 1 (here 3)

The final table thus looks so:

TABLE1 BYTE 5,6,2,3 BYTE >00,>F1,>F3,>E7,>80,>3F

Great, but recall this is only valid for coincidence between object
1 and object 2, in this very order. Should you decide to check for
coincidence
between object 2 and object 1 (although I really don't see why), then
you
would need another table.

If there are several objects of each kind, you also need different
tables
to check for coincidence between objects 1 and 1, and ojects 2 and 2.

Changing the mapping value

The mapping value selects the "grain" of coincidence checking:

A value of 0 operates at pixel level,

A value of 1 considers "boxes" of 2 by 2 pixels,

A value of 2 uses 4x4 pixel boxes

Etc.

The advantage of a coarser grain is that it reduces the size of the
coincidence table, at the expense of a lower resolution.

To construct a table in mapping value 1, first construct the
"pixel-wise"
table with mapping value 0. Then divide it in 2x2 bits boxes, starting
with the position where the upper left corner of the two objects are
superimposed.

Using the above example again, we have:

V 0 0 0 0 0 0 0 0 1 1 1 1 0 0

0 1 1 1 1 1 0 <-- upper-left corners superimposed 0 1 1 1 1 1 0

0 1 1 1 1 0 0 0 0 0 0 0 0 0

Now reduce each box to a single bit, by taking the predominant value
in each box. If there is a tie, one can choose to consider it as 0 or 1
(for the purpose of this example, let's decide for 1).

The reduced table looks like this:

0 1 1 0 0 1 1 1 0 1 1 0

Which gives us >67 >6F, when padding with four 1s.

For a mapping value of 2, one would proceed similarly, by creating
4x4
boxes.

Now, did you get that? I hope so, given the time it took me to put
it
down!

Using sprites

Sprites size and magnification

The size and magnification of sprites are determined by 2 flag bits
in the VDP register 1:

Sprites are not allowed in text mode (40 columns, 6 pixels-wide
characters).
Neither are colors: colors of text and background is stored in VDP
register
7.

Interrupts should be left on for proper sprite motion and sound
processing

Memory size should be left as 16K (otherwise any address above
>1000
will wrap around (i.e. >2345 is understood as >0345)

When setting vdp register 1 (with the MOVE instruction) a copy is
automatically
made at >83D4 (VDPR1), it's often convenient to recover that byte to
modify vdp register 1, since all VDP registers are write-only. The
keyboard
scanning routine (GPL opcode SCAN) automatically reloads register 1
from
that byte when a key is detected.

Sprite attributes

For each sprite, in numerical order, a 4 bytes definition is to be
loaded
in the sprite attribute table, whose location is defined by VDP
register
5 (address = register content * >0080). The usual address is
>0300,
it MUST be used if auto-motion is desired.

The sprite pattern table doesn't need to be the same as the
character
pattern table. By entering a different value in VDP register 6 (addr =
value * >0800) one can have 256 definitions, located say at
>1000,
and that have nothing in common with character pats (located at
>0800
if VDP reg 4 contains 1).

You probably noted that a sprite can "vanish" at the right
of the screen, being only partly visible, whereas this is impossible at
the left: at position >00 all the sprite is onscreen, at >FF it
jumps
to the right.
The way around this is to set the clock bit, i.e. add >80 to sprite
color: this results in shifting the sprite reference point from the
top-left
corner to 16 pixels to the right (i.e. top-right corner of a dobble
size,
dobble magnification sprite). Of course sprite position must be
adjusted
(by adding 16 to column value), but now the sprite can vanish on the
left.

Sprites can vanish at the top (row values >F0-FF) and at the
bottom
(row value >B0-BF) without any problem because there are only 192
pixel
rows.

Automatic motion

The interrupt routine in charge of moving sprites expects a sprite
motion
table located at >0780 in VDP memory, and the sprite attributes at
>0300
(VDP reg 5 = >06)

The speed is defined as pixels per 16/60 seconds (16/50 in Europe),
positive values move sprites to the right/bottom, negatives to the
left/top.

To enable auto-motion, after properly setting the table, you should:

Store the number of the last sprite to move into byte >837A
(SPRNO)

Make sure the "ignore all" and "ignore sprites"
bits of the flag byte >83C2 (SYSFL) are not set. These are bit 0
(>80)
and 1 (>40), they can be cleared with: AND >3F,@>83C2.
(For your information, the next 2 bits (>20 and >10) disable
auto-sound
processing and <quit> key detection, respectively).

GROM subroutines

Only GROMs 0 and 1 have a standard header, GROM 2 is the
continuation
of GROM 1 and has no header.

At the beginning of GROM 0 is a table of subprograms, that contains
only branching instructions (mostly BR, and a few B). The location of
these
subprograms may vary among GROM versions, but the table is always the
same.

For each of these subroutines, there is a pre-defined symbol in my
assembler.
No guaranty that other assemblers will use the same name...