
Recently, I was shown assembler emulators for the Intel-4004, and I was stuck for a while. This is the "grandfather" of the current processors - if you believe the
Wikipedia article - the first commercially common microprocessor.
It is unlikely that it can now be used for some serious purposes. But just to break my head (instead of brainf ** k) - well, that's what I did. The main thing is that it is 4-bit and the set of commands is rather small (before that I knew only a little bit of the x86, at the painful institute course).
')
Below is a free translation-retelling of
this assembler instruction for the Intel-4004 - and brief remarks about my attempts to write something on it.
First about Emulators
I think to see the Intel-4004 alive, and even more so as part of some working device in our time is not easy. For experiments, therefore, emulators remain:
- e4004.szyc.org - the online, it seems, the only full-fledged emulator of the whole "ecosystem" that included this processor - also contains an assembler and disassembler, allows step-by-step debugging, visualization of everything and everything - by Maciej Szyc
- Intel-4004 emu @ github - offline, written in Python (it has a simple online version) - but not “full-fledged” is not - more for exercises and experiments; The online version allows you to transfer the code by reference, for demonstration - I use it below.
Immediately make a reservation - I got acquainted with this topic precisely by the guidance of the authors of the second emulator (and the translated instruction refers to it) - but I only tried its online form, so I apologize in advance for possible errors and inaccuracies in the translation. The first emulator is more convenient for me to debug (although the instruction to it would not hurt either).
About Architecture
From the point of view of me as a programmer, the architecture is very simple. We have:
- 4-bit registers (r0 to r15)
- battery (also 4-bit)
- carry flag
- code memory, contains instructions for 1 or 2 bytes
- RAM - with 4-bit cells
In fact, there is still an invisible instruction counter, a pointer to read / write instructions to the RAM, and a small call stack.
Most logical and arithmetic instructions work either with a battery or with one of the registers.
First try
The first two instructions that offer to remember -
ldm to load the number in the battery and
xch - to exchange the battery and register.
Yes! It does not have instructions for copying the battery to the register (although the reverse
ld instruction is present).
Here is the program of these two instructions:
ldm 5 ; 5 xch r2 ; R2
It is also proposed to see how this works in the emulator
using such a link — all you need to do is to click the “Run” button — and the contents of the registers will appear in the Output field after the code is executed.
Arithmetic
This grandfather doesn’t know how to share something — even multiply. As I understood having played with him a little bit, because of this, even a translation between the 10th and 16th system becomes very difficult. Therefore, it seems that it is proposed to count in BCD - store decimal digits in 4 bits and perform special actions on them to correct decimal results.
Add add - adds the specified register to the battery. In addition, the carry flag is added (so it is useful to reset it first with
clc ). After the addition, the carry flag is set if there was an overflow.
For counting in 10-hour numbers after the addition, you can execute the
daa instruction - in fact, if the number in the battery is from 10 to 15, subtract 10 from it and set the carry flag.
; R6:R7 fim r0 $67 ; 6 R0 7 R1 ld r0 ; 6 clc ; add r1 ; , 13 daa ; 3 ; R2:R3 xch r3 ; R3 ldm 0 ; ral ; xch r2 ; R2
I do not know if there is a way to write down the transfer flag to the register. Check the code can be
on the link .
Subtraction works like. In the Hex format there are no problems with it, the transfer flag is used as a loan. Unfortunately, subtraction in BCD requires a slight brain strain before the meaning of the instructions becomes clear - so I’ll skip it for now.
There are
iac increment and
dac decrement instructions for the battery, a separate
inc increment for registers, and also instructions for battery inversion and
cma and
cmc transfer .
Branches, transitions
For structural organizations like conditions and cycles, we have a few instructions.
Unconditional transition
jun - just to a given label.
The
jms subroutine call is the same by the label (but the return address is pushed onto the stack). Return instruction
bbl which takes a number as a parameter - writes it to the battery. We can not say that it was convenient - it turns out, an arbitrary result of calculations in the battery can not be returned.
The conditional jump instructions can determine whether the carry flag is set / cleared, or the battery is equal to / not equal to zero.
jcn c0 ... ; = 0 jcn c1 ... ; = 1 jcn az ... ; = 0 jcn an ... ; <> 0
There is another interesting
isz instruction - it increases the specified register by one.
For the demonstration, I will write a program that squares the number loaded into the battery:
; ACC, R2:R3 ldm 5 ; , , 5 xch r0 ; R0 ld r0 xch r1 ; R1 - repeat: ld r0 ; R0 clc add r3 ; xch r3 ; R3 jcn c0 nocarry inc r2 ; R2 nocarry: ld r1 ; 1 dac jcn az finish ; xch r1 ; jun repeat ; finish: nop
Demonstration
of the link .
Conclusion
There are several more instructions for loading data, working with RAM and code memory. In addition to them, the offline emulator has a couple of “magic” calls that allow you to read-write the console - this makes it possible to write something like scripts to handle strings, etc. - it is clear, however, that this does not apply to the original systems using this processor.
But I see that quite a lot of text has already happened, although I managed to retell only about half of what I read. It is probably better to stop at this and, if you are interested, write a supplement as a separate article.
Links to original instructions: