Simulated simple computer

Assignment 1

OS Problem Set

Introduction
The following machine description will provide the basis for this assignment. You will
create a virtual machine/operating system for the machine described below that will accept
programs in the target machine language. The details for this assignment are presented
below following the machine description.

MICROPROGRAMMING/MACHINE DISCRIPTION

The following is a description of a machine called SIMMAC that contains the following:
512 32-bit words of memory (memory is word addressable).
Each Instruction consists of a 16-bit opcode and a 16-bit operand.
An ALU for performing mathematical operations.
Registers
ACC Accumulator; A 32-bit register involved in all arithmeticoperations. One of the operands in each arithmetic operationmust be in the Accumulator; the other must be in primarystorage.
PSIAR Primary Storage Instruction Address Register; This 16-bitregister points to the location in primary storage of the nextmachine language instruction to be executed.

SAR Storage Address Register; This 16-bit register is involved in allreferences to primary storage. It holds the address of thelocation in primary storage being read from or written to.
SDR Storage Data Register; This 32-bit register is also involved inall references to primary storage. It holds the data beingwritten to or receives the data being read from primary storage
at the location specified in the SAR.
TMPR Temporary Register; This 32-bit register is used to extract theaddress portion (rightmost 16-bits) of the machine instruction inthe SDR so that it may be placed in the SAR. (No SDR to SARtransfer.)
CSIAR Control Storage Instruction Address Register; This registerpoints to the location of the next micro-instruction (in controlstorage) to be executed.
IR Instruction Register; This register contains the currentinstruction being executed.
MIR Micro-instruction Register; This register contains the currentmicro-instruction being executed.
Register Transfers (REG is ACC, PSIAR, or TMPR):
SDR = REG
REG = SDR
SAR = REG
Primary Storage Operations:
READ Data from primary storage location named in the SAR is
placed in the SDR.
WRITE Data in the SDR is placed in primary storage location
named in the SAR.
Sequencing operations:
CSIAR = CSIAR + 1
CSIAR = decoded SDR
CSIAR = constant
SKIP = (add 2 to CSIAR if ACC=0; else add 1)
Operations involving the accumulator:
ACC = ACC + REG
ACC = ACC – REG
ACC = REG
REG = ACC
ACC = REG + 1
Instruction fetch:

  • SAR = PSIAR
    (01) READ
    (02) IR = SDR
    (03) SDR = decoded IR (Operand)
    (04) CSIAR = decoded IR (OP CODE)
    ADD (Opcode 10):
    (10) TMPR = ACC
    (11) ACC = PSIAR + 1
    (12) PSIAR = ACC
    (13) ACC = TMPR
    (14) TMPR = SDR
    (15) SAR = TMPR
    (16) READ
    (17) TMPR = SDR
    (18) ACC = ACC + TMPR
    (19) CSIAR = 0
    SUB (Opcode 20):
    (20) TMPR = ACC
    (21) ACC = PSIAR + 1
    (22) PSIAR = ACC
    (23) ACC = TMPR
    (24) TMPR = SDR
    (25) SAR = TMPR
    (26) READ
    (27) TMPR = SDR
    (28) ACC = ACC – TMPR
    (29) CSIAR = 0
    LOAD (LDA, Opcode 30):
    (30) TMPR = ACC
    (31) ACC = PSIAR + 1
    (32) PSIAR = ACC
    (33) ACC = TMPR
    (34) TMPR = SDR
    (35) SAR = TMPR
    (36) READ
    (37) ACC = SDR
    (38) CSIAR = 0
    STORE (Name STR, Opcode 40):

(40) TMPR = ACC
(41) ACC = PSIAR + 1
(42) PSIAR = ACC
(43) ACC = TMPR
(44) TMPR = SDR
(45) SAR = TMPR
(46) SDR = ACC
(47) WRITE
(48) CSIAR = 0
BRANCH (Name BRH, Opcode 50):
(50) PSIAR = SDR
(51) CSIAR = 0
COND BRANCH (Name CBR, Opcode 60):
(60) SKIP
(61) CSIAR = 64
(62) PSIAR = SDR
(63) CSIAR = 0
(64) TMPR = ACC
(65) ACC = PSIAR + 1
(65) PSIAR = ACC
(66) ACC = TMPR
(67) CSIAR = 0
LOAD IMMEDIATE (LDI, Opcode 70):
(70) ACC = PSIAR + 1
(71) PSIAR = ACC
(72) ACC = SDR
(73) CSIAR = 0

