ZX Characters Trevor Terrell and Robert Simpson provide character forming advice to help Spectrum users define their own graphics. A display of the character set of the ZX Spectrum obtained using the three lines of Basic 10 FOR x=255 TO 32 STEP -1 15 PRINT CHR$ x; 25 NEXT x is shown in figure 1. From the character set summary in the Sinclair manual it may be noted that each character is assigned a unique code in the range 0 to 255. However some codes are not used, and others are used as control charac- ters. There are only 224 characters that can be displayed on the screen, - codes 32 to 255 inclusive - see range of x values in line 10 of the program. The characters having codes in the range 32 to 127 inclu- sive, are stored in a block of read only memory - ROM - between memory addresses 15616 to 16383 inclusive. Each character is defined by the contents of eight successive memory bytes. The space character - code 32 - is stored in the eight bytes in the address range 15616 to 15623, and successive codes are correspondingly stored in successive blocks of eight bytes. The eight bytes of any of these characters are stored in memory ranging from address 15616 + (8*(code-32)) to address 15623 + (8*(code-32)). For example, the + cha- racter - code 43 - is stored in the memory address range 15704 to 15711. You may Peek into these memory locations using 10 FOR x=0 TO 7 15 PRINT PEEK (15704+x) 20 NEXT x 25 STOP to obtain a display of the contents of each memory loca- tion. The values are Memory Displayed Memory address contents contents decimal binary 15704 0 00000000 15705 0 00000000 15706 8 00001000 15707 8 00001000 15708 62 00111110 15709 8 00001000 15710 8 00001000 15711 0 00000000 When the ZX Spectrum displays this + character it inter- prets the bit pattern such that 0 is paper and 1 is ink, and it is displayed using an eight-by-eight picture-element - pixel - grid, as shown in figure 2. Program 1 listed below may be used to display, for an inputted character code, the eight-by-eight bit character definition and the pixel grid definition boosted by a factor of 64. Character codes used with program 1 must be in the range 32 to 127. For example, when code 127 is inputted, the eight-by-eight binary bit pattern and corres- ponding eight-by-eight pixel grid definition, magnified by a factor of 64, for the © character is displayed, figure 3. [Actually, figure 3 is another character - see later in the article. There was no figure for ©. The program in question is on the TZX which goes with this article, under the name of "Grid".] Program 1 may be modified so that you can obtain a dis- play of the eight-by0-eight bit pattern and pixel-grid definition of a character entered via the keyboard. In this case the keyboard-entered character is converted to the corresponding code using the Inkey$ function. To do this you must change lines 5, 12 and 30 to 5 IF INKEY$="" THEN GO TO 5 12 PRINT AT 5,6;"The character is ";z$ 30 LET j=15615+8*(CODE z$-32)+x and insert the additional lines of program 3 PAUSE 10 10 LET z$=INKEY$ [The result is also on the TZX, as "Grid-inkey".] With the modified form of the program you cannot input all the characters with codes in the range 32 to 127 inclu- sive. For example the } character - code 125 - is excluded. But the modified form of the program does allow you to enter most characters directly without looking up the cha- racter codes in the character set summary. The characters stored in ROM cannot be changed, and therefore if you require to display additional characters, you may define them and store them in random access memory - RAM. It is possible to define up to 21 user-defined characters which require 168 bytes of memory, and the area of RAM reserved for them has the address range 32600 to 32767 in the 16K Spectrum and the address range 65368 to 65535 in the 48K Spectrum. The address of the first byte in memory of any of the user-defined graphic in characters may be determined by using the Usr finction in the form PRINT USR "user defined graphic symbol" and the computer outputs to the screen the appropriate address. For example PRINT USR "D" outputs the address 32624 for the 16K Spectrum, and 65392 for the 48K Spectrum. The area of RAM used for the user-defined characters is initialised, at switch-on, with data bytes which define the alphabetic characters A to U. The eight bytes of any of these characters are stored in the memory from address Addr+8*(code-144) to address Addr+7+8*(code-144), where code has a value in the range A to U respectively, as given in the character set summary. Addr is equal to 32600 for the 16K Spectrum and it is equal to 65368 for the 48K Spectrum. For example, in the 16K Spectrum, if you examine the content of the eight bytes of memory with addresses from 32672 to 32679 inclusive, you will see that the J character in binary form as Memory Memory address contents 32672 00000000 32673 00000010 32674 00000010 32675 00000010 32676 01000010 32677 01000010 32678 00111100 32679 00000000 A simple way of proving this to yourself is to run Program 1 with line 30 changed to 30 LET j=32599+8*(code-144)+x 16K or 30 LET j=65367+8*(code-144)+x 48K [or, for either, 30 LET j=USR "a"-1+8*(code-144)+x.] [The next line was corrupted - it showed a duplicate of a line further on in the article. My best guess at what was intended is:] [These default user-defined characters will] probably be of very little use to you because the same characters, A to U, exist as part of the character set stored in ROM. How- ever, because the user-defined characters are stored in RAM you can generate your own character by writing the appro- priate eight bytes into any of the 21 user-defined graphics memory areas. For example, to obtain a character of the form shown in figure 3 [which, this time, is correct] you must first define the bit pattern of each byte of the character. In this example we have: 00001000 00010100 00100010 01000001 00100010 00010100 00001000 00000000 Let us assume that this character is to be identified as the user-defined character D, then we must store the above bytes in memory addresses Addr to Addr+7, where Addr is equal to 32624 for the 16K Spectrum and it is equal to 65392 for the 48K Spectrum. We can do this using POKE Addr , BIN 00001000 POKE Addr+1, BIN 00010100 | | | | | | | | | | | | | | | | POKE Addr+7, BIN 00000000 To examine the binary bit pattern and pixel-grid definition of this defined character we may use program 1 with line 30 changed to 30 LET j=32599+8*(code-144)+x 16K Spectrum or 30 LET j=65367+8*(code-144)+x 48K Spectrum [or, vide supra.] To include a user-defined graphic character in a Basic program you enter graphics mode and access the character by pressing the appropriate alphabetic symbol key A to U. For the above example to display the diamond character at the centre of the screen you enter PRINT AT 10,15;"÷" Where ÷ is obtained by putting the computer in graphics mode and pressing the D key [and in the article was a diamond shape, but that character is not in the ANSI charset, so it can't be represented in this text file.] This character is used in the simple game shown in program 2, in which treasure has been randomly and invisibly buried in one character square of the screen display. The treasure is found by moving the character upwards or downwards by pressing the u or d key respectively, and left or right by pressing the L or R key, until the ÷ character is on the character square where the treasure has been buried. The number of moves taken to find the treasure is then dis- played. [This is on the TZX as "Game".] The eight-by-eight pixel grid pattern enables 2 ^ 8 ^ 8 (1.8446744E+19) different characters to be defined, however you can only have 21 user-defined characters. To create more characters you can use the Over 1 statement, which permits one character to overlay another character, but note that coincident inked pixels are written as Paper. ___________________________________________________________ COPY RETURN CLEAR DRAW CLS IF R ANDOMIZE SAVE RUN PLOT PRINT POK E NEXT PAUSE LET LIST LOAD INPUT GO SUB GO TO FOR REM DIM CONTIN UE BORDER NEW RESTORE DATA READ STOP LLIST LPRINT OUT OVER INVER SE BRIGHT FLASH PAPER INK CIRCLE BEEP VERIFY MERGE CLOSE # OPEN # ERASE MOVE FORMAT CAT DEF FN S TEP TO THEN LINE <>>=<= AND OR B IN NOT CHR$ STR$ USR IN PEEK ABS SGN SQR INT EXP LN ATN ACS ASN TAN COS SIN LEN VAL CODE VAL$ TA B AT ATTR SCREEN$ POINT FN PIINK EY$RNDUTSRQPONMLKJIHGFEDCBA€€€€€ €€€€€€€€€€ ©~}|{zyxwvutsrqponmlk jihgfedcba£_^]\[ZYXWVUTSRQPONMLK JIHGFEDCBA@?>=<;:9876543210/.-,+ *)('&%#"! Figure 1. [The € characters represent block graphics, which are absent from the ANSI character set - in fact, most of them aren't even in Unicode.] ___________________________________________________________ Figure 2. +---+---+---+---+---+---+---+---+ | | | | | | | | | +---+---+---+---+---+---+---+---+ | | | | | | | | | +---+---+---+---+---+---+---+---+ | | | | |###| | | | +---+---+---+---+---+---+---+---+ | | | | |###| | | | +---+---+---+---+---+---+---+---+ | | |###|###|###|###|###| | +---+---+---+---+---+---+---+---+ | | | | |###| | | | +---+---+---+---+---+---+---+---+ | | | | |###| | | | +---+---+---+---+---+---+---+---+ | | | | | | | | | +---+---+---+---+---+---+---+---+ ___________________________________________________________ Figure 3. +---+---+---+---+---+---+---+---+ | | | | |###| | | | +---+---+---+---+---+---+---+---+ | | | |###| |###| | | +---+---+---+---+---+---+---+---+ | | |###| | | |###| | +---+---+---+---+---+---+---+---+ | |###| | | | | |###| +---+---+---+---+---+---+---+---+ | | |###| | | |###| | +---+---+---+---+---+---+---+---+ | | | |###| |###| | | +---+---+---+---+---+---+---+---+ | | | | |###| | | | +---+---+---+---+---+---+---+---+ | | | | | | | | | +---+---+---+---+---+---+---+---+