                          Windos



           Ian Briscoe's program will extend the

           graphics capability of your Spectrum.



[ This program was published in Your Computer in two

  parts, in December 1984 and January 1985. I've joined

  the two together in this text file. The tables for each

  part are at the end of that part - part one is a small

  bit of text with a lot of tables, part two has just one

  small table but much more main text.

    At the same site where you got this text, you should

  also be able to find a "Windos.tzx" file containing all

  the programs described below. They're not quite in the

  order described, but in one that is more convenient for

  loading from tape. For part one, the demo program comes

  first, followed by the Windos machine code itself, and

  only then the machine code loader.

    For part two, first up is the Invert-Screen loader

  program - I haven't provided pre-loaded machine code

  for this, because it needs the rest of Windos anyway.

  Next is the whole demo again, this time with picture 2

  using the Extended Basic, followed by the main code

  again (to save the bother of rewinding the TZX) and the

  Extended Basic machine code. Note that the Ext-Basic

  does require that the Interface 1 areas have been

  initialised before you execute it; if it crashes on

  you, try any IF1 command (CAT 1 works, even if you have

  no cartridge loaded) before loading the demo. Finishing

  off part two are the Extended Basic loader, and the

  un-MERGEd new version of Picture 2 (which is useless on

  its own, but as it was a separate listing which had to

  be typed in, I thought I might as well provide it).

    The original Extended Basic loader saved its machine

  code to Microdrive, and its demo loaded the code from

  Microdrive as well (unlike the main demo, which asks

  which you prefer), presumably because if you need an

  Interface 1 anyway, Microdrives are faster than tapes.

  However, since I was preparing a TZX already and

  nothing in the code requires a Microdrive (only the IF1

  itself is necessary), I've changed this to use tape.

                               Richard Bos, October 2012. ]



Ever since the Spectrum was launched, other computers have

been brought on to the market with better graphics capa-

bilities.

  Some feeling that the Spectrum could do with some added

graphical muscle, armed with my 48K Spectrum with Micro-

drive and Hisoft's excellent Devpac, a highly recommended

package, I set out to give the Spectrum all these facili-

ties and more. The result is Windos, a 5K program packed

with practically every feature you could wish for. A whole

book could be written describing all the possibilities, but

the main functions are:

#32- or 64-column windowing.

#Four-way window scrolling.

#An extended plot function.

#Instant colour changes.

#Large letters in any of four orientations.

#An intelligent paint/unpaint.

#An alternative screen at any address.

  To get Windos up and running, type in listing 1 and save

it a few times, then run it. Once run successfully, the

code will be automatically saved.

  Owners of Microdrives may wish to change the appropriate

lines to enable saving to cartridge.

  Most experienced Spectrum users will be familiar with the

concept of streams and channels. What I have done is to

alter the channel 3 output routine vector, found in the

channel information area, and make it point to my own

output routine.

  This means that the ZX Printer is now disabled.

        LPRINTs, OPEN #2,"p"

can be used to enable Print. However, how can this be of

any use for accessing the routines? BBC users are used to

the VDU statement on their micro, but this can be replaced

by:

        PRINT CHR$ n;CHR$ n; etc

to achieve the same effect. Well, this is exactly how the

routines are accessed, via control codes. Of course, most

of the codes are different from the BBC's and have a diffe-

rent number of parameters - see table 1 for a complete

run-down. Now back to the original question. To get Windos

into operation, first initialise channel 3 by using

        RANDOMIZE USR 60000

  However, this won't clear the system's own variables area

which holds the attributes for all 8 windows, each "window

map", as I call them, being 45 bytes long, so use

        RANDOMIZE USR 60003

to initialise it. More information about the window map can

be found in table 2.

  Now you can begin to use the system. Type in the demon-

stration program to see some of the many effects possible.

  Once fully understood, I hope that you will begin to

realise the possibilities the system offers. Next month,

I will explain how the system works inside.

  The last part of the series will give Interface 1 owners

an Extended Basic to use the system neatly.

___________________________________________________________



 Table 1. The Control codes

 CHR$ 0;CHR$ n; Selects a window. n must be in the range

        0 to 7.

 CHR$ 1;CHR$ tlx;CHR$ tly;CHR$ brx;CHR$ bry; Defines a

        window's size. Top left x, top left y, bottom

        right x, bottom right y.

 CHR$ 2;CHR$ n; Scrolls. In the window map there are two

        scrolling registers. This scrolls the current

        window according to these registers. n is the

        number of times the operation is to be done.

 CHR$ 3;CHR$ n; Scroll window left n times. Preserves the

        scroll registers.

 CHR$ 4;CHR$ n; As above but for right.

 CHR$ 5;CHR$ n; As above but for up.

 CHR$ 6;CHR$ n; As above but for down. WARNING. CHR$ 6 is

        the comma in PRINT statements. Any attempt to use

        PRINT comma will result in a down scroll.

 CHR$ 7;CHR$ byte;CHR$ value; Window map poke. There are 45

        bytes in a window map (see table 2), numbered 0-44.

        This enables those bytes to be changed easily.

 CHR$ 8; Back cursor.

 CHR$ 9; Forward cursor.

 CHR$ 10; Down cursor.

 CHR$ 11; Up cursor.

 CHR$ 12; Delete.

 CHR$ 13; Newline.

 CHR$ 14;CHR$ routine+mode;CHR$ x;CHR$ y; This is the plot

        command and is a lot like the Beeb's. See table 3.

 CHR$ 15; COPY the whole screen to the ZX printer.

 CHR$ 16;CHR$ ink; Define text ink. PRINT INK n; will work

        but is not temporary.

 CHR$ 17;CHR$ paper; As above but for paper.

 CHR$ 18;CHR$ flash; As above but for flash.

 CHR$ 19;CHR$ bright; As above but for bright.

 CHR$ 20;CHR$ over; As above but for OVER.

 CHR$ 21;CHR$ inv; As above but for INVERSE.

 CHR$ 22;CHR$ x;CHR$ y; Same as PRINT AT y,x but note the

        x and y are the opposite way around to Sinclair AT

        control code.

 CHR$ 23;CHR$ tab; Changes the current x co-ordinate to

        "tab".

 CHR$ 24;CHR$ oldink;CHR$ newink; Window instant ink

        change. Changes any oldink to newink.

 CHR$ 25;CHR$ oldpaper;CHR$ newpaper; As above but for

        paper.

 CHR$ 26; CHR$ bright; Window actual bright set/reset.

 CHR$ 27; CHR$ flash; Window actual flash set/reset.

 CHR$ 28;CHR$ width;CHR$ height; Like the CSIZE command on

        the QL. Defines the width and height of the large

        characters. See table 2 for more information.

 CHR$ 29; In the window map there is an address which

        tells all the Windos routines where the start of

        the screen is. If this were changed, then any

        output would not be seen. A Dragon-like invisible

        screen will be present. So to get the data from

        the screen memory to the actual display memory,

        use this command.

 CHR$ 30; Home cursor.

 CHR$ 31; Clear the current window.



 NOTES

     There is no graphics windowing.

     CLS uses the print routine.

     There is normally a visible cursor.

___________________________________________________________



 Table 2. The window map.

 Byte   Meaning.

 0-3    The window size as set up and in the same order as

        CHR$ 1; etc.

 4      The text colour.

 5      The graphics colour.

 6-7    The text co-ordinates, with 0,0 being at the top

        left of the window, NOT the screen.

 8-9    The last x,y specified by CHR$ 14;.

 10-11  Used internally.

 12     Text flags. See table 4.

 13     Graphics flags. See table 5 [which was missing].

 14     The attribute used by the cursor, so the cursor

        can be flashing or not.

 15-29  The parameter queue. See next month's article for

        more details.

 30     Current control code.

 31-32  Next free space in queue, as an address.

 33     Number of parameters to come before execution.

 34     Width of large characters.

 35     Height of large characters.

 36-37  Second to last point specified by CHR$ 14;.

 38     Draw pattern. Like the Oric PATTERN command. This

        is the bit pattern that draw uses to do dotted

        lines. Normally 255 for solid lines.

 39     Text attribute mask. As there is no eg. PAPER 8

        allowed, this is used to achieve the same effect.

        Every bit of this byte that is set means that

        the equivalent bit of the old attribute to be

        obliterated by printing will not be destroyed.

        So to achieve INK 8 set this byte to 7, PAPER 8

        is BIN 111000 etc.

 40     As above but for graphics.

 41     The pixel scroll register.

 42     As above but for the attributes.

 43-44  This is the address of screen memory. Normally

        16384, but can be changed. Normal Intel format

        applies, i.e. LSB first followed by the MSB.

___________________________________________________________



 Table 3. The plotting routines and modes.

   When using the plot command, CHR$ 14, the first para-

 meter is the routine added to the plotting mode. They are

 as follows:

 Plotting modes.

 0  = Normal OR plotting.

 1  = XOR or OVER plotting.

 2  = UNPLOT.

 3  = MOVE.

 Plotting routines.

 0  = PLOT. An ordinary dot plot.

 4  = DRAW. Draw a line to x,y. Note that the origin is in

      the top left corner.

 8  = PAINT. Fill an enclosed area. This is an intelligent

      fill so make sure there is at least 0.5K between

      Ramtop and your program as the machine stack is used

      as workspace.

 12 = BOX. 

 16 = TRIANGLE. Draws a triangle using the last and the

      second to last points plotted as two of the three

      points, the third being the point specified.

 20 = FILLED BOX. Like BOX only filled. Like the other

      shape routines, the draw routine is used so if a

      draw pattern - see table 2, byte 38 - is in use then

      there will be a textured box.

 24 = SET. Just sets the plotting mode and the graphics

      co-ordinates.

___________________________________________________________



 Table 4. The text flags.

 Bit.   Meaning.

 0-1  00 = Normal over printing.

      01 = XOR or OVER 1 printing.

      10 = Inverse printing.

      11 = OR printing.

 2    Scrolling suppression.

      0 = Normal scrolling when the cursor tries to go too

          far up, or too far down.

      1 = A Lynx-type wraparound window.

 3    Attribute suppression.

      0 = Old attributes destroyed.

      1 = Old attribute left unchanged.

 4    'Form feed' suppression.

      0 = Normal newline.

      1 = Cursor stays on the same line.

 5    Output selection.

      0 = Normal 32 or 64 column windowing.

      1 = Large letters. To print large letters, this bit

      must be set.

 6    32/64 column selection.

      0 = 32 column windows and printing.

      1 = 64 column windows and printing.

 7    Cursor switch.

      0 = Cursor on.

      1 = Cursor off.

   It is useful when working at bit level to use the BIN

 function.

___________________________________________________________



[Table 5. The graphics flags.

   This table seems to have gone missing from the article.

 From the demonstration program and a bit of rummaging

 around, the following could be made up:

   The large letter mode uses the graphics flags, not the

 text flags. As can be seen from lines 6045 onwards, the

 position for large letter printing must be set using the

 Plot function, not using AT, and they take the graphics

 colour.

   The bits in the graphics flag have (as far as I can

 make out, so cum grano salis) the following meaning:

   Bits 0 and 1 are used as a copy of the plotting mode in

 the last Plot command. This is not useful for Plot itself

 (since you re-specify them every time you use it), but it

 does mean that the large letters take on the mode (Over

 and Inverse) of the last plot. This is the only way to

 get Over and Inverse for large letters. It is convenient

 to specify them in the positioning Set Plot which will

 probably precede their printing.

   Bits 2 and 3 specify the direction of print, as shown

 in lines 6045-6048 of the demo. Bit 2 controls normal

 direction or reversed and bit 3 controls vertical or not,

 leading to the following combinations: 0 is normal,

 left-to-right printing (of course); 4 is upside down,

 right-to-left (not just mirrored); 8 is vertical, turned

 90 degrees left (so legible bottom to top); and 12 is

 vertical, 90 degrees right, printed top to bottom.

   Bit 5 functions as a temporary attribute mask, as if

 byte 40 in the window map had been poked with 255 - that

 is, similar to bit 3 in the text flags.

   Bits 6 and 7 are used internally, but I have not been

 able to work out what for, and setting them by hand does

 not seem to do anything.

   It looks like bit is 4 never used at all.]

___________________________________________________________



                         [Part 2]



     Ian Briscoe continues his explanation of Windos.



If you typed in last month's listings, and managed to get

them to work perfectly, then you should by now have real-

ised that used properly, Windos is a pretty powerful aid to

graphics creation. There are a few quirks that I neglected

to point out last month - if you try to LIST with the new

routines, you will not have a chance to stop the listing,

and also no tokens will be printed as tokens, but instead

as odd characters. This is not as hopeless as it seems,

because you can now set up a character set in RAM, and use

codes 128-255 as the user-definable characters.

  The normal system variable CHARS is the system's charac-

ter set pointer, except in 64 column mode, as this has its

own font near the start of Windos. In addition, you may

have discovered that the Plot command works on a full 256

by 192 grid.

  Now to the main business. This article is aimed primarily

at hackers - i.e. fanatical machine-code buffs who delight

in nosing their way through other people's programs and

systems, and altering them to their own tastes [Right! And

that is _not_ the same thing as a script kiddie, damn it] -

and ordinary machine-code addicts. You will see in table 1

that there are a few vector tables, which hold addresses of

plotting routines, control codes etc. To start with, we'll

look at the control code vectors.

  Remember the window map and the parameter queue? Well,

this is where they come in. Throughout the following, the

byte numbers refer to bytes in the window map, numbered

0-44. When a character gets sent to be printed, it first

goes into the A register, then through the current channel

until it reaches the output routine.

  When it reaches the one in Windos, one of two things can

happen. If A is 32 or above, then an ASCII character is

output. However, if A is 31 or below, a fair amount of work

get done before anything happens. First the number of para-

meters it has are checked, by referring to the 32 byte

argument table, one byte for each control code.

  If this is zero, then the execution address is found by

doubling A, adding this to the base address of the control

code table, then, in effect, an indirect CALL to the appro-

priate routine occurs. However, if the number of parameters

is more than 0, then first the queue is initialised. This

is where all the parameters are going to be stored before

execution.

  Byte 30 becomes A, and byte 33 becomes the number of

parameters left to arrive before execution of the control

code. Then, on subsequent outputs, the parameters are

queued, from byte 15 onwards, and byte 33 decremented by 1.

When this reaches 0, then the code is executed. The code

routine uses (IX + 15) etc. to fetch the parameters, since

IX holds the base address of the current window map. Then

the whole show starts again when the next character comes

through. Confused?

  An example of how to alter one of these codes will show

the potential of altering these tables. The control code to

be changed is CHR$ 29. Normally, this transfers the screen

memory to the display memory, but usually these are one and

the same. So, to change it to a code which inverts the

whole screen, we first need a screen invert routine. See

listing 1.

  Now we need to change the appropriate vector in the

control code vector table. Its address is the Base Address,

which is 63947, plus two times the code number, so in this

case this is 63947 + (2*29) = 64005.

  Now using the normal Intel format, 64005 becomes the low

byte and 64006 the high byte of the routine address, in

this case 65300. The listing shows how it's all done. If we

wanted to add a routine which needed parameters then we

would have had to have changed the appropriate byte in the

argument number table.

  Providing you know Z-80 assembly language, altering

Windos is not at all difficult. At the start of Windos

there are four JP addresses. The first two you know, at

60000 and 60003, but 60006 is the entry point to Windos'

output routine. Just LD A,n and CALL 60006 within your

routines. Every single register is saved, except the I and

R registers. Obviously, this slows things down a bit, but

the peace of mind of knowing that no registers will be

corrupted is worth it.

  This vector can be altered so that before outputting a

character, something else can be done, like a beep, before

jumping back to the output routine. This might be useful to

someone. The fourth jump is to the copy screen routine.

This normally points to a COPY routine for the ZX Printer,

which incidentally copies all 192 pixel lines.

  However, this can be altered so that it jumps to a full-

size printer copy routine instead, and this will be useful

to those fortunate enough to have real printers. CHR$ 15

uses this, so any change to this would affect CHR$ 15.

  Determined hackers may like to look around the graphics

area of Windos. All the relevant addresses are to be found

in table 1.

  Hopefully, after reading this you will understand and

appreciate more fully the thinking behind Windos. I have

tried to make it as expandable as possible while still

leaving plenty of memory to work with.



You may be cursing the inadequacies of Sinclair Basic which

make many programs using Windos fairly bulky or tedious to

write. Here is a partial solution which will help Inter-

face 1 owners no end. In a mere 901 bytes I have added 23

commands to the Spectrum's vocabulary using the very well

documented method of extending the Basic, which will not be

described here.

  To keep the size of the Basic down, I used a list to hold

the addresses, the command name itself and the length of

the name, and I will show you how to add to this list at

the end of this article. This method makes adding commands

easy.

  First of all, to get the Basic going type in and save the

loader program. Then run it. If there are no errors, saving

will begin automatically on Microdrive cartridge. Then, to

initialise the Basic, type

        RANDOMIZE USR 59000

This must be typed every time you load in the Basic, or

want to re-initialise, possibly after a NEW. Now, making

sure Windos is in memory, type the following command line:

        *NEW:*INIT: OPEN #2,"p"

Windos has just been initialised. If the system crashes,

check your listing for errors that the checksuims [sic!]

were not able to detect. The full list of commands is as

follows:

  *PUT n,n,n... or *VDU n,n,n...: These are exactly the

same and simply output the character codes n directly

through the Windos output routine - this is necessary

because of the weird things that happen if you don't -

Careful of too many parameters, since the machine stack

is used to hold them.

  *PLOT mode + routine,x,y: This is exactly the same as

CHR$ 14, except it looks much better!

  *WPOKE byte,value: This is the window poke. Beware of

byte numbers over 44 - you will be poking another window

