Books Issue 26 Contents Mind Games

helpline



Andrew Hewson

Difficulties with odd characters

Andrew Hewson intrigued by printer buffer

ONE OF the difficulties of writing a regular column on a popular subject is that if I make a mistake my letterbox reverberates as correspondents from far and near hasten to correct my error and I have to hide from a postman weighed down with mail. So will all those readers who have been POKEing their Spectrums to determine whether they have Issue 2 or Issue 3 machines according to my advice in the January issue of Sinclair User please cease writing to ask what I was talking about? What I wrote was incorrect and I apologise for the confusion.

I was attempting to describe the difference between the most recent form of the Spectrum, the Issue 3 machine, and its predecessor in terms of a subtle difference in their response to the IN command. In fact, a much more straightforward method is to look through the slot in the rear where the edge connector is situated. In the latest models an aluminium heatsink about 12cm long and 2cm wide is clearly visible situated above the printed circuit board. That heatsink is absent from Issue 2 machines.

Incidentally, the 48K form of the first version of the Spectrum, Issue 1, made use of the space now occupied by the heatsink for a 32K memory board. In the re-design which resulted in Issue 2, sufficient space was found on the main board for the extra memory.

Doreen Fusco has brought an unusual effect to my attention. She writes: I was poking about in the printer buffer of my ZX-81 when I discovered that if I altered the contents of the final byte my printer produced double-height characters. I knew this could be done in machine code but I was surprised to discover it was possible from Basic, too. What is happening?

I was intrigued by the letter and I soon discovered that a simple ZX-81 routine of the form:

10 POKE 16476,0
20 LPRINT "DOUBLE HEIGHT"

would produce double-height printer output.

The reason is that the relevant ROM routine uses the newline character - CODE 118 - which is held at address 16476 to indicate the end of the information to be posted to the printer. The routine scans through the printer buffer eight times, working out, with the aid of the character table, the form of the top eighth of each character, then the second eighth, then the third eighth and so on.


'Unfortunately the routine picks up other information'

In between each line of eighths the routine sends a signal to the printer causing it to slow the rate at which the printer motor turns. When the routine has gathered all the information for the next line of eighths, a second signal is sent, causing the motor to increase speed again. It is that staccato effect which causes the printer to sound like an asthmatic old man.

Changing the contents of 16476 causes the ROM routine to omit, among other things, to send the slow-down signal to the printer, hence more paper is wound past the printing head in between eighths, giving the appearance of double-height characters. Unfortunately in the absence of the newline character, the routine picks up other extraneous information which results in nonsense characters also appearing on the output. I can see no way round the difficulty and I would be interested to hear from anyone who can. In the meantime, however, there appears to be no way of putting the effect to good use.

John Heritage is clearly using his computer for financial calculations. He asks: How can I reduce the answer to a calculation to two decimal places and how can I ensure that the decimal points in a vertical line of figures always lie below one another?

As is so often the case, the answer to each of the questions is straightforward, once the general principle is understood. In the first case the INT function, which rounds down a decimal number to the nearest whole number, can be used to round down to two decimal places, simply by multiplying beforehand by 100 and dividing by the same number afterwards.

In the second case, the number can be converted to a string using the STR$ function and then the string can be searched to identify the position of the decimal point. A simple calculation will then ensure that the number is PRINTed with the decimal point in the correct column.

The program in table one shows those principles in practice. Notice that the variable I is increased by five in the equivalent of the third decimal place in line 30 to counteract the effect of the INT function rounding downwards. Thus, for example, a value of 3.648 is rounded up, correctly, to 3.65 by that line, whereas 3.642 is rounded down to 3.64.

10  LET D$="."
20  INPUT I
30  LET I=INT(100*I + 0.5) / 100
40  LET Z$ = STR$I
50  FOR J = 1 TO LEN Z$
60  IF Z$(J) = D$ THEN GO TO 80
70  NEXT J
80  PRINT AT 21,16 - J;Z$
90  INPUT "33 spaces";
100 GO TO 20

Table 1. A Spectrum routine which rounds
the contents of I to two decimal places and
PRINTS the result with decimal point in
column 16. To adapt the routine for the ZX-81,
change line 90 to read 90 SCROLL.

