=========================================
Memopak HRG Interface Manual for the ZX81
Memotech Corp
=========================================

Hello User,

By now you may have become quite expert at BASIC programming on the
Sinclair ZX81. You're probably making good use of one of the Memotech
MEMOPAKs or another commercial RAM pack. But you'd like to try graphics
- programming in a new dimension. Graphics can be great fun. Apart from
space zombies to be zapped without serious risk to your health, there is
a new world of design, animation, geometry and presentation to try.

Again, we hope that you like our elegant design. Now let's tell you how
it works.


How do I set up the Memopak HRG?

Disconnect your ZX81 power supply, and install your HRG pack between the
ZX81 and your RAM pack. You need a RAM pack because the HRG routines
operate primarily on the memory - a screen image is held as a 'video
page' in about 6.2K of RAM. The more RAM you've got the more video pages
you can use.

We recommend you use the Sinclair 1200 milliamp power supply as supplied
with the Sinclair printer and recent ZX81s.

You will find all MEMOPAK units plug in firmly, but for the best
connection we suggest you cut up and use the velcro tabs provided.
Moreover, our HRG pack utilises the addresses between 8 and 10K, so if
you have a MEMOPAK 64K you will have to make sure this area is switched
out. This means you must set your switch either in MODE B (2 ON; 1, 3
and 4 OFF) or MODE D (4 ON; 1, 2 and 3 OFF).Remember ON is UP. With a
64K RAM pack you will probably want to put your video page above 49152.
In this case you should remove the little square jumper switch next to
the back connector board. It's best to use a pair of tweezers or pliers
(but disconnect the power first). To keep the jumper safe, you can
replace it on just one pin.


Is there a quick test to show my pack is running OK?

Yes. Choose a spare memory area of at least 6.2K and set V to its start
byte address. Then do our special call. So enter as follows:

  LET V=19000 (with jumper in)
    or
  LET V=50000 (with jumper out)
  RAND USR 8619

What you should get is MEMOTECH appearing in white on a black background.
If not, check your configuration and your connectors, and try again.
When it's working, you can test the 'BASIC RE-SET' button which is
located on the side of your pack. This is for returning you from your
HRG display to your normal BASIC display.


Where and how are the HRG routines kept?

The MEMOPAK HRG contains a 2K EPROM where our subroutines reside and it's
full to bursting. We have provided at least 30 functions in the firmware
to help the user get the most out of the HRG. Our philosophy here has
been in the Sinclair tradition: help the user to help himself. We have
increased the scope of your activity; we leave you free to explore the
new territory.


How does the HRG work?

Simply, the HRG allows you to output in dots rather than characters
(1 character = 8x8 = 64 dots) or Sinclair pixels (1 pixel = 4x4 = 16 dots).
Since the dot is the smallest graphics item, it offers the maximum
flexibility. Any shape, character or pattern can be generated by the
right combination of dots, and the possibility of smoother curves
increases.

In everyday life, to fill a page with dots is a laborious process. But
here the sweat is taken out of it by a number of means:

a) Subroutines which work much faster because they operate directly in
   machine code.

b) Full use of looping facilities in both BASIC and machine code.

c) The ability to pre-plot special characters or mix in characters
   from the Sinclair range.

d) Powerful rolling and scrolling facilities.

The range of subroutine calls is listed in a table in the back of the
booklet. They span many functions, and are particularly powerful in
their ability to make the most of your memory. They also span a number
of different levels - dot, line, character, block and page.


How is the screen related to the memory?

As far as our pack is concerned, your screen is made up of 192 x 248 dots
or HRG pixels (the equivalent area of 24 x 31 BASIC screen character
positions). The leftmost column of the screen is ignored by the HRG
- for subtle software reasons. All screen activity takes place in a
'video page' of memory which you can show on the screen at the same time.
You can also manipulate the 'video page' without showing it on the screen;
or you can be looking at another video page while doing so!