SIMMAC Programming Language Description
Addition
Usage: ADD <address>
Where <address> holds the value to add to the accumulator.
Subtraction
Usage: SUB <address>
Where <address> holds the value to subtract from the accumulator.
Load
Usage: LDA <address>
Where <address> holds the value to load in to the accumulator.
Load Immediate
Usage: LDI number
Where number is the value to load in to the accumulator.
Store
Usage: STR <address>
Where <address> is the storage location for the contents of the
accumulator.
Branch
Usage: BRH <address>
Where <address> is the target of the absolute branch.

Conditional Branch
Usage: CBR <address>
Where <address> is the target of an absolute branch if the
accumulator is zero.

Project Description
Design and implement a program to simulate the operation of the SIMMAC based on thedescriptions above.Add a HALT instruction that dumps the contents of all registers and memory and then printsan “End of Job” message.Your project must implement multi-tasking in a single queue using a round-robin schedulingdiscipline. You will implement process entities (jobs) that will allow your machine to runseveral SIMMAC machine-language programs. In order to do this you will define a ProcessControl Block (PCB) data structure that will be created for each job in your system. For thisassignment assume each SIMMAC instruction is equivalent to one clock cycle. Additionallythe time quantum value for round-robin scheduling is an integer multiple of a clock cycle.The quantum value is to be set on the command line or prompted for during initialization.You will define the notion of an interrupt handler that will process a time quantum for eachrunning job. On each job switch, you will print some state information such as which job willbe loaded and the current state of the job queues.
Your version of SIMMAC will then run multiple SIMMAC machine language programs
simultaneously. These programs will test the ability of your SIMMAC to handle multitasking and scheduling. You must design your system such that all SIMMAC machineprograms are loaded from text files.
The SIMMAC must be designed to take command line arguments or to prompt for input
files in addition to the previously specified items. By this mechanism, all SIMMAC
language programs will be loaded. Since there is the LDI command, all data can be loadedinto SIMMAC memory using SIMMAC programming statements.
You must develop SIMMAC language programs to be run on your SIMMAC machine.
There must be at least three different programs that exercise the system and are of
significant length to demonstrate the multitasking/scheduling ability of your system. Youmust clearly document your programs so that it is clear as to the logic and intent of eachSIMMAC language program.

Each line of any SIMMAC program must have the following format:
Opcode OperandYou will be responsible for turning in the system design document, source code of yourversion of SIMMAC (this code must be appropriately commented & readable), anexecutable version of your SIMMAC, and the output generated from your SIMMACprograms running on your version of SIMMAC. 

Solution: 

Instruction.java

package simmac;

public class Instruction {

public static final int DW = 0x0000;

public static final int ADD = 0x0001;

public static final int SUB = 0x0002;

public static final int LDA = 0x0003;

public static final int LDI = 0x0004;

public static final int STR = 0x0005;

public static final int BRH = 0x0006;

public static final int CBR = 0x0007;

public static final int HLT = 0x0008;

/* if the given word corresponds to a valid opcode returns the numerical

opcode, if it is not a valid opcode returns -1*/

public static int getOpcode(String word){

String opcode=word.toUpperCase();

switch (opcode) {

case “DW”:

return DW;

case “ADD”:

return ADD;

case “SUB”:

return SUB;

case “LDA”:

return LDA;

case “LDI”:

return LDI;

case “STR”:

return STR;

case “BRH”:

return BRH;

case “CBR”:

return CBR;

case “HALT”:

return HLT;

default:

return -1;

}

}

/* if the string operand corresponds to a valid operand for the opcode

it returns the numerical value, otherwise it returns null

*/

private static Integer parseOperand(int opcode,String operand,String filename,int nline) {

switch(opcode) {

case ADD:

case SUB:

case LDA:

case STR:

case BRH:

case CBR:

if (operand.matches(“\\d+”)) { // if it’s a valid unsigned number

int val=Integer.parseInt(operand);

if(val>=0 && val<32767) // if it’s at most 16 bits

return val;

else {

System.out.println(“Error [“+filename+”(“+nline+ “)]: the number: “+operand+” is longer than 16 bits.”);

return null;

}

}

else {

System.out.println(“Error [“+filename+”(“+nline+ “)]: invalid number: “+operand+”.”);

return null;

}

case DW:

if (operand.matches(“[+-]?\\d+”)) {

int val=Integer.parseInt(operand);

return val;

}

else {

System.out.println(“Error [“+filename+”(“+nline+ “)]: invalid integer number: “+operand+”.”);

return null;

}

case LDI:

if (operand.matches(“[+-]?\\d+”)) {

int val=Integer.parseInt(operand);

if(val>=-32768 && val<32767)

return val;

else {

System.out.println(“Error [“+filename+”(“+nline+ “)]: the number: “+operand+” is longer than 16 bits.”);

return null;

}

}

else {

System.out.println(“Error [“+filename+”(“+nline+ “)]: invalid integer number: “+operand+”.”);

return null;

}

default:

return null;

}

}

/* parses the given line and determines if it corressponds to a valid

SIMMAC instruction */

public static Integer parseInstruction(String line,String filename,int nline) {

String [] parts= line.split(“\\s+”);

if(parts.length>2) {

System.out.println(“Error [“+filename+”(“+nline+ “)]: a SIMMAC instruction can only contain one opcode and one operand.”);

return null;

}

if(parts[0].length()==0) {

System.out.println(“Error [“+filename+”(“+nline+ “)]: a SIMMAC instruction can only contain one opcode and one operand.”);

return null;

}

int opc= getOpcode(parts[0]);

if (opc==-1) {

System.out.println(“Error [“+filename+”(“+nline+ “)]: invalid instruction opcode: “+parts[0]+”.”);

return null;

}

if(opc==HLT) {

if(parts.length>1)  {

System.out.println(“Error [“+filename+”(“+nline+ “)]: invalid operand for HALT instruction. HALT requires no operands.”);

return null;

}

return (opc << 16);

}

else {

if(parts.length!=2)  {

System.out.println(“Error [“+filename+”(“+nline+ “)]: SIMMAC instructions other than HALT must contain an opcode and an operand.”);

return null;

}

Integer op=parseOperand(opc,parts[1],filename,nline);

if(op==null)

return null;

return ((opc << 16)| op);

}

}

}

Main.java

package simmac;

import java.io.File;

import java.io.FileNotFoundException;

import java.util.ArrayList;

import java.util.Scanner;

public class Main {

/* open a SIMMAC program file and parse its contents, if everything is fine

returns an array with all the instructions */

public static int [] readProgramFile(String filename) {

try {

Scanner s = new Scanner(new File(filename));

ArrayList<Integer> instructions = new ArrayList();

int nline = 1;

while (s.hasNext()){

String line=s.nextLine().trim();

if(line.length()>0)

{

Integer inst=Instruction.parseInstruction(line,filename,nline); // parse the instruction contained in the current line

if (inst != null) { // if the instruction was valid

instructions.add(inst);

}

else

System.exit(0);

}

nline++;

}

s.close();

int [] instr = new int[instructions.size()];

for(int i=0; i<instructions.size(); i++)

instr[i]=instructions.get(i);

return instr; // success, return the instruction list

} catch (FileNotFoundException e) {

System.out.println(“Error: program file ” + filename + ” could not be opened.”);

System.exit(0); //failure

}

return null;

}

/**

* @param args the command line arguments

*/

public static void main(String[] args) {

System.out.print(“Please enter the time quantum value: “);  // ask for the filename to use

Scanner s = new Scanner(System.in);

int quantum = s.nextInt();

SIMMAC cpu = new SIMMAC();

OperatingSystem os = new OperatingSystem(cpu,quantum);

if(args.length==0) {

boolean done=false;

ArrayList<String> filenames=new ArrayList();

while(!done) {

System.out.print(“Please enter a program filename to load: “);  // ask for the filename to use

filenames.add(s.next());

System.out.print(“Do you want to load another file? (Y/N): “);

String c=s.next();

if(c.toUpperCase().equals(“N”) || !c.toUpperCase().equals(“Y”))

done=true;

}

for(int i=0; i<filenames.size(); i++) {

int [] program = readProgramFile(filenames.get(i));

os.loadProgram(program);

}

}

else {

for(int i=0; i<args.length; i++)

{

int [] program = readProgramFile(args[i]);

os.loadProgram(program);

}

}

os.run();   // run the processes

}

} 

OperatingSystem.java

 package simmac;

import java.util.ArrayList;

public class OperatingSystem {

ArrayList<Process> readyQueue;  // queue of processes ready to run

Process currentProcess;         // process currently being executed

SIMMAC cpu;                     // cpu used to execute the processes

int quantum;    // value of the time quantum

int lastLoadAddress;    // address to load a program

int clock;

public OperatingSystem(SIMMAC cpu,int quantum) {

this.cpu=cpu;

this.quantum=quantum;

lastLoadAddress=0;

readyQueue=new ArrayList();

currentProcess=null;

clock=0;

}

/* prints the ready process queue */

public void printProcesses() {

System.out.print(“Process queue: “);

System.out.print(“[ “);

for(int i=0; i<readyQueue.size(); i++)

{

if(i>0)

System.out.print(“, “);

System.out.print(readyQueue.get(i).procid);

}

System.out.println(” ]”);

}

/* Switch the current process for another from the ready queue */

public void switchProcess() {

if(currentProcess!=null) {

currentProcess.ACC = cpu.ACC;   // save current register state

currentProcess.PSIAR = cpu.PSIAR;

readyQueue.add(currentProcess);

}

currentProcess=readyQueue.remove(0);    // get process from queue

cpu.ACC=currentProcess.ACC; // load register state

cpu.PSIAR=currentProcess.PSIAR;

cpu.memoryLimit = currentProcess.memoryLimit;   // load memory limits

cpu.memoryBase = currentProcess.memoryBase;

clock = 0;  // restart clock count

System.out.println(“\nSwitching process.”);

System.out.println(“Next process ID: “+currentProcess.procid);

printProcesses();

System.out.println();

}

/* Run the loaded processes in an loop until all are executed or an error happens*/

public void run() {

boolean terminate = false;

currentProcess=null;

switchProcess(); // load first process

while(!terminate)

{

boolean exitStatus = cpu.executeInstruction();

clock++;

if(exitStatus==true) { // it the process was terminated

if(readyQueue.size()>0)

{

currentProcess=null; // invalidate current process

switchProcess();    // forced swap to a different process

}

else

terminate=true; // no more processes, exit the program

}

if(clock>=quantum && !terminate) {

switchProcess();

}

}

}

/* load a SIMMAC program to memory */

void loadProgram(int [] program) {

int startAddress=lastLoadAddress;

if (lastLoadAddress + program.length >= cpu.MEMORY_SIZE) {

System.out.println(“Error: cannot load program, program size exceeds memory size.”);

System.exit(0);

}

for (int i=0; i<program.length; i++)

cpu.Memory[lastLoadAddress+i] = program[i];

lastLoadAddress+=program.length;

Process process= new Process(startAddress,program.length,readyQueue.size());

readyQueue.add(process);

}

}

Process.java

 package simmac;

// Definition of a process control block

public class Process {

public int procid;

public int ACC;

public int PSIAR;

public int memoryBase;

public int memoryLimit;

public Process(int address,int size,int procid) {

this. procid=procid;

ACC = 0;

PSIAR = 0;

memoryBase = address;

memoryLimit=address+size;

}

} 

SIMMAC.java

 package simmac;