Incidentally, a number should be rounded only immediately before it is PRINTed and not at intermediate stages of a calculation. If the number is to be used on a subsequent occasion the unrounded form should be stored in a separate variable. Alistair Baird raises an interesting topic. He writes: I wish to store some information above RAMTOP on my 48K Spectrum and to clear out the user-defined graphics, I entered CLEAR 65535: NEW: CLEAR 60000: NEW. Imagine my surprise when I found that the lowest 104 bytes were set to zero but the remaining 64 bytes 65472 to 65535 - still contained non-zero values. Can you explain?

Computer memory is rather like a blackboard; it is of limited size and to accommodate new information it is usually necessary to erase information which has become redundant. There are two principal methods which a computer can use to update its blackboard. Either it can erase information as soon as it has become redundant and move all current information into one block, so as to accumulate all spare memory in one place, or it can ignore the problem and over-write redundant information the next time it wants to use the space.

The first method has the advantage of minimising the total amount of memory required but the disadvantage that current information is forever being shuffled around in memory - in the jargon of the computer trade that activity is called garbage collection. The second method has the advantage of speed but the disadvantage that unless the software keeps a careful note of the situation, portions of memory can become clogged with redundant information.

The ZX-81 and the Spectrum use the first method to an obsessive degree, fussing around like a nervous squirrel hoarding memory at every opportunity. As a result, Basic programs tend to run slower than on other machines.

In the case of Baird's problem, the Spectrum omits to re-set a portion of memory which it will not be accessing in future. The two instructions CLEAR 65535 : NEW delete the user-defined graphics area as required but the machine then establishes its stack at 65535 working downwards; the machine stack is used to hold the return addresses of ROM routines being executed and other vital but temporary information.

Entering CLEAR 60000: NEW subsequently moves down the stack but draws a frozen copy of it in the 64 bytes at 65472 to 65535, as Baird discovered. The only solution is for the user to delete the data, a fairly simple matter using either a Basic or a machine code routine.

Wim Gulpen of the Netherlands brings an international flavour to the column. He asks: Can you provide a Spectrum machine code routine to scroll the top eight lines of the display only? I have written a Basic routine but it is too slow.

To answer the question I have adapted two routines which appear in 40 Best Machine Code Routines for the ZX Spectrum, a book I wrote with John Hardman. The routines are listed together in table two. The first part scrolls the display file and the remainder scrolls the attributes. The eighth line of the display is cleared and its attributes set to the value held in the system variable ATTR P.

Hexadecimal AssemblerComment
11 00 40 ld de,16384Top lhs of first line
21 20 40 ld h1,16416Top lhs of secod line
06 08 ld 6,8Number of lines
C5NXTBLKpush beSave number of lines
01 E0 00 ld bc,2247 lines each 32 characters long
ED B0 ldirCopy (hl) to (de)
06 20 ld 6,32Length of last line
3E 00 ld a,0Clear a register
12LASTLINld (de),aClear last line
13 inc de 
23 inc hl 
10 FB djnz LASTLIN 
C1 pop beRecover number of lines
10 EE djnz NXTBLKDecrement and jump if not zero
01 E0 00 ld bc,2247 lines each 32 characters long
11 00 58 ld,de,22528First line of attributes file
21 20 58 ld h1,22560Second line of attributes file
ED B0 ldir Copy(hl) to (de)
3A 8D 5C ld a,(23693)Value of ATTR P to a register
06 20 ld b,32Length of last line
12LASTATTR  ld (de),aClear last line
13 inc de 
10 PC djnz LASTATTRRepeat if not zero
C9 retReturn
Table 2. A Spectrum program to scroll the top eight lines of the screen display.

The routines can be loaded into the Spectrum printer buffer using an assembler or the Basic hexadecimal loader program listed in table three. Call the routines by entering:

RANDOMIZE USR 23296
10 FOR I = 33296 TO 23551
20 INPUT Z$
30 IF Z$ = "S" THEN STOP
40 PRINT Z$
50 LET Z$(1) = CHR$(CODE Z$(1) - 7*(CODE Z$(1)>57))
60 LET Z$(2) = CHR$(CODE Z$(2) - 7*(CODE Z$(2)>57))
70 POKE I,16*CODEZ$(1) + CODEZ$(2) - 816
80 NEXT I

Table 3. A Spectrum program to load pairs of
hexadecimal codes into the printer buffer.


Books Issue 26 Contents Mind Games

Sinclair User
May 1984