Table of Contents

Part 1

Entries

Topics

Objectives

Experiments

CPU Simulator

The following information was provided by Matt Haas (of Lab46 fame). Heretofore the following only existed in an email, and has been posted here for the sole reason that I would rather not lose it. (I have edited to make this conversationally independent)

The basic premise of the simulator, aside from any independent user interface, is that the bulk of the coding is rather repetitious. Interpreting instructions (in hex), has typically been done via a switch-case statement (a very big one), and in each case stanza the appropriate actions take place.

An example based on an imaginary CPU:

Let's say our CPU has four 8-bit registers:

  1. Accumulator (A)
  2. Data (D)
  3. Program Counter (PC)
  4. Instruction Register (IR)
  5. Flags (F) - R R R R R R S Z (first six bits are reserved, last two are “sign” and “zero”)

The CPU has 8 bytes of memory (memory addresses 0x00 through 0x07)

Our CPU has one instruction, ADD, with three variations and thereby three hex codes of 0x1A, 0x1B, and 0x1C:

 0x1A: Add Accumulator and Data, store result in Accumulator
 0x1B: Add Accumulator and Immediate (user specified) value, store result in Accumulator
 0x1C: Add Accumulator and Memory location, store result in Accumulator

We'll have the following program in memory (address first, then instruction):

 0x00    0x1A
 0x01    0x1B
 0x02    0x03
 0x03    0x1C
 0x04    0x07
 0x05    0x00
 0x06    0x00
 0x07    0x42

Obviously in a real CPU there'd be far more instructions, and more things going on.

When the program starts, the registers have the following values:

 A: 0x06
 D: 0x02
 PC: 0x00 (program counter contains the address of the next instruction to execute)
 IR: 0x00 (nothing has happened yet)
 F: 0x00 (nothing has happened yet)

In our simulator, we'll want to read the next instruction located at the address stored in the program counter into the address register:

while (1)
{
   IR = *PC; (we grab the contents of the memory address to which PC is pointing)
   switch(IR)
   {
       increment = 1; // how much to increment the PC
       case 0x1A:
           A = A + D;
           if (A == 0) // result of operation was zero
               F = F | 0x01; (we OR the flags register, forcing the 'Z' bit high)
           else // result was non-zero
               F = F & 0xFE; (we AND the flags register, forcing the 'Z' bit low)

           if (A < 0) // result is a negative value
               F = F | 0x02; (we OR the flags register, forcing the 'S' bit high)
           else
               F = F & 0xFD; (we AND the flags register, forcing the 'S' bit low)
           break;

       case 0x1B:
           A = A + *(PC+1); // add accumulator to value stored in memory immediately following instruction
           if (A == 0) // result of operation was zero
               F = F | 0x01; (we OR the flags register, forcing the 'Z' bit high)
           else // result was non-zero
               F = F & 0xFE; (we AND the flags register, forcing the 'Z' bit low)

           if (A < 0) // result is a negative value
               F = F | 0x02; (we OR the flags register, forcing the 'S' bit high)
           else
               F = F & 0xFD; (we AND the flags register, forcing the 'S' bit low)
           increment = 2; // this instruction is 2 bytes
           break;

   case 0x1C:
           A = A + **(PC+1); // double dereference... first grab memory address, then dereference it
           if (A == 0) // result of operation was zero
               F = F | 0x01; (we OR the flags register, forcing the 'Z' bit high)
           else // result was non-zero
               F = F & 0xFE; (we AND the flags register, forcing the 'Z' bit low)

           if (A < 0) // result is a negative value
               F = F | 0x02; (we OR the flags register, forcing the 'S' bit high)
           else
               F = F & 0xFD; (we AND the flags register, forcing the 'S' bit low)
           increment = 2; // this instruction is 2 bytes
           break;

   default:
           // bad instruction
           break;
   }
   PC=PC+increment; // increment the program counter appropriately
}