public class SIMMAC {

public final int MEMORY_SIZE = 512;

public int Memory[];

public int memoryBase;  // starting address for current process

public int memoryLimit; // maximum address allowed for current process

// registers

public int ACC;    // accumulator

public int PSIAR;  // Primary Storage Instruction Address Register

int SAR;    // Storage Address Register

int SDR;    // Storage Data Register

int TMPR;   // Temporary Register

int CSIAR;  // Control Storage Instruction Address Register

int IR;     // Instruction Register

int MIR;    // Micro-instruction Register

public SIMMAC() {

Memory=new int [MEMORY_SIZE];

CSIAR = 0;

PSIAR = 0;

ACC = 0;

memoryLimit=MEMORY_SIZE;

memoryBase=0;

}

/* read from memory using the SAR register, if an error was found returns true */

boolean read() {

if(SAR+memoryBase>=0 && SAR+memoryBase<memoryLimit) {

SDR=Memory[memoryBase+SAR];

return false;

}

else

return true;

}

/* write to memory using the SAR register, if an error was found returns true */

boolean write() {

if(SAR+memoryBase>=0 && SAR+memoryBase<memoryLimit) {

Memory[memoryBase+SAR]=SDR;

return false;

}

else

return true;

}

boolean fetch() {

SAR = PSIAR;

if(read())

return true;

IR = SDR;

SDR = IR & 0xFFFF;

CSIAR = IR >> 16;

return false;

}

boolean add() {

TMPR = ACC;

ACC = PSIAR + 1;

PSIAR = ACC;

ACC = TMPR;

TMPR = SDR;

SAR = TMPR;

if(read())

return true;

TMPR = SDR;

ACC = ACC + TMPR;

CSIAR = 0;

return false;

}

boolean sub() {

TMPR = ACC;

ACC = PSIAR + 1;

PSIAR = ACC;

ACC = TMPR;

TMPR = SDR;

SAR = TMPR;

if(read())

return true;

TMPR = SDR;

ACC = ACC – TMPR;

CSIAR = 0;

return false;

}

boolean load() {

TMPR = ACC;

ACC = PSIAR + 1;

PSIAR = ACC;

ACC = TMPR;

TMPR = SDR;

SAR = TMPR;

if(read())

return true;

ACC = SDR;

CSIAR = 0;

return false;

}

boolean store() {

TMPR = ACC;

ACC = PSIAR + 1;

PSIAR = ACC;

ACC = TMPR;

TMPR = SDR;

SAR = TMPR;

SDR = ACC;

if(write())

return true;

CSIAR = 0;

return false;

}

boolean branch() {

PSIAR = SDR;

CSIAR = 0;

return false;

}

boolean conditionalBranch() {

if (ACC==0) {

PSIAR = SDR;

CSIAR = 0;

}

else {

TMPR = ACC;

ACC = PSIAR + 1;

PSIAR = ACC;

ACC = TMPR;

CSIAR = 0;

}

return false;

}

boolean loadImmediate() {

ACC = PSIAR + 1;

PSIAR = ACC;

ACC = SDR;

CSIAR = 0;

return false;

}

/* print the contents of all the registers and all memory */

public void dump() {

System.out.printf(“Register contents:\n”);

System.out.printf(“ACC = %08X\tPSIAR = %04X\tSAR = %04X\tSDR = %08X\n”,ACC,PSIAR,SAR,SDR);

System.out.printf(“TMPR = %08X\tCSIAR = %04X\tIR = %04X\tMIR = %04X\n”,TMPR,CSIAR,IR,MIR);

System.out.printf(“\nMemory contents:\n%03d: “,0);

for (int i=0; i<MEMORY_SIZE; i++) {

if(i!=0 && i%8==0)

System.out.printf(“\n%03d: “,i);

System.out.printf(“%08X “,Memory[i]);

}

System.out.println();

}

public boolean executeInstruction() {

boolean halt = false;

boolean error = false;

fetch();

switch(CSIAR) {

case Instruction.ADD:

error=add();

break;

case Instruction.SUB:

error=sub();

break;

case Instruction.LDA:

error=load();

break;

case Instruction.STR:

error=store();

break;

case Instruction.BRH:

error=branch();

break;

case Instruction.CBR:

error=conditionalBranch();

break;

case Instruction.LDI:

error=loadImmediate();

break;

case Instruction.HLT:

dump();

System.out.println(“End of job.”);

halt=true;

break;

default:

dump();

System.out.printf(“Error: invalid instruction %04X.\nProgram terminated.\n”,IR);

halt =true;

}

if(error) {

dump();

System.out.printf(“Error: invalid memory address %04X.\nProgram terminated.\n”,SAR);

}

return (halt || error); // return true if there was an error, false otherwise

}

}