How is a video page organised?

A variable is reserved by the HRG system to hold the memory address of
the start byte of the video page. So always remember to set variable V
to the start of the particular video page you want to reach.

Roughly speaking, one screen dot (or HRG pixel) is stored in one bit of
memory. However when placed in memory each horizontal 'line' of 248
graphics bits is preceded by 2 bytes of control data. In addition, there
is a single byte of screen control data terminating the whole video page.
So the arithmetic looks like this:

Bit Summary

        Line     Screen    HRG
        Control  Graphics  Memory
Line      16   +   248   =   264
Page    3072   + 47616   = 50688

1 video page = 50688 + 8 page control bits = 50696 bits.

Byte Summary

        Line     Screen    HRG
        Control  Graphics  Memory
Line      2    +   31    =   33
Page    384    + 5952    = 6336

1 video page = 6336 + 1 page control byte = 6337 bytes.


Whereabouts in memory can I put a video page?

You must choose an area which is not otherwise occupied by the system
variables, the instructions, the display file or your other arrays.
The simplest thing is to set a low RAMTOP leaving you enough space
(6337 bytes per video page) between that and your real limit of memory.
Clever users may find other ways.


How do I use the HRG subroutines?

A subroutine is called by using the Sinclair USR function. We recommend
the use of an instruction such as RAND, as this has few side effects,
but other instructions may do. All the subroutines can be called
initially from one address (8192), so that the same call can be used for
any function:

  RAND USR 8192

If however you want to reserve RAND to set the seed for the randomizer,
then use, say, LET A=USR 8192. To nominate a particular subroutine
however you must first specify its name in a reserved variable Z$. So to
call for example the simple PLOT function (which sets a bit in the video
page) you must first enter the instruction:

  LET Z$="PLOT"

"PLOT" in turn uses the X and Y variables to find out the co-ordinates
to be plotted. So the whole step goes like this:

  LET X=64
  LET Y=100
  LET Z$="PLOT"
  RAND USR 8192

This little routine, provided the right initialisation steps have been
taken, will set one bit in the video page specified.


How do I use the MEMOPAK HRG with a BASIC program?

The MEMOPAK HRG has been designed so that you can use it in ordinary
BASIC. There are also routines which allow you to switch the screen from
conventional BASIC display to the HRG display and back again. While you
are developing your program, you can use the manual 'BASIC RETURN' button
on the side of the pack which puts you back into BASIC display mode,
without in any way endangering your graphics data. When you return back
to the BASIC display mode, you may be upset to find a blank screen. This
is blank simply because although your BASIC program is running, it has
not been requested to output anything to the screen. You'll probably want
to look at your program listing at this point, so you need to use the
Sinclair BREAK and LIST functions.


What about FAST mode?

These routines work rapidly in FAST mode, at least as rapidly as graphics
on the Sinclair Spectrum and with more pixels. However, in FAST mode you
lose the screen and the gratifying experience of seeing the graphics
at work for you. Moreover in FAST mode the 'BASIC RETURN' button cannot
work, so if you want to get back to BASIC display manually, you have to
break in and enter "SLOW" even though there will be no screen response
until you've done it. Now you can use the 'BASIC RETURN' button.


How do I initiate an HRG routine in my BASIC program? (Page functions}

The first thing is to set the start byte of your video page in the
reserved variable V. Then you must cite and activate the "START" function.
Functions must always be cited in reserved variable Z$ prior to the call.
"START" does two things: initiates the HRG system and assigns the video
page area (start address cited in V) to it. (Later in the program the
"PAGE" function could be used to assign another video page without
reinitiating the system.) (Note: the groups of instructions which follow
are typical enough but when all put together they may form a pretty
absurd program. For 'real' program examples see the back of this booklet).
Your routine so far could well look like this:

  10 LET V=40000
  20 LET Z$="START"
  30 RAND USR 8192

