BASIC MACHINE CODE FOR THE ZX81

Discussion about ZX80 / ZX81 Software
User avatar
XavSnap
Posts: 1719
Joined: Sat May 10, 2008 4:23 pm
Location: 'Zx81 France' Fb group.

Re: BASIC MACHINE CODE FOR THE ZX81

Post by XavSnap »

Thanks David.
Xavier ...on the Facebook groupe : "Zx81 France"(fr)
David G
Posts: 313
Joined: Thu Jul 17, 2014 7:58 am
Location: 21 North, 156 West

Chapter 3 - BASIC MACHINE CODE

Post by David G »

And now! A machine/code to turn text into inverse

Ch. 3 - BASIC MACHINE CODE FOR THE ZX81

BASIC MACHINE CODE FOR THE ZX81 A beginner's series

CHAPTER 3
* Type-in: the "play by ear" utility program
* Where to Put the Program
* What we Need
** to successfully store machine code in the BASIC program
** to enter and proofread it
** to have it run successfully
** to be able to modify and extend the code later

from SyncWare News Volume 2 Number 3 Jan.-Feb. '85 pages 21-23
BASIL'S COMPENDIUM

John (Basil) Wentworth
1413 Elliston Drive
Bloomington, In. 47401

Where to Put the Program

This chapter will list some requirements for the place where we will put the machine code, and will show you how to find a memory location that meets those requirements. But first, our "play by ear" utility program.

The "rough draft" 1 REM line and the proofreading program are shown in Figures 3-1 and 3-2, respectively

Code: Select all

FIGURE 3-1. 1 REM for BLACKTOP -FIRST DRAFT-

HOW IT LOOKS

   1 REM . CHR$ .E'RNDY.WUyC.Y..."4.TAN

HOW IT IS DONE

   1 REM (GR 1) CHR$ (GR 2) E (SHIFT SPACE) RND Y . W 7 (INVERSE Y) C . Y (INVERSE SPACE) (GR Y) . " 4 . TAN
Fig 3-1 REM for BLACKTOP -FIRST DRAFT-
Fig 3-1 REM for BLACKTOP -FIRST DRAFT-
There is a typo in that listing. It should be like this:
Fig 3-1 corrected.png
Fig 3-1 corrected.png (4.27 KiB) Viewed 558 times

Code: Select all

FIGURE 3-2. THE RUDIMENTARY LOADER

1000 REM PROOFREADING THE PROGRAM
1020 FOR F=16514 TO 16534
1030 PRINT F;TAB 6;PEEK F;TAB 10 
;CHR$ PEEK F
1040 NEXT F
1050 STOP
1500 REM POKING THE VACANCIES
1510 INPUT A
1520 PRINT A; TAB 6;
1525 LET A=A+16500
1530 INPUT B
1540 POKE A,B
1550 PRINT PEEK A
1560 GOTO 1510
and the readout for proofreading is in Figure 3-3.
FIGURE 3-3. PROOFREADING THE <br />PROVISIONAL 1 REM
FIGURE 3-3. PROOFREADING THE
PROVISIONAL 1 REM
When I typed it in, the typo become apparent
Fig 3-3 actual
Fig 3-3 actual

Next, the article talks about POKEing the vacancies. To do that:
* GOTO 1500
* When the L prompt appears, type in the first number and press NEWLINE/ENTER
* Type the second number and NEWLINE
* when done, Enter a letter (e.g. X) to break out of the loop
After you POKE the vacancies, according to Figure 3-4,

Code: Select all

FIGURE 3-4. POKING THE VACANCIES 

   21   117 
   26   252 
   30   119 
   33   242
When that is done, RUN to proofread again
the final proofreading should checkout with Figure 3-5.
Fig 3-5 Proofreadeing the Final 1 REM.jpg
Again, after typing it out, it looks different. CHR$ 12 is the Pound Sterling sign, not the apostrophe ('). I cannot think of how they generated the screenshot in the newsletter, there is no apostrophe on the ZX81! Is there?
I know that's awfully fast, but it's just a repeat of what you have done in the previous chapters. If you're still having a problem with this procedure, then get in touch with me directly. I'll be glad to be of service.

When you have the final 1 REM line in place, add the following two lines to your program:

Code: Select all

1000 PRINT AT 10,3;"BASIL LOVES 
JOCELYN"
1010 RAND USR 16514
Then, GOTO 1000 and watch the fun.
It works!

strangely enough as the code is:

Code: Select all

DEC   BC
JR    NZ,-14
DEC BC doesn't update the Z flag, yet it works. How is it able to work successfully?
And now the lesson.

What We Need

Where in ram are we going to store our machine code? We must satisfy two conditions.

1. The machine code routine must not
interfere with the normal running of the
computer itself.

2. The running of the computer must not
interfere with the machine code.

Live and let live. For convenience, we'd like to impose a few more conditions, including:

3. The program should be easily entered,
proofread and edited.

4. It should be possible to SAVE the
program.

5. It should be expandable. We should be
able to add more subroutines as they become
necessary.

For the moment, let's shelve number 5, and concentrate on the first four conditions. We'll get back to number 5 later on.

Recall that the USR command must specify the starting address of the machine code routine. Much as GOTO and GOSUB have to be followed by a number (or an expression which the computer can evaluate as a number), so does the USR command require a number or expression equal to a number. This means that we'll have to know (or compute) the address of the first byte of machine code every time we want to invoke it.

"What do you mean, every time?" I hear you cry. "Doesn't my code stay put?" Well, that depends. Let's try a little experiment.

Suppose your program consists of a line of 27's. It never will, of course, but 27 is the code of a character that's easy to spot (pardon the pun; try PRINT CHR$ 27). Let's put a line of 27's into the computer. Try this:

Code: Select all

  10......
OOPS! The computer won't accept it. So, let's give in to the computer on this point, and use up an extra byte. Try:

Code: Select all

  10 REM ......
If you're really vindictive, POKE 16513,27. GOTCHA! There's that line that the computer wouldn't accept. Don't ever try to EDIT that line. It's much easier to include the REM. It takes up only one extra byte, doesn't get in the way and makes things much easier all around (like salvaging the program if you ever inadvertently get the line down into the edit position).

So, now you have,

Code: Select all

  10 REM ......
Let's see what the memory contents look like. Use the program of Figure 3-6.

Code: Select all

FIGURE 3-6. WHERE ARE THE 27'S?

  10 REM ......
 100 FOR M=16509 TO 16530
 110 PRINT M;"  ";PEEK M
 120 NEXT M
See those 27's starting at 16514? Now add another line:

Code: Select all

   1 REM
Run the program again. The 27's have moved up to memory locations starting at 16520! Change line 1 to:

Code: Select all

   1 REM ABC
Run the program again and notice that the 27's have moved once again. Well, it's going to be pretty hard to find a starting address that keeps moving around, but don't give up.

Let's try something else. Delete line 1 and Run the program again. Not surprisingly, the 27's are back at 16514. Now, change the number of the REM from 10 to 1. Run it again. Notice that there is no change in the location of the 27's. Now, add:

Code: Select all

  10 REM ABC
Run the program again and notice that there is still no change in position of the 27's.

And here's the conclusion that we draw from this maneuvering:

The address of the first byte in the
first statement of the program does not
depend on the line number of that
statement, nor is it changed by the
addition of any program lines numbered
higher than the first line.

So, what are you to do? Put your machine code in a 1 REM, and the first byte after the REM will always have the same address, namely 16514, unless of course, you put a 0 REM in front of it. (We're going to show you how and why to use line 0 one of these days.)

Ok, now let's do something stupid, just to demonstrate a point. Don't worry, it won't do any harm, other than to crash (guaranteed) the program in memory. So, if you have any program material that you care about, SAVE it now, before continuing.

Ready? Enter the line

Code: Select all

   1 REM
and then POKE 16514,27. Now, LIST the program.

Don't say that I didn't warn you. It's an interesting picture, but it's not the sort of program you want to use every day. You can't even get rid of it without turning off the computer.

What happened? Well, the computer was using 16514 for one of those "housekeeping" bytes (end of line marker), and was thrown off balance when you asked it to something else with that byte.

What we have to do is lay claim to some space for our machine code, and to do it before the computer starts using that space for its own purposes. The way we do this Is to fill all the bytes we need after the REM with characters of our own choosing. There are various ways to accomplish this (*see SWN 2/2, Memotext in ram or the article by Chuck Peterson on generating a big REM).

Enough preliminaries. Next time, we'll actually write a real (though simple) program in machine code.
END OF CHAPTER 3

* The article "Memotext in RAM" was by Fred Nachbaur of British Columbia.

Fred discusses about how to "Generate a REM..." meaning a long REM
* use a REM generator utility
* or ... Fred's Easy Way
If you had to type in an [eight thousand] 8K REM statement a character at a time, it would probably be enough to make you give up computing for good.

Fortunately, you can use a couple tricks to help matters immeasurably...
David G
Posts: 313
Joined: Thu Jul 17, 2014 7:58 am
Location: 21 North, 156 West

Re: Chapter 3 - BASIC MACHINE CODE

Post by David G »

And the ZX81 Type-ins for Chapter 3

BLACKTOP_Provisional_2K.p
For working through the chapter Fig 3-2 and 3-3
(1.13 KiB) Downloaded 12 times
Attachments
BLACKTOP_Final_1K.p
M/C demo that inverts text
(232 Bytes) Downloaded 14 times
User avatar
mrtinb
Posts: 1709
Joined: Fri Nov 06, 2015 5:44 pm
Location: Denmark
Contact:

Re: Chapter 3 - BASIC MACHINE CODE

Post by mrtinb »

David G wrote: Wed Aug 03, 2022 11:45 pm Again, after typing it out, it looks different. CHR$ 12 is the Pound Sterling sign, not the apostrophe ('). I cannot think of how they generated the screenshot in the newsletter, there is no apostrophe on the ZX81! Is there?
Maybe the American user thought a pound sign was useless to him, but really needed the apostrophe, to write American (where it's quite common). Maybe the author of the article just created an EPROM replacement for the ROM, where this single char was changed. Then it would be an apostrophe both on screen and on print. Maybe the EPROM replacement was well known in the user group, so it was accepted in their newsletter. I'm just speculating.
Martin
https://zx.rtin.be
ZX81, Lambda 8300, Commodore 64, Mac G4 Cube
David G
Posts: 313
Joined: Thu Jul 17, 2014 7:58 am
Location: 21 North, 156 West

Re: Chapter 3 - BASIC MACHINE CODE

Post by David G »

That thought had crossed my mind, but I immediately discounted it as crazy
mrtinb wrote: Fri Aug 05, 2022 9:31 amMaybe the author of the article just created an EPROM replacement for the ROM, where this single char was changed. Then it would be an apostrophe both on screen and on print.

But this speculation makes it seem plausible. Maybe someone knows if they used custom EPROMs back in 1984
Maybe the EPROM replacement was well known in the user group, so it was accepted in their newsletter. I'm just speculating.
David G
Posts: 313
Joined: Thu Jul 17, 2014 7:58 am
Location: 21 North, 156 West

Chapter 4 - BASIC MACHINE CODE

Post by David G »

BASIC MACHINE CODE FOR THE ZX81 A beginner's series

Chapter 4 - BASIC MACHINE CODE

This chapter I found difficult to understand. One problem is the figures are scattered around the text, not really Basil's fault but more of the newsletter layout. So here I've re-arranged the Figures in the text to flow better

The other problem with this chapter is Basil chose a learn-by-doing style. So I really had to work at these to understand them. In a previous thread we had trouble understanding the main type-in program from this chapter:
[Zx81:Type-Ins] "SyncWare News" campaign...

"BASIL's Compendium"

Syncware Newsv2.4

Not sure what it is... Scan the BASIC room to find a REM, scan a "<" in it then a ">" and destroy the MC h eader!
Well here it is in all it's glory (and within context of the full chapter). The program does work as described. With perseverance I have learned a few new tricks of m/c for the ZX81

CHAPTER 4 from SyncWare News Volume 2 Number 4 Mar.-Apr. '85 pages 15-17
BASIL'S COMPENDIUM

John (Basil) Wentworth
1413 Elliston Drive
Bloomington, In. 47401

LET A= ...

This installment will teach you how to enter an actual program in machine code. But first, a "fun" program - a rather lengthy one, this time.

You'll notice that we have changed the loader program again, as shown in Figure 4-1. After the experience you've had in the first three chapters, you should be able to combine the operations of POKEing the vacancies and proofreading the program.

The program we're giving you this time will enable you to delete blocks of program material in a single operation. All you do is mark the beginning of the section to be deleted with

Code: Select all

  N1 REM >
and the end with

Code: Select all

  N2 REM <
where N1 and N2 are line numbers. Then RAND USR 16514 will lump all the material between the markers into one line which can be deleted at one go.

The rough draft of the 1 REM statement is shown in Figure 4-2, and the final listing in Figure 4-3. While you're proofreading the statement, the display will stop for you wherever you have included a period, and wait for you to INPUT the final number (which may, of course, actually be 27). When the screen is full, just CONTINUE to get the following bytes.

As before, the mnemonics, which are included for the Information of more experienced programmers, will not appear on your listing.

One word of caution: DON'T use this program in the SLOW mode. It's very likely to crash if you do, since this program pre-empts some of the the computer's capabilities that are required to make the SLOW mode work.

Code: Select all

FIGURE 4-1.  LOADER/PROOFREAD PROGRAM

1000 LET F=16513
1010 LET F=F+1
1020 PRINT F;" ";
1030 IF PEEK F<>27 THEN GOTO 1060
1040 INPUT A
1050 POKE F,A
1060 PRINT PEEK F,CHR$ PEEK F
1065 IF PEEK F=113 THEN STOP
1070 GOTO 1010
FIGURE 4-2 ROUGH DRAFT OF 1 REM
FIGURE 4-2 ROUGH DRAFT OF 1 REM

Code: Select all

FIGURE 4-2. ROUGH DRAFT OF 1 REM

   1 REM '<>5}RNDYuW<>7<>û TAB ÁR
ND<>û¡COS YREM <>û¬TAB ³RNDY><>û²TA
B ãRND<>FAST AT W<>û²TAB ³RND<>
 FAST LPRINT GOSUB PI777VAL <>LPRINT
 <>t¤<>u¦TAN '

HOW IT LOOKS 

   1 REM <> 5 , RND Y . W <> 7  
<> y (SPACE) TAB (GR G) RND <> y
(GR 1) COS Y , <> y (GR 5) TAB  
(GR Y) RND Y > <> y (GR T) TAB c
TAB (GR Y) RND <> FAST LPRINT , 
PI 7 7 7 VAL <> LPRINT <> .    
 (GR 4) <> . (GR U) TAN

HOW IT IS DONE 
FIGURE 4-3 FINAL LISTING OF 1 REM
FIGURE 4-3 FINAL LISTING OF 1 REM

Code: Select all

FIGURE 4-3. FINAL LISTING OF 1 REM
16514 221 <>           LD IX,
16515 33  5             16509
15516 125 ?
16517 64  RND
16518 62  Y            LD  A
16519 117 ?             117
16520 60  W            INC  A
16521 221 <>           INC IX
16522 35  7
16523 221 <>           CP (IX+0)
16524 190 y
16525 0
16526 194 TAB          JP NZ,
16527 137 [BLACK/GRAY BARS]16521
16528 64  RND
16529 221 <>           CP(IX+1)
16530 190 y
16531 1
16532 200 COS          RET Z
16533 62  Y            LD A,
16534 234 REM           234
16535 221 <>           CP(IX+5)
16536 190 y
16537 5   |
16538 194 TAB          JP NZ,
16539 134 [\ graphic]   16518
16540 64  RND
16541 62  Y            LD A,
16542 18  >             18
16543 221 <>           CP(IX+8)
16544 190 y
16545 6   /
16546 194 TAB          JP NZ,
16547 168 c             16552
16548 64  RND
16549 221 <>           PUSH IX
16550 229 FAST
16551 193 AT           POP BC
16552 60  W            INC  A
16553 221 <>           CP(IX+6)
16554 190 y
16555 6   [/ graphic]
16556 194 TAB          JP NZ,
16557 134 [\ graphic]  16518
16558 64  RND
16559 221 <>           PUSH IX
16560 229 FAST
16561 225 LPRINT       POP  HL
16562 237 GOSUB        SBC HL,BC
16563 66  PI
16564 35  7            INC HL
15555 35  7            INC HL
16566 35  7            INC HL
16567 197 VAL          PUSH BC
16568 221 <>           POP IX
16569 225 LPRINT
16578 221 <>           LD(IX+4),H
16571 116 ?
16572 4   [SW DOT]
16573 221 <>           LD(IX+3),L
16574 117 ?
16575 3   [NORTH BAR]
16576 201 TAN          RET
Now back to lessons.
To be continued ...
Attachments
FIG_4-3_1_REM_(MERGE_LINES).p
(407 Bytes) Downloaded 10 times
David G
Posts: 313
Joined: Thu Jul 17, 2014 7:58 am
Location: 21 North, 156 West

Re: Chapter 4 - BASIC MACHINE CODE

Post by David G »

This program "1 REM" is an odd one. I named it "MERGE LINES" because takes some of your program lines, which you have marked, it bunches them together under one line number. Which you can then delete all at once. Interesting, but is it useful? I'm guessing Basil will use this as a stepping stone to something further advanced ...
David G
Posts: 313
Joined: Thu Jul 17, 2014 7:58 am
Location: 21 North, 156 West

Re: Chapter 4 - BASIC MACHINE CODE (page 16)

Post by David G »

Re: Chapter 4 - BASIC MACHINE CODE (page 16)
BASIC MACHINE CODE FOR THE ZX81 A beginner's series

CHAPTER 4 continued from SyncWare News Volume 2 Number 4 Mar.-Apr. '85 page 16
Now back to lessons.

You've carved out some turf for yourself - so what do you do with it? You may remember an earlier declaration that the output of a machine language routine is what the computer calls BC; i.e.

Code: Select all

    C+256*B
So how do we make B and C reflect any value that we can use?

For the moment, think of B and C as simple variables. What we want to do is to assign values to them. The Z80 machine code instructions that we want are:

LET B=m is 6,m
and LET C=n is 14,n

And RETURN, which we must not forget, is 201.

Note that the instructions (6,14) and the data (m,n) are mixed into the program. There is no difference between them, as far as mortal eye can see. The computer knows, though, from the context.

If it receives an instruction of 6 or 14, for instance, it'll interpret the next byte as data, whether you mean it to or not.
Now we're ready for our first, very simple, program. After reserving at least 5 nulls in a 1 REM statement (see the previous chapter, if you've forgotten how), POKE in the sequence shown in

Code: Select all

FIGURE 4-4. SETTING B AND C

                 MEANING
   POKE 16514,6    LET B=
   POKE 16515,1     1
   POKE 16516,14   LET C=
   POKE 16517,0     0
  [POKE 16518,201  RET]
   PRINT USR 16514 PRINT 256*B+C
Figure 4-4. Give the command PRINT (not RAND) USR 16514, and there's your answer: 256.

Now another one, as in Figure 4-5. Note that you don't have to delete the previous material - the new entries will overwrite the old bytes.

Before printing the output, what do you expect it to be? Enter PRINT USR 16514, and check your prediction.

Code: Select all

FIGURE 4-5. SETTING B AND C

                 MEANING
   POKE 16514,6    LET B=
   POKE 16515,0     0
   POKE 16516,14   LET C=
   POKE 16517,1     1
  [POKE 16518,201  RET]
   PRINT USR 16514 PRINT 256*B+C
FIG_4-4_1K.p
Figure 4-4 Setting B and C
(483 Bytes) Downloaded 5 times

It should have been

Code: Select all

   256*B(=0)+C(=1)=1
TO BE CONTINUED...
David G
Posts: 313
Joined: Thu Jul 17, 2014 7:58 am
Location: 21 North, 156 West

Re: Chapter 4 - BASIC MACHINE CODE (page 16 continued)

Post by David G »

BASIC MACHINE CODE FOR THE ZX81 A beginner's series

CHAPTER 4 continued from SyncWare News Volume 2 Number 4 Mar.-Apr. '85 page 16
But all this POKEing is getting to be a bit tedious, isn't it? (You'll notice that I stalwartly resist the temptation to make a pun on poking fun.) Plus the danger of losing your place

Code: Select all

FIGURE 4-6. A SIMPLE LOADER

  1 REM ...........
1000 FOR M=16514 TO 17000
1010 PRINT M; " ",
1020 INPUT A
1030 POKE M,A
1040 PRINT PEEK M
1050 NEXT M

**** DON/T WORRY; WE WON/T USE ALL 457 BYTES. SEE THE TEXT ON THIS POINT.
and skipping a byte. With the further disadvantage that you can't proofread the program.

It has probably already occurred to you that this is an appropriate place to use a loop. So let's build a very simple loader program, like the one in Figure 4-6.

To try it out, let's go through the two programs we wrote above. First, RUN the program of Figure 4-6, and then INPUT in succession:

Code: Select all

   6,1,14,0,201,Z
The Z, or any other letter that the computer will not interpret as a number (NOT M or A, which have already been assigned values by the computer), will cause the program to STOP, with an error report of 2/1120, meaning "I don't recognize that as a defined value for A". And that's the way you get out of the loop without having to go through all 487 INPUTS.

Code: Select all

FIGURE 4-7. PROOFREADING

16514 6
16515 1
16516 14
16517 0
16518 201
Now you have the contents of the whole 1 REM statement displayed on the screen, as shown in Figure 4-7, so you can proofread it - including making sure that it includes the all-important 201, for RETURN. If it's the way you want it, PRINT USR 16514. And there's the 256, just as before.

If you do find an error in the program, POKE in the proper value, as, for instance, POKE 16516,14. If your program is to be more than 22 bytes long, use CONTINUE when the screen is filled. Or you can add 1005 SCROLL, if you prefer.

If you want to proofread a program after POKEing in a correction, use the following procedure:

1. Disable lines 1030 and 1040. You can do this either by deleting the lines or by inserting a REM at the beginning of each line, right after the line number.

2. If you have included a SCROLL, either disable it or put the computer into SLOW mode.

3. RUN the program.
David G
Posts: 313
Joined: Thu Jul 17, 2014 7:58 am
Location: 21 North, 156 West

Chapter 4 - BASIC MACHINE CODE: El Minimo

Post by David G »

BASIC MACHINE CODE FOR THE ZX81 A beginner's series

CHAPTER 4 conclusion from SyncWare News page 17
El Minimo

The following experiment will help you to understand what goes on when you store your machine code in REM. It'll also give you a clue to the way we've been writing those "fun" programs at the head of each chapter.

I call this loading technique "EL MINIMO" because it's just about the most compact program loading system possible.

Enter

Code: Select all

  1 REM (Gr T) (space) : (Grl) TAN
If you'll look at the listing of the character set in your manual, or if you'll check each character by PRINT CODE "...", you'll find that the codes of these respective characters are, to nobody's surprise, 6,0,14,1, and 201.

This is in fact the series of numbers that has been entered into memory, starting at 16514.

Try PRINT USR 16514 for this program, and again after you have exchanged the places of the 0 and the 1.

You may find it more convenient to use this technique for building up your 1 REM statement, as we have been doing in the "fun" programs. If so, you'll find it useful to add a little more information to your ZX81 manual. You'll notice that the table of the character set as listed in the manual shows the graphics symbols for Codes 1-10 and 128-138 (with an error in the entry for 135, at least in my copy). However, it's not too easy to find these symbols on the keyboard, so I wrote into the manual the keystroke needed to produce each of these symbols. They're listed in Figure 4-8.
FIG 4-8 KEYING THE GRAPHICS SYMBOLS
FIG 4-8 KEYING THE GRAPHICS SYMBOLS

Incidentally, if you want to enter keywords, like RUN (CHR$ 247), REM (234), FOR (235), and the like directly from the keyboard, you can do it by preceding the character with THEN, which conditions the ZX81 to interpret the next keystroke as a command. You'll have to delete the THENs from the final program, of course.

And that's it for now. There will be more.
Here's my take on how to enter the special characters:
* To enter graphics mode: press GRAPHICS (which is SHIFT-9)
* To enter "CODE 1" from the chart (where it says "GR 1"), press SHIFT-1
* In the brackets is my description of the graphics symbol (in SyncWare it uses a picture of the symbol)

Code: Select all

FIGURE 4-8. KEYING THE GRAPHICS SYMBOLS

CODE CHR$               KEYSTROKE
0  ' '                    SPACE
1  [NW DOT]               GR 1
2  [NE DOT]               GR 2
3  [NORTH BAR]            GR 7
4  [SW DOT]               GR 4
5  [WEST BAR]             GR 5
6  [SLASH]                GR T
7  [INVERSE SW DOT]       GR E
8  [GRAY SQUARE]          GR A
9  [GRAY SOUTH BAR]       GR D
10  [GRAY NORTH BAR]      GR S
128 [BLACK SQUARE]        INV SPACE
129 [INVERSE NW DOT]      GR Q
130 [INVERSE NE DOT]      GR W
131 [SOUTH BAR]           GR 6
132 [INVERSE SW DOT]      GR R
133 [EAST BAR]            GR 8
134 [BACKSLASH]           GR Y
135 [SE DOT]              GR 3
136 [INVERSE GRAY SQUARE] GR H
137 [BLACK/GRAY BARS]     GR G
138 [GRAY/BLACK BARS]     GR F
Post Reply