Let us briefly describe the assembly language that we will implement, i.e. the language that the processor in our fictitious machine will understand.
As mentioned, the processor is just a bit pusher - a sophisiticated way of pushing data around inside a computer. So perhaps the most important instructions which our processor will implement, are the data movement instructions.
Since the registers in our machine are 2 bytes, or 16 bits, it makes sense to implement a whole lot of data movement instructions which shift data around 16 bits at a time. If you open up the file emulate.h you will see the instructions listed by name with the data movement instructions listed first.
The first instruction listed is named LDA. A comment next to it says that it loads the accumulator from memory. An example of how this instruction might be used in an assembly language program is:
This would load the 16 bits of data at the memory location numbered 2312, into the accumulator.
The next instruction, LAX, does a similar thing, except that it uses a different way of figuring out which memory location to load. The address of the location is given by the contents of the segment register X plus the offset listed. For example:
would load the accumulator from the memory location whose address is given by the contents of the segment register plus 13.
Sometimes we might just want to load a specific value into the accumulator. This is accomplised with an instruction like:
which would load the value 2 directly into the accumulator.
The instructions STA and STX perform store operations. They do the opposite of the load instructions, and put whatever is in the accumulator into memory.
LDX is the first case of a no operand instruction. This means that it is used on its own, with no additional numbers following it. E.g:
would appear in a program just on its own, without any operands. This instruction simply moves the contents of the accumulator into the segment register.
The instructions XCHG and XCHR are exchange instructions. They swap two values over. E.g:
swaps the contents of the accumulator with the register numbered 4.
The PUSH and POP instructions put information onto the stack and retrieve it back off again respectively. E.g:
pushes the contents of register 4 onto the stack. These instructions are usually used in conjunction with subroutines. Just before a subroutine is called, information is pushed onto the stack. When the subroutine executes, no matter where it is called from in the program, it knows that it will find the relevant data that it needs to use, on the stack. After the subroutine returns the information can be taken back off the stack and restored to normal.
Alternatively, PUSH and POP instructions can be used to save the contents of certain registers while a particular computation is being performed which might mess up the contents of those registers. Again this is usually done when calling subroutines. A subroutine itself might mess up the value in the accumulator, which the main program might need to remain unscathed. Therefore the subroutine, when it is called, might push the accumulator onto the stack, and just before it finishes, it might restore the accumulator back off the stack (i.e. back to its original value which was saved on the stack).