This is going to be really simple. Our computer will have:
At each “step”, the computer reads the memory word whose address is in $IP$ and then increments $IP$. Then it carries out the instruction that that word represents.
This is how most computers, uh, cores, work. It is called the fetch-execute cycle.
In this class, we’re not too concerned with how steps are synchronized; we’ll just say there’s a clock.
Each word that the computer tries to execute will be interpreted to have:
For a given instruction word, let’s call $op$ the first four bits, and $x$ the last 28 bits. We formally specify the operation of each instruction as follows. All arithmetic is signed, modular, 32-bit integer arithmetic.
op | Action | Remarks |
---|---|---|
0 | $A := M[x]$ | Load accumulator from memory |
1 | $M[x] := A$ | Store accumulator to memory |
2 | $A := P[x]$ | Read from a port into the accumulator |
3 | $P[x] := A$ | Write accumulator out to a port |
4 | $A := A + M[x]$ | Add into accumulator |
5 | $A := A - M[x]$ | Subtract from accumulator |
6 | $A := A \times M[x]$ | Multiply into accumulator |
7 | $A := A \div M[x]$ | Divide accumulator |
8 | $A := A \:\texttt{mod}\: M[x]$ | Modulo |
9 | $A := A \wedge M[x]$ | Bitwise AND |
A | $A := A \vee M[x]$ | Bitwise OR |
B | $A := A \oplus M[x]$ | Bitwise XOR |
C | $IP := x$ | Jump to new address |
D | if $A = 0$ then $IP := x$ | Jump if accumulator is zero |
E | if $A < 0$ then $IP := x$ | Jump if accumulator is less than zero |
F | if $A > 0$ then $IP := x$ | Jump if accumulator is greater than zero |
This program, when loaded into memory at address 0, outputs powers of two, starting with 1, and going just past 1,000,000, to port 100 (64 hex):
C0000003 00000001 000F4240 00000001 30000064 40000001 10000001 50000002 E0000003 C0000009
Hello, world
to port 888, assuming a UTF-32 encoding.
The example above was hard to read. Just listing the contents of memory that the processor executes is called “writing machine language.” Let’s use mnemonics for each instruction. Then the example becomes:
0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 |
C0000003 00000001 000F4240 00000001 30000064 40000001 10000001 50000002 E0000003 C0000009 |
JUMP start ; begin by jumping over the data area pow: 1 ; store the current power value here limit: 1000000 ; we'll be computing powers up to this amount start: LOAD pow ; bring the value into accumulator to use OUT 100 ; output the current power ADD pow ; adding to itself makes the next power! STORE pow ; store it (for next time) SUB limit ; we need to compare with limit, subtracting helps JLZ start ; if not yet past limit, keep going end: JUMP end ; this "stops" the program! |
In general, each line of an assembly language program contains:
;
character.
In our machine, the mnemonics will be: LOAD, STORE, IN, OUT, ADD, SUB, MUL, DIV, MOD, AND, OR, XOR, JUMP, JZ, JLZ, JGZ.
The process of converting from assembly language to machine language is called assembly. The reverse process is called disassembly. Yes, there exist programs called assemblers and disassemblers.
100038A0
. Is this an instruction to store the accumulator into memory address 0x00038A0, or is it a representation of the value 268449952? Or is it both? Why is this question philosophically interesting? Discuss.
The purpose of this simple computer is to introduce the basic concepts of the fetch-execute cycle and the difference between machine and assembly language. Things we haven’t covered include:
If you found this machine interesting, here are things you can do: