Movement Instructions II

Let's now look at the implementation of the setflags() function, which is called next in our implementation of LDA. It has two jobs: to set the zero flag and the sign flag (the carry flag is not touched).

The function will set these flags based on some value. In our case, in the implementation of the LDA instruction, we want it to adjust the sign and zero flags based on the new value of the accumulator. Thus we feed this value as a parameter to the function setflags(). The other parameter is just a pointer to the machine structure. We have to pass this, since the setflags() function can't possibly know about it, since althought the type is defined in the emulate.h file, which we have #included in our emulate.c file, the actual instance of the machine structure (where we actually defined a variable of type machine) is specified in the main.c file, which is out of the scope of the setflags() function. This passing of data around from function to function, is quite common in languages in which there are scope rules (scope rules prevent all variables and functions from being visible everywhere - only the ones that occur in files included by the current file are visible, for one thing).

At any rate, the setflags() function does a simple test to see if testval is zero, and another to see if it is positive or not. Note that these tests are simply expressions in parentheses, like those we might use in an if statement, or while loop. These can evaluate to one of two values, true or false. Thus MC->Z is being set to either true or false, depending on how (testval == 0) evaluates. A similar thing happens for MC->P.

Note again the use of the double equals to check for equality. A single equals sign would simply set testval to zero, and perform no test. The expression in parentheses would then evaluate to the value that the variable was being set to, which would be zero, or false, always. So to do an actual comparison, as opposed to an assignment, we use the double equals. This is the source of many errors for beginners and experts alike in the C language.

Coming back to our LDA implementation, we see that the final thing the instruction does is to add an extra 2 to the instruction pointer. This is because the instruction has an operand (the address we spoke about before) which is two bytes long, and we want to skip over that, before moving on to the next instruction (which happens automatically after the big long switch statement).

Next comes the LAX instruction, which is supposed to load the accumulator from the memory location specified by the segment register, X, plus the operand given to the instruction. To fetch that operand from memory, we again use a #define macro, this time labelled OFF.

Next is the LDI instruction, which loads the operand to the instruction, directly into the accumulator. This instruction would be useful if we wanted to load the value 23 say, directly into the accumulator. We'd just use the instruction LDI followed immediately by the operand 23.

The LDS and LSI instructions for loading the stack pointer in various ways should now be self explanatory.

Next come two store instructions, STA and STX for storing the value of the accumulator in memory in various ways. These again should be self explanatory, with the address of the memory location being specified either as an immediate operand, or as the segment register plus them immediate operand, respectively.

LDX loads the segment register from the accumulator. It takes no operands, so the instruction pointer needs no extra updating other than that which occurs automatically after the case statement has executed.

Next come the exchange instructions, which swap two values over. To save the contents of one whilst being overwritten by the other, we make use of one of our temporary variable, which we defined for just a contingency.

The only other interesting thing to note in the exchange instructions is the use of the macro REG in the XCHR instruction. Whenever a register is specified, it is referenced by its number as an operand to the instruction being executed. So again, the macro retrieves this operand from the fictitious memory in which our assembly language code is stored, so use can be made of it. In this case, the register number is used as an offset in the REGS array inside our machine struct. Note that the code for retrieving the operand from memory actually makes use of another macro called IMM8. So we have a macro calling another macro!

The final movement instructions are the stack pushing and popping instructions. These store data on or retrieve data, respectively, from the stack. Take PUSH for example. It moves the stack pointer down two bytes, making room on the stack for the new two bytes of data to be stored on it. Then the relevant data is written to the stack. Since the stack is just a piece of memory pointed to by the stack pointer, we can just use the put() function to do the actual writing for us.