import java.io.* ; // for the IOException
class Sim {
public static final int MAX_ADDRESS = 9999; // addresses are 2 “bytes”
// the following constants give symbolic names for the opcodes
public static final int LDA = 91; // Load Accumulator from memory
public static final int STA = 39; // Store Accumulator into memory
public static final int CLA = 8; // Clear (set to zero) the Accumulator
public static final int INC = 10; // Increment (add 1 to) the Accumulator
public static final int ADD = 99; // Add to Accumulator
public static final int SUB = 61; // Subtract from Accumulator
public static final int JMP = 15; // Jump (“go to “)
public static final int JZ = 17; // Jump if the Zero status bit is TRUE
public static final int JN = 19; // Jump if the Negative status bit is TRUE
public static final int DSP = 1; // Display (write on the screen)
public static final int HLT = 64; // Halt
// instance variable representing the memory and registers of
// the TC1101 architecture
private static final int[] memory = new int[MAX_ADDRESS + 1];
private static int pc; // program counter
private static int a; // accumulator
private static int opCode; // the opcode of the current instruction
private static int opAddr; // the ADDRESS of the operand of the current instruction
private static boolean z; // “Zero” status bit
private static boolean n; // “Negative” status bit
private static boolean h; // “Halt” status bit
private static int mar; // Memory Address register
private static int mdr; // Memory Data register
private static boolean rw; // Read/Write bit. Read = True; Write = False
// this method reads the whole file “filename” and stores the non-comment
// values in memory at successive storage locations
public static void load (String filename) throws IOException {
int[] values;
int i;
int address = 0;
SimIO.setInputFile(filename);
while (!SimIO.eof()) {
values = SimIO.readCommentedIntegerLine();
for (i = 0; i < values.length; i++) {
memory[address] = values[i];
address = address + 1;
}
}
}
// this method simulates the effect of activating the memory control line
private static void accessMemory() {
if (rw) { // rw=True means "read"
// = copy a value from memory into the CPU
mdr = memory[mar];
} else { // rw=False means "write"
// = copy a value into memory from the CPU
memory[mar] = mdr;
}
}
// this method simulates the Fetch-Execute cycle starting at location 0000
public static void run() {
pc = 0; // always start execution at location 0000
h = false; // reset the Halt status bit
while (h == false) {
// FETCH OPCODE
mar = pc;
pc = pc + 1; // NOTE that pc is incremented immediately
rw = true;
accessMemory();
opCode = mdr;
// If the opcode is odd, it needs an operand.
// FETCH THE ADDRESS OF THE OPERAND
if ((opCode % 2) == 1) {
mar = pc;
pc = pc + 1; // pc is incremented immediately
rw = true;
accessMemory();
opAddr = mdr; // this is just the HIGH byte of the opAddr
mar = pc;
pc = pc + 1; // pc is incremented immediately
rw = true;
accessMemory(); // this gets the LOW byte
opAddr = 100*opAddr + mdr; // put the two bytes together
}
// EXECUTE THE OPERATION
switch (opCode) {
case LDA: {
mar = opAddr; // Get the Operand's value from memory
rw = true;
accessMemory();
a = mdr; // and store it in the Accumulator
break ;
}
case STA: {
mdr = a; // Store the Accumulator
mar = opAddr; // into the Operand's address
rw = false; // False means "write"
accessMemory();
break ;
}
case CLA: {
a = 0; // Clear = set the Accumulator to zero
z = true; // set the Status Bits appropriately
n = false;
break ;
}
case INC: {
a = (a + 1) % 100; // Increment = add 1 to the Accumulator
z = (a == 0); // set the Status Bits appropriately
n = (a < 0);
break ;
}
case ADD: {
mar = opAddr; // Get the Operand's value from memory
rw = true;
accessMemory();
a = (a + mdr) % 100; // and add it to the Accumulator
z = (a == 0); // set the Status Bits appropriately
n = (a < 0);
break;
}
case SUB: {
mar = opAddr; // Get the Operand's value from memory
rw = true;
accessMemory();
a = (a - mdr) % 100; // and subtract it from the Accumulator
z = (a == 0); // set the Status Bits appropriately
n = (a < 0);
break ;
}
case JMP: {
pc = opAddr; // opAddr is the address of the next
// instruction to execute
break;
}
case JZ : {
if (z) { // Jump if the Z status bit is true
pc = opAddr;
}
break ;
}
case JN : { // Jump if the N status bit is true
if (n) {
pc = opAddr;
}
break;
}
case HLT: {
h = true; // set the Halt status bit
break ;
}
case DSP: {
mar = opAddr; // Get the Operand's value from memory
rw = true;
accessMemory();
System.out.println("memory location " + format( mar, 4 ) +
" contains the value " + format( mdr, 2 ) );
break;
}
default:
System.err.println( "Error - unknown opcode: " + opCode );
dump();
System.exit( 1 );
} // end of the case statement
} // end of fetch-execute loop
} // end of "run" method
private static String format( int i, int width ) {
String res = "" + i;
while ( res.length() < width ) {
res = "0" + res;
}
return res;
}
private static void dump() {
for ( int i=0; i<75; i++ ) {
System.err.println( "memory[ "+ format( i, 4 ) + " ] = " + format( memory[ i ], 2 ) );
}
System.err.println( "pc = " + format( pc, 4 ) ); // program counter
System.err.println( "a = " + format( a, 2 ) ); // accumulator
System.err.println( "opCode = " + format( opCode, 2 ) ); // the opcode of the current instruction
System.err.println( "opAddr = " + format( opAddr, 4 ) ); // the ADDRESS of the operand of the current instruction
System.err.println( "z = " + z ); // "Zero" status bit
System.err.println( "n = " + n ); // "Negative" status bit
System.err.println( "h = " + h ); // "Halt" status bit
System.err.println( "rw = " + rw ); // Read/Write bit. Read = True; Write = False
System.err.println( "mar = " + format( mar, 4 ) ); // Memory Address register
System.err.println( "mdr = " + format( mdr, 2 ) ); // Memory Data register
}
}