map.

  *CSIZE width,height: The same as the QL command, and the

same as CHR$ 28.

  *UP, *DOWN, *LEFT, *RIGHT: These four commands set the

direction of the large printing. Careful use can lead to

some very professional effects.

  *LARGE: Sets large characters mode.

  *NORMAL: Resets to either 32 or 64 column mode, depending

on what bit 6 of byte 12 is.

  *32COL: Sets the 32 column mode.

  *64COL: Sets the 64 column mode.

  *INIT: Initialises Windos, and interfaces it to the stan-

dard Spectrum system. Equivalent to RANDOMIZE USR 60000.

  *NEW: Resets all eight window maps. Equivalent to

RANDOMIZE USR 60003.

  *DOKE: address,contents: This is a two byte POKE, nothing

to do with Windos.

  *CALL address: Calls the machine-code routine at the

specified address.

  *RENUM start,increment: At last, a renumber command. No

GO TOs or GO SUBs done, and the parameters are 8 bit not

16. *RENUM 10,10 is valid, but *RENUM 1000,300 is not.

  *SCROLL byte 41,byte 42,repeat no: This is a very useful

command for setting up first the pixel scroll register and

then the attribute register. Then the actual scrolling

takes place. The registers remain altered after this

command, so *VDU 2,number would result in the same scroll

taking place.

  *WINDOW tlx,tly,brx,bry: This is the same as CHR$ 1, i.e.

it defines the window size.

  *CLS: This is obvious!

  *GCOL: This sets the graphics attribute.

[ *SCREEN: This command was not mentioned in the article,

but as can be seen from the demonstration, it selects the

active window, just as CHR$ 0.]

  Note: All of the commands must be preceded by a '*' but

thereafter, UPPER or lower case may be used in any order,

e.g. *Large is valid. Also, because of the ROM routine

NXTCHR, a command spaced out, e.g. * N o r m a l would be

accepted.

  The demonstration is a copy of the subroutine 'picture 2'

in the main demo of Windos, and shows how concise program-

ming may be achieved. Obviously, the *Plot, *VDU/*Put and

*WPoke commands will be used most often and these will cut

the size of your programs down a great deal.

  There now follows an explanation of the method used to

enable lots of commands to be added in a relatively small

amount of memory. There is a list at the end of the Basic

starting at 59707 and finishing at 59900 and it takes the

form:



  LIST DEFB length of following string

       DEFM "*command"

       DEFW address of syntax and runtime routine

       ...

       DEFB 0 terminates the list



Now, the final 0 which terminates the list is at address

59900. There are 99 bytes spare between here and the start

of Windos, plenty of room in which to place (a) new command

description(s), but make sure that the DEFB always contains

the full length of the string following, and that the list

is terminated by a 0. To get the base address of the cur-

rent window map into IX just use in assembly language,

        LD IX,(23728)

  Of course, you need a lot of information and a good

assembler before you can start creating the Basic of your

dreams. I would suggest that, money permitting, Hisoft's

Devpac and Dr Ian Logan's books, Spectrum Microdrive Book

and The Complete Spectrum ROM Disassembly are absolute

essentials, not forgetting the trusty old Spectrum Manual.

  If you run out of list space, the address which holds the

list pointer is 59019, but take care when changing this,

and transferring the old list to its new location, unless

of course you don't need the commands for Windos, or

Windos, in which case you have 5K of list space available.

  I hope that you will find a use for Windos and the Exten-

ded Basic, but to give you some ideas, why not write a 64

column word processor, or spreadsheet, or try your hand at

a text and graphics adventure, using the various graphics

routines, and remember that the Sinclair graphics routines

still work.

  Other ideas are a drawing program making use of the

alternative screen facility, or for the very ambitious, a

multi-tasking language in machine code making use of the

windows, which have completely separate identities.

___________________________________________________________



 Table 1. Useful addresses

 60000 Initialise entry point.

 60003 New entry point.

 60006 Output routine entry point.

 60009 Copy screen routine entry point.

 60012-60056 Initial data for the window maps.

 60057-60416 The window maps.

 60417-61184 The 64 column character set.

 61185-65281 WINDOS code and tables.

 63915-63946 Argument number table.

 63947-64010 The control code routine vectors.

 64622-64685 The plotting routine vectors.

 64054 The main PLOT subroutine used by other graphics

 routines. B=x, C=y.

 64328 The main DRAW subroutine used by other routines.

 B=x, C=y.

 64684 Equivalent to PLOT k,x,y. A=k, B=-x, C=y.

 23728 The base address of the current window map.