You may now want to clear the video page area initially (or else you may
pick up what you left there before - remember an area above RAMTOP is not
cleared by Sinclair).

  40 LET Z$="CLEAR"
  50 RAND USR 8192

Note the same USR address is used whatever the function. "CLEAR" also
uses variable V to find out where the page to be cleared is located.
Since we are talking about the same page that was assigned with the
"START" function, there is no need to re-set V. All the activity so far
has gone on in the memory video page and we haven't seen a thing. To keep
your eye on what's going on, let's do an "HRG" call. This will do an HRG
display of the memory page rather than display anything your BASIC
program may have output. Don't worry, your BASIC outputs are still
accessible (they're still in the Display or D-FILE), but they are now
invisible.

  60 LET Z$="HRG"
  70 RAND USR 8192

Note that as we are still talking about the same video page, we still
have not re-set V. The screen is now locked into our video page and
anything that happens there, we can watch. "HRGINV" will also show what
is in the page, but in reverse, and without changing the bits in the
memory. So in just seven lines we are ready to start depicting something.
If seven lines is too much for you, we have kindly provided you with a
macro (multiple) function: "STARCH". "STARCH" sounds like a new concept
in programming for laundry control but really it simply means "START" +
"CLEAR" + "HRG" and the above program can now be shortened to 3
instructions:

  10 LET V=40000
  20 LET Z$="STARCH"
  30 RAND USR 8192

To summarise: the HRG system is initialised; a video page is assigned
from 40000 onwards; the page is cleared and the contents (blanks or
unset HRG pixels) displayed. We can just mention 3 other page level
functions:
"PRINT" will transfer any video page to the Sinclair printer.
"STRING" will let you pass a video page into a long string which can
then be SAVEd on cassette by the ZX81.
"UNSTRING" will unpack a string into a video page for you on re-LOADing.
The video string is always S$. You can use "STRING" simply to clear
space for yourself above RAMTOP. But don't try to "UNSTRING" something
which you did not "STRING" first, unless you are sure you have got the
control characters right. When re-loading a video page with "UNSTRING"
(that has been stored and SAVED within the "STRING" function) it is
necessary to:

a) make sure you do not use RUN for the re-load section but GOTO, in
   order to prevent S$ from being cleared.

b) make sure you do not redimension S$ on re-entering as this will also
   lose the array.

c) remember to re-set V and call the "STARCH", "UNSTRING" and "HRG"
   subroutines to see the video page again.

Sample re-load subroutine. Enter program with GOTO 1000.

 990 STOP
1000 LET V=50000
1010 LFT Z$="STARCH"
1020 RAND USR 8192
1030 LET Z$="UNSTRING"
1040 RAND USR 8192
1050 LET Z$="HRG"
1060 RAND USR 8192
1070 GOTO ....

Incidentally, if you don't like the idea of repeating the subroutine
call - e.g. RAND USR 8192 - all the time, you may like to place it in
a little subroutine. For some repeated calls, you might also like to set
the parameters from within the routine as well.


What can I do now?

You are now free to experiment with the other subroutine functions (and
their parameters) listed at the back.

They are broken down into five kinds: page functions, block functions,
character functions, line functions and dot (or HRG pixel) functions. The
page functions have already been described above. As for the rest, let's
start small.


HRG pixel (or dot) routines

The simplest function is "PLOT" which requires X and Y co-ordinate
parameters in addition to V:

  80 LET X=50
  90 LET Y=60
 100 LET Z$="PLOT"
 110 RAND USR 8192

This will place a dot on your screen. Remember that the co-ordinates in X
and Y work like this:

    Axis        Range  Direction
X   Horizontal  0-247  Left to right
Y   Vertical    0-191  Bottom to top

"UNPLOT" works in exactly the same way, so:

 120 LET Z$="UNPLOT"
 130 RAND USR 8192

will take the dot away again. If you want to find out whether an HRG pixel
is set use "TEST", this time calling the routine with the Basic LET
instruction for the reply:

 140 LET Z$="TEST"
 150 LET K=USR 8192
 160 IF K=0 THEN .........
 170 IF K=1 THEN .........

Any variable may be used; if the routine returns 0 then the pixel is unset,
if 1 then set; and you can take action accordingly. In this case, since
the routine is still testing the old X, Y locations, which we UNPLOTted,
then the reply will be zero. With "HRG" called, your screen displays an
image of the video page. However you can use the "LOCATE" function to find
the absolute memory address of a pair of co-ordinates, and so manipulate
the video page directly. Remember however, that the video page is not
exactly the same as a screen; there are two control bytes preceding each
line (the first one is a Sinclair newline byte (118) and the second one is
zero) and one more byte after the last line in the page (also 118). So if
you want to interfere with a video page directly, take these into account.
To find out where in memory our pixel location is, enter:

 180 LET Z$="LOCATE"
 190 LET K=USR 8192

and K will receive the address.


Can I run two or more video pages together?

Yes, they can be located next to each other in memory and will effectively
be joined vertically. In this case the first line control byte of the
later video page should be the same as the last page control byte of the
first video page. It is now possible to look at any 'intermediate' page
made up of later lines of the earlier page and earlier lines of the later
page. To call such a page make sure that your start byte value placed in V
is displaced from the start bytes of the 'real' video page by a multiple
of 33.


What about Geometry?

At this point we can introduce our simple geometric functions. We could
have provided more but we think it is an excellent chance for users to
brush up on their skills. The only functions we provide are "LINE",
"UNLINE", "BLINE" and "WLINE"; any other shape can be effected by
combinations of these or the "PLOT" call, and the Sinclair maths
functions.

You'll need to work on your algebraic geometry, or dust off a text-book to
get algorithms for curves, sine waves and so on. Try this natural log
curve:

 200 LET Z$="PLOT"
 210 FOR X=1 TO 245
 220 LET Y=33*LN X
 230 RAND USR 8192
 240 NEXT X


Line routines

"LINE" will join the points specified in the pairs of co-ordinates P, Q
and X, Y and you should be able to do straight-edge geometry yourself.
"UNLINE" will wipe out a line in the same way. "BLINE" (black line) and
"WLINE" (white line) are used only for vertical plotting and will draw a
line upwards from X, Y until a bit of the same setting is encountered. The
vertical coordinate of the setting is returned in Y. Used in conjunction
with the "LAUNCH" routine, some sophisticated shading routines are
possible. See our example at the back. Lastly, for the zappers, there is
our "LAUNCH" routine. This will fire a laser beam vertically up the screen
and detect a 'hit' (i.e. if any of the bits in its path were set). If
there is a hit, it passes back the vertical co-ordinate and vanishes.
Otherwise, it disappears off the top of the screen. "LAUNCH" need not be
used so aggressively; it can also serve as a 'radar' function to detect
the presence of the first bit set in a vertical column rising from the
X, Y position cited. This can be used for shading or blocking in.


Character routines

There are two kinds of character you can plot - those you've designed
yourself and those Sinclair provides. To design a simple horizontal line
of bit settings, simply set up a string of O's and 1's in C$, with a colon
as terminator:

 250 LET C$="10101:"

Instead of 0, you can use * to avoid disturbing the initial status of a
bit. To design a 2-dimensional character you can simply use N, S, E or W
(or a combination) to re-set the start location of the next series of bit
settings, and continue. So we could plan a cross on the screen instead:

Type in

 250 LET C$="1***1NE1*1NE1NW1*1NW1***1 :"
 260 LET X=30
 270 LET Y=40
 280 LET Z$="SKETCH"
 290 RAND USR 8192

and the cross will appear with the bottom left-hand point located at 30,40.
In this example, we built the character upwards using N, but we could have
dropped it downwards using S, or missed out a line altogether using SS.

"UNSKETCH" has the effect of unsetting the bits set in the string.

