The GMC-4 - a 4-bit microcomputer

overview

The GMC-4 is the only 4-bit microcomputer to be mass-produced in the last 30 years. It was produced by Gakken - a Japanese publisher - as a mook (magazine-book?) that included the almost assembled GMC-4. You connect a speaker, a battery pack, a sticky key-pad and your are off.

It is slightly baffling to look at and all non-geeks I have shown it to have struggled to grasp the point of it. To be fair, it is pretty hard to justify its existence outside of the realm of fun in the problem-solving department. Its real purpose is to provide an easy way to play with and learn about assembly language and the bare-bones of computing. The pricinples of this little computer pretty much hold for all modern computers.

lightning tour

The GMC-4 comprises a printed circuit board attached to a speaker and a battery enclosure. The board itself includes a key pad (0-F, reset, run, incr and a set), seven 2-pin LEDs, a seven-segment LED and a hard-reset swtich.

Getting a bit more geeky, the GMC-4 seems to have 128 4-bit bytes of memory. This is divided into 96 bytes of program memory, 16 bytes of data memory and 16 bytes given to the 8 registers (yes - there are 8 bytes unaccounted for amongst the registers).

The program memory is where you store instructions for the processor to execute. The data memory is used to store arbitrary data that you might need. The registers are specical bits of memory that are referenced by specific intructions. The point of the registers should become clearer as you read on but for now, just remember there are eight: A, B, Y, Z, A', B', Y' and Z'. The A register is the main one that most instructions use and a value stored in the Y register is used to point to a byte in data memory.

Programming the GMC-4

To enter a program into the GMC-4, first ensure that all memory is cleared by pressing the hard reset button. This will set all memory addresses to a hex value of F (decimal 15 or binary 1111). At this stage the program counter (to be explained later) is pointing to the first memory address. The intructions you can choose from all correspond to a hex character (0-9 and A-F). If you press a key on the pad, the hex value will be stored to the current memory address (where the program counter is pointing) and also displayed on the 7-segment LED. To move the program counter to the next memory address, press the INCR (increment) button. You can keep entering instructions and pressing INCR until you are ready to run.

To run a program, press the RESET button (the one on the keypad - not the hard reset switch wired to the board) to return the program counter to the first memory address. Then press 1 on the keypad (this selects an execute mode) and press RUN. All being well, your program will now do it's thing.

If you need to review what you have entered (eg. for debugging) you can either press the INCR key to see the contents of successive memory addresses or you can jump to a specific place in memory by entering to hex values and pressing the A SET button (address set?).

Assembly language

The GMC-4 understands about 30 instructions. Of these, 15 are accessed using a single hex value and the remainder are accessed by prefixing a hex value with hex E (i.e. E0 - EF)

Each instruction (also called an op code or '4-bit code' in the table below) has a mnemonic that makes up the assembly language. There are even GMC-4 assemblers on the interwebs that you can use to convert a program written in the mnemonics into hex values to be entered via the keypad.

The following table was created by Curtis Hoffman in a Knol on the GMC-4.

Program code table:

Instruction
4-bit Code
Mnemonic Action Result
Flag
Detail
0 KA K->Ar 0, 1 The pressed key from the hex keypad is saved to the A register. If a key is not pressed, the Flag is set to 1, otherwise it is 0.
1 AO Ar->Op 1 The 7-segment readout displays the value currently contained in the A register.
2 CH Ar<=>Br
Yr<=>Zr
1 Exchange the contents of the A and B registers, and the Y and Z registers.
3 CY Ar<=>Yr 1 Exchange the contents of the A and Y registers.
4 AM Ar->M 1 Write the contents of the A register to data memory (memory address is 50 + Y register).
5 MA M->Ar 1 Write the contents of data memory (50 + Y register) to the A register.
6 M+ M+Ar->Ar 0, 1 Add the contents of data memory (50 + Y register) to the A register. If there is overflow, the Flag is set to 1, otherwise 0.
7 M- M-Ar->Ar 0, 1 Subtract the contents of data memory (50 + Y register) from the A register. If the result is negative, the Flag is set to 1, otherwise 0.
8 TIA [ ] [ ] -> Ar 1 Transfer immediate to the A register.
9 AIA [ ] Ar + [ ] -> Ar 0, 1 Add immediate to the A register. If there is overflow, the Flag is set to 1, otherwise 0.
A TIY [ ] [ ] -> Yr 1 Transfer immediate to the Y register.
B AIY [ ] Yr + [ ] -> Yr 0, 1 Add immediate to the Y register. If there is overflow, the Flag is set to 1, otherwise 0.
C CIA [ ] Ar != [ ] ? 0, 1 Compare immediate to the A register. If equal, Flag reset to 0, otherwise set to 1.
D CIY [ ] Yr != [ ] ? 0, 1 Compare immediate to the Y register. If equal, Flag reset to 0, otherwise set to 1.
E --- --- --- Extended code. See table below.
F JUMP [ ] [ ] 1 Jump to the immediate address if the Flag is 1, otherwise just increment the program counter. The Flag is then set to 1. Note that this is an absolute address. That is, JUMP [0] [2] will change the address pointer to hex address 0x02. You can jump both forward and backward in program space.

