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.
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.
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?).
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.
Program code table:
|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.|
|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   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).|
|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.
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:
And finally, here is what happens when you run it...