"INVSKETCH" is like "SKETCH" except that it reverses the bit settings,
placing a reverse image of your character in the video page itself.

"SINCH" does the same thing as "SKETCH" except that you need to cite a
Sinclair character. For reverse images, you can use Sinclair's own
inverse functions. A whole string of Sinclair characters can be displayed
anywhere in the page, starting at the X, Y point which represents the
bottom left-hand corner of the first character. To wipe out a "SINCH"
display, use the Sinclair space character.


Block handling routines

For block handling routines, to save on tedious co-ordinates we have hit
on the concept of north, south, east and west. For this reason, variables
N S, E and W are called.

We have two dynamic routines which can be useful for animated displays -
roll and scroll. The "roll" functions take a block and shift the
constituent lines up or down, taking the line that has dropped off the
block at one end and adding it on at the other. This is done according to
the following 2-character command strings - "RU" (roll up) and "RD"
(roll down), and these will use the N, S, E and W parameters.

A similar set of commands exist for the scroll functions. "Scroll" differs
from "roll" in that the line that drops off will completely disappear and
a blank line will step in at the other end. Scrolling can be done
horizontally as well as vertically. So these are the last four command
strings you've got: "SU", "SD", "SR" and "SL".

Note that when moving horizontally, E must be greater than W; when going
vertically, N must be greater than S. Scrolling and rolling is most
effective when set in a loop.


Subroutine Calls

Command
string (Z$)    Function                                       Parameters

Page routines
START          Initiates HRG system and assigns memory        V
               video page

PAGE           Assigns memory video page                      V
CLEAR          Clears a page                                  V
HRG            Displays a page                                V
HRGINV         Displays a page inversely                      V
STARCH         Macro = Start + Clear + HRG                    V
PRINT          Prints a video page                            V
PRINT1         Prints top line of video page                  V
BASIC          Displays current BASIC page                    none
STRING         Copies page into BASIC string                  V,S$
UNSTRING       Copies string into video page                  V,S$
               (requires DIM S$(6337) or more)

Block routines
RU             Roll block up                                  V,N,S,E,W
RD             Roll block down                                V,N,S,E,W
SU             Scroll block up                                V,N,S,E,W
SD             Scroll block down                              V,N,S,E,W
SR             Scroll block right                             V,N,S,E,W
SL             Scroll block left                              V,N,S,E,W

Character routines
SKETCH         Plots user-defined character                   V,X,Y,C$
UNSKETCH       Unplots user-defined character                 V,X,Y,C$
INVSKETCH      Reverses user-defined character in
               page and screen                                V,X,Y,C$
SINCH          Plots ZX81-defined character                   V,X,Y,C$

Line routines
LINE           Draws a line                                   V,X,Y,P,Q
UNLINE         Wipes out a line                               V,X,Y,P,Q
*BLINE         Draws black line 'UP' until set BIT            V,X,Y
*WLINE         Draws white line 'UP' until set BIT            V,X,Y
*LAUNCH        Draws momentary line 'UP' until set BIT        V,X,Y

Dot routines
PLOT           Sets one BIT/HRG pixel                         V,X,Y
UNPLOT         Unsets one BIT/HRG pixel                       V,X,Y
*TEST          Gets a setting of a BIT                        V,X,Y
*LOCATE        Gets a memory location of a BIT                V,X,Y

* These calls elicit a reply and so should be made with the LET statement:

  LET G=USR 8192

will place the reply in G. "LAUNCH", "BLINE" and "WLINE" will get a value
of the vertical coordinate or zero if none is found. "TEST" will get a
value of zero for an unset, one for a set bit. "LOCATE" will get the
absolute memory address of a bit set. Or you can use a logic test:

  IF NOT USR 8192 THEN GOTO 1000


HRG Parameters