Extended code table.:

E0 CAL RSTO 1 Clear the 7-segment readout.
E1 CAL SETR 1 Turn on the 2-pin LED using the Y register (Y register takes the value of 0-6).
E2 CAL RSTR 1 Turn off the 2-pin LED using the Y register (Y register takes the value of 0-6).
E3 --- --- Not used.
E4 CAL CMPL 1 Complement the A register (1 <=> 0).
E5 CAL CHNG 1 Swap the A/B/Y/Z registers with A'/B'/Y'/Z'
E6 CAL SIFT 0, 1 Shift the A register right 1 bit. If the starting value is even (bit 0 = 0), set the Flag to 1, otherwise 0.
E7 CAL ENDS 1 Play the End sound.
E8 CAL ERRS 1 Play the Error sound.
E9 CAL SHTS 1 Play a short "pi" sound.
EA CAL LONS 1 Play a longer "pi-" sound.
EB CAL SUND 1 Play a note based on the value of the A register (allowed values are 1 - E).
EC CAL TIMR 1 Pause for the time calculated by (value of A register +1) * 0.1 seconds.
ED CAL DSPR 1 Set the 2-pin LEDs with the value from data memory. The data to display is as follows: the upper three bits come from memory address 5F (bits 0-2), and the lower four from memory address 5E (bits 0-3).
EE CAL DEM- 1 Subtract the value of the A register from the value in data memory. The new value is stored in data memory as a decimal. Afterwards, the Y register is decremented by 1.
EF CAL DEM+ 1 Add the value of the A register to the value in data memory. The new value is stored in memory as a decimal. If the result is overflow, data memory will be automatically adjusted. Afterwards, the Y register is decremented.


I have also created a diagram to help remember what the op codes do.

programming examples

1) Knight Rider lights

OK, this is a pretty obvious thing to do with an array of 2-pin red LEDs across the top of a computer but hey ho. First off, here is the assembly code.

;
;   Knight Rider
;
                    ;   wait timer (b)
start:  tia 0
        ch
        tiy 0
        cal setr
        tiy 1
        cal setr
        tiy 2
        cal setr
                    ;   y=head(0) a=tail(3)
loop:   tiy 0
        tia 3

left:   cal rstr
        cy
        cal setr
        cy
        ch
        cal timr
        ch
        aia 1
        aiy 1
        cia 7
        jump    left
        cy
        aia f
        aiy f

right:  cal rstr
        cy
        cal setr
        cy
        ch
        cal timr
        ch
        aia f
        aiy f
        cia f
        jump    right
        jump    loop

Running that through an assembler gives us the op codes to type in:

アドレス 命令 命令コード
00TIA8
01<0>0
02CH2
03TIYA
04<0>0
05CALE
06_SETR1
07TIYA
08<1>1
09CALE
0A_SETR1
0BTIYA
0C<2>2
0DCALE
0E_SETR1
0FTIYA
10<0>0
11TIA8
12<3>3
13CALE
14_RSTR2
15CY3
16CALE
17_SETR1
18CY3
19CH2
1ACALE
1B_TIMRC
1CCH2
1DAIA9
1E<1>1
1FAIYB
20<1>1
21CIAC
22<7>7
23JUMPF
24<1>1
25<3>3
26CY3
27AIA9
28<F>F
29AIYB
2A<F>F
2BCALE
2C_RSTR2
2DCY3
2ECALE
2F_SETR1
30CY3
31CH2
32CALE
33_TIMRC
34CH2
35AIA9
36<F>F
37AIYB
38<F>F
39CIAC
3A<F>F
3BJUMPF
3C<2>2
3D<B>B
3EJUMPF
3F<0>0
40<F>F

And finally, here is what happens when you run it...