Z$ = Command string
V  = Start byte of assigned video page
X  = Horizontal co-ordinates (0-247)
Y  = Vertical co-ordinates (0-191)
P  = Secondary horizontal co-ordinates (0-247)
Q  = Secondary vertical co-ordinates (0-191)
N  = Uppermost block line (0-191)
S  = Lowest block line (0-191)
E  = Rightmost block line (0-247)
W  = Leftmost block line (0-247)
C$ = String for "SKETCH", "SINCH" etc.
S$ = String for storing video page data


HRG error codes

L = Parameter variable not declared
M = HRG command string not known
N = Horizontal parameter too large
O = Vertical parameter too large
P = Invalid element in "SKETCH" string


Here are some examples to try:

A) To draw two waves, and shade in the areas between.

  10 LET V=40000
  20 LET Z$="STARCH"
  30 RAND USR 8192
  40 LET Z$="PLOT"
  50 FOR X=0 TO 247
  60 LET Y=100+50*SIN (X/20)
  70 RAND USR 8192
  80 LET Y=100+SIN (X/30)*COS (X/15)*50
  90 RAND USR 8192
 100 NEXT X
 110 FOR X=0 TO 247
 120 LET Y=0
 130 LET Z$="LAUNCH"
 140 LET Y=1+USR 8192
 150 LET P=USR 8192
 160 IF P=0 THEN GOTO 190
 170 LET Z$="BLINE"
 180 RAND USR 8192
 190 NEXT X

Run it and see. Is it a bird? Is it a Loch Ness Monster?

A few notes about the program: "LAUNCH" detects the first set bit in a
vertical pattern. In line 140 we add 1 and use that as the start of "BLINE"
which will draw a black line up until the next set bit. Sometimes, we
don't want to draw a line up, so we test to make sure that a second bit
exists as in lines 150-160.


B) To make a beautiful pattern from curves. Is it a bird? Is it a seal?

  10 LET V=40000
  20 LET Z$="STARCH"
  30 RAND USR 8192
  40 LET Z$="PLOT"
  50 FOR A=10 TO 100 STEP 3
  60 LET D=A*A
  70 LET C=D*190
  80 FOR X=0 TO 247
  90 LET Y=C/(X*X+D)
 100 RAND USR 8192
 110 NEXT X
 120 NEXT A


C) Here is a program which shows a funny clock. We're sure you could make
   it better - more accurate; with hours as well. Change line 80 to make
   it slow down or speed up.

  10 LET V=40000
  20 LET Z$="STARCH"
  30 RAND USR 8192
  40 LET P=100
  50 LET Q=100
  60 FOR T=1 TO 60
  70 GOSUB 130
  80 FOR Z=1 TO 20
  90 NEXT Z
 100 GOSUB 210
 110 NEXT T
 120 STOP
 130 LET X=100+50*SIN (T*PI/30)
 140 LET Y=100+50*COS (T*PI/30)
 150 LET Z$="SINCH"
 160 LET C$=STR$ T
 170 RAND USR 8192
 180 LET Z$="LINE"
 190 RAND USR 8192
 200 RETURN
 210 LET X=100+50*SIN (T*PI/30)
 220 LET Y=100+50*COS (T*PI/30)
 230 LET Z$="UNLINE"
 240 RAND USR 8192
 250 RETURN


Good Luck from all at MEMOTECH


===============================================================================


TECHNICAL NOTES

Display file resolution: 248 x 192
Display file structure : 33 bytes x 192 (first two bytes are control codes:
                         $76 and $00) + 1 byte screen terminator ($76)
Display file size      : 6337 bytes
Display file location  : ($407B)

IN $005F = Selects normal display mode.
IN $025F = Selects hi-res mode.
IN $035F = Selects inverse hi-res mode.

The INs set the I register to $1E (normal display mode) and $1F (hi-res
display mode) - bit 0 of the I register selects the display mode.

The 2K ROM appears at $2000-$27FF.

The internal 1K RAM overlays the ROM between $0000-$03FF.
