/lab4/pdp8.c
C | 654 lines | 485 code | 56 blank | 113 comment | 230 complexity | 4fc493487052aa32f16a47cd9b438105 MD5 | raw file
- /* Name of Program pdp8.c */
- /* Program Description: Simulates a 12-bit pdp8 machine when given and object file */
- /* Name Jeremy Wenzel */
- /* CSID/EID jhw866 */
- /* Section number: 53865 */
- /* Last update: 10/27/2013 23:30 */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- typedef short Boolean;
- #define TRUE 1;
- #define FALSE 0;
- int time = 0;
- short ep_found = 0;
- short skip;
- short memory[4096] = {0};
- short pc;
- short accumulator;
- short link_bit;
- short rotated = 0;
- short halt = 0;
- short indirect = 0;
- short dev = 0;
- short mode = 0;
- /* If this is called, we start writing to stderr with the verbose */
- /* Input: None */
- /* Return: None */
- void verbose(short opcode) {
- char str[30] = {0};
- short group;
- short placed = 0;
- short check = 0;
- short one_two = 0;
- /* For memory reference instructions */
- if(opcode == 0)
- strcat(str, "AND");
- if(opcode == 1)
- strcat(str, "TAD");
- if(opcode == 2)
- strcat(str, "ISZ");
- if(opcode == 3)
- strcat(str, "DCA");
- if(opcode == 4)
- strcat(str, "JMS");
- if(opcode == 5)
- strcat(str, "JMP");
- /* For Input/Output Instructions */
- if(opcode == 6) {
- if(dev == 3)
- strcat(str, "IOT 3");
- else if(dev == 4)
- strcat(str, "IOT 4");
- else
- fprintf(stderr, "IOT <bad-device>");
- }
- if(opcode == 7) {
- group = (memory[pc] >> 8) & 1;
- if(group == 0) {
- // Write CLA
- check = (memory[pc] >> 7) & 1;
- if(check == 1) {
- strcat(str, "CLA");
- placed = 1;
- }
- // write CLL
- check = (memory[pc] >> 6) & 1;
- if(check == 1) {
- if(placed == 1)
- strcat(str, " ");
- strcat(str, "CLL");
- placed = 1;
- }
- // Write CMA
- check = (memory[pc] >> 5) & 1;
- if(check == 1) {
- if(placed == 1)
- strcat(str, " ");
- strcat(str, "CMA");
- placed = 1;
- }
- // Write CML
- check = (memory[pc] >> 4) & 1;
- if(check == 1) {
- if(placed == 1)
- strcat(str, " ");
- strcat(str, "CML");
- placed = 1;
- }
- // Write IAC
- check = memory[pc] & 1;
- if(check == 1) {
- if(placed == 1)
- strcat(str, " ");
- strcat(str, "IAC");
- placed = 1;
- }
- // Write Rotate Right (Don't forget to do both)
- one_two = (memory[pc] >> 1) & 1;
- check = (memory[pc] >> 3) & 1;
- if(check == 1) {
- if(placed == 1)
- strcat(str, " ");
- if(one_two == 1)
- strcat(str, "RTR");
- else
- strcat(str, "RAR");
- placed = 1;
- }
- // Write Rotate Left (Don't forget to do both)
- check = (memory[pc] >> 2) & 1;
- if(check == 1) {
- if(placed == 1)
- strcat(str, " ");
- if(one_two == 1)
- strcat(str, "RTL");
- else
- strcat(str, "RAL");
- placed = 1;
- }
- }
- else if(group == 1) {
- // Write SMA
- check = (memory[pc] >> 6) & 1;
- if(check == 1) {
- if(placed == 1)
- strcat(str, " ");
- strcat(str, "SMA");
- placed = 1;
- }
- // Write SZA
- check = (memory[pc] >> 5) & 1;
- if(check == 1) {
- if(placed == 1)
- strcat(str, " ");
- strcat(str, "SZA");
- placed = 1;
- }
- // Write SNL
- check = (memory[pc] >> 4) & 1;
- if(check == 1) {
- if(placed == 1)
- strcat(str, " ");
- strcat(str, "SNL");
- placed = 1;
- }
- // Write RSS
- check = (memory[pc] >> 3) & 1;
- if(check == 1) {
- if(placed == 1)
- strcat(str, " ");
- strcat(str, "RSS");
- placed = 1;
- }
- // Write CLA
- check = (memory[pc] >> 7) & 1;
- if(check == 1) {
- if(placed == 1)
- strcat(str, " ");
- strcat(str, "CLA");
- placed = 1;
- }
- // Write HLT
- check = (memory[pc] >> 1) & 1;
- if(check == 1) {
- if(placed == 1)
- strcat(str, " ");
- strcat(str, "HLT");
- placed = 1;
- }
- }
- else {
- fprintf(stderr, "We have a problem in verbose op 7");
- exit(-1);
- }
- }
- if(indirect == 1) {
- strcat(str, " I");
- indirect = 0;
- }
- fprintf(stderr, "Time %i: PC=0x%03X instruction = 0x%03X (%s), rA = 0x%03X, rL = %i\n", time, pc, memory[pc], str, accumulator, link_bit);
- }
- /* Memory Reference call for the PDP-8 Instructions. Determines if input/direct, */
- /* Zero/Current Page and does all opcodes 0-5, which are AND, TAD, ISZ, DCA, JMS, JMP */
- /* Input: Opcode, which should be 0-5 */
- /* Return: None */
- void simple(short opcode) {
- short check_link = 0;
- short d_i;
- short z_c;
- short address;
- short value;
- // get D/I bit
- d_i = (memory[pc] >> 8) & 1;
- // get Z/C
- z_c = (memory[pc] >> 7) & 1;
- // check if zero or current
- if(z_c == 0)
- address = (memory[pc] & 127);
- else {
- z_c = pc & 3968;
- address = z_c + (memory[pc] & 127);
- }
- // check D/I bit
- if(d_i == 0)
- value = memory[address];
- else {
- address = memory[address];
- value = memory[address];
- indirect = 1;
- }
-
- // ANDING
- if(opcode == 0) {
- accumulator = value & accumulator;
- if(d_i == 0)
- time = time + 2;
- else
- time = time + 3;
- if(mode == 1)
- verbose(opcode);
- }
- // Two's complement add
- if(opcode == 1) {
- accumulator = value + accumulator;
- // if overflow set link to 1
- check_link = (accumulator & (1 << 12)) >> 12;
- accumulator = accumulator & 4095;
- if(check_link == 1)
- link_bit = ~link_bit & 1;
- if(d_i == 0)
- time = time + 2;
- else
- time = time + 3;
- if(mode == 1)
- verbose(opcode);
- }
- // Increment and skip if zero
- if(opcode == 2) {
- // increment
- value++;
- value = value & 4095;
- memory[address] = value;
- if(value == 0)
- skip = 1;
- if(d_i == 0)
- time = time + 2;
- else
- time = time + 3;
- if(mode == 1)
- verbose(opcode);
- }
- // Deposit and clear accumulator
- if(opcode == 3) {
- memory[address] = accumulator;
- accumulator = 0;
- if(d_i == 0)
- time = time + 2;
- else
- time = time + 3;
- if(mode == 1)
- verbose(opcode);
- }
- // jump to subroutine
- if(opcode == 4) {
- if(d_i == 0)
- time = time + 2;
- else
- time = time + 3;
- if(mode == 1)
- verbose(opcode);
- memory[address] = pc + 1;
- pc = address;
- }
- // just jump
- if(opcode == 5) {
- if(d_i == 0)
- time = time + 1;
- else
- time = time + 2;
- if(mode == 1)
- verbose(opcode);
- pc = address - 1;
- }
- }
- /* Device call for the PDP-8 Instructions. Determines if printing to stdout, */
- /* or taking something in from stdin */
- /* Input: Opcode, which should be 6 */
- /* Return: None */
- void devices(short opcode) {
- short device = (memory[pc] & (31 << 3)) >> 3;
- char output;
- time = time + 1;
- // we are reading in from stdin
- if(device == 3) {
- accumulator = getc(stdin);
- accumulator = accumulator & 4095;
- dev = 3;
- }
- // we are outputting to stdout
- else if(device == 4) {
- output = accumulator & 255;
- fprintf(stdout, "%c", output);
- dev = 4;
- }
- else {
- fprintf(stderr, "IOT to unknown device %i; halting\n", device);
- halt = 1;
- }
- if(mode == 1)
- verbose(opcode);
- }
- /* Group 0 for opcode 7 subinstruction. Checks all subinstructions in order: */
- /* CLA, CLL, CMA, CML, IAC, RAR, RTR, RAL, RTL */
- /* Input: None */
- /* Return: None */
- void group0(void) {
- int rotate = 0;
- // clearing the accumulator
- int check = (memory[pc] >> 7) & 1;
- if(check == 1) {
- accumulator = 0;
- }
- // clearing the link bit
- check = (memory[pc] >> 6) & 1;
- if(check == 1) {
- link_bit = 0;
- }
- // complement Accumulator
- check = (memory[pc] >> 5) & 1;
- if(check == 1) {
- accumulator = (accumulator ^ 4095);
- }
- // complement link_bit
- check = (memory[pc] >> 4) & 1;
- if(check == 1) {
- link_bit = ~link_bit & 1;
- }
- // increment Accumulator
- check = (memory[pc] & 1);
- if(check == 1) {
- accumulator = accumulator + 1;
- // do we check for overflow?
- check = (accumulator >> 12) & 1;
- accumulator = accumulator & 4095;
- if(check == 1)
- link_bit = ~link_bit & 1;
- }
- // how many rotations
- check = (memory[pc] >> 1) & 1;
- if(check == 1)
- rotate = 2;
- else
- rotate = 1;
- // rotate Accumulator RIGHT
- check = (memory[pc] >> 3) & 1;
- if(check == 1) {
- rotated = 1;
- while(rotate > 0) {
- link_bit = accumulator & 1;
- accumulator = accumulator >> 1;
- accumulator = accumulator + (link_bit << 11);
- rotate--;
- }
- }
- // rotate Accumulator LEFT
- check = (memory[pc] >> 2) & 1;
- if(check == 1) {
- if(rotated == 1) {
- fprintf(stderr, "Instruction has been rotated. Halting\n");
- halt = 1;
- }
- while(rotate > 0) {
- accumulator = accumulator << 1;
- accumulator = accumulator & 4095;
- accumulator = accumulator + link_bit;
- rotate--;
- }
- }
- time = time + 1;
- }
- /* Group 1 for opcode 7 subinstruction. Checks all subinstructions in order: */
- /* SMA, SZA, SNL, RSS, CMA, OSR (ignored), HLT */
- /* Input: None */
- /* Return: None */
- void group1(void) {
- // check SMA (skip if accumulator is negative number)
- int x;
- int check = (memory[pc] >> 6) & 1;
- if(check == 1) {
- x = (accumulator >> 11) & 1;
- if(x == 1)
- skip = 1;
- }
- // check SZA (skip if zero accumulator)
- check = (memory[pc] >> 5) & 1;
- if(check == 1) {
- if(accumulator == 0)
- skip = 1;
- }
- // check SNL (skip if link_bit is non-zero)
- check = (memory[pc] >> 4) & 1;
- if(check != 0) {
- if(link_bit != 0)
- skip = 1;
- }
- // check RSS (complement skip flag)
- check = (memory[pc] >> 3) & 1;
- if(check == 1) {
- skip = ~skip & 1;
- }
- // clearing the accumulator
- check = (memory[pc] >> 7) & 1;
- if(check == 1)
- accumulator = 0;
- // if OSR (treat as NOP)
- // Halting
- check = (memory[pc] >> 1) & 1;
- if(check == 1) {
- halt = 1;
- }
- time = time + 1;
- }
- /* Operate instruction. Checks whether group 0 or group 1 */
- /* and then sends to corresponding functions */
- /* Input: Opcode, which should be 7 */
- /* Return: None */
- void operate(short opcode) {
- short group = (memory[pc] >> 8) & 1;
- if(group == 0)
- group0();
- else
- group1();
- if(mode == 1)
- verbose(opcode);
- }
- /* Execute fucntion. Gets opcode of instrcution at PC,*/
- /* Then sends to corresponding fucntions. We also increment */
- /* the program counter here, as well as skiping lines. We also halt her */
- /* Input: None */
- /* Return: None */
- void execute(void) {
- short opcode;
- do{
- opcode = ((memory[pc] >> 9) & 7);
- // go to memory reference instructions
- if(opcode <= 5)
- simple(opcode);
- // go to device instructions
- else if(opcode == 6)
- devices(opcode);
- // go to operate instruction
- else
- operate(opcode);
-
- // if we were told to skip in any instruction, increment the pc by 1
- if(skip == 1)
- pc++;
- skip = 0;
- pc++;
- pc = pc & 4095; // makes sure pc always stays within 4095 words
- if(halt == 1)
- exit(0);
- } while(pc <= 4096);
- }
- /* ReadInput Funtion: It reads ascii values and puts them into memory */
- /* Determines if we have found EP or not */
- /* Input: char array, should be of size 3, no more */
- /* Return: returns -1 if ep, else returns hex instruction */
- short readInput(char values[]) {
- int i;
- short total = 0;
- short adder = 0;
- // If we have ep
- if((values[0] == 'E' || values[0] == 'e') && (values[1] == 'P' || values[1] == 'p')) {
- // if we have found the EP for the first time
- if(ep_found == 0) {
- ep_found = 1;
- return -1;
- }
- // if we find another error
- else {
- fprintf(stderr, "Error found: Multiple EP's found. Exiting\n");
- exit(-1);
- }
-
- }
- // we are getting a hex instruction
- else {
- for(i = 0; i < 3; i++) {
- // Get values in upper case hex
- if(values[i] >= 65 && values[i] <= 70)
- adder = values[i] - 55;
- // get values in lower case hex
- else if(values[i] >= 97 && values[i] <= 102)
- adder = values[i] - 87;
- // get ascii numbers
- else if(values[i] >= 48 && values[i] <= 57)
- adder = values[i] - 48;
- // Error in object File
- else {
- fprintf(stderr, "Error in object file: invalid input: %c; exiting\n", values[i]);
- exit(-1);
- }
- adder = (adder << (4 * (2 - i)));
- total = total + adder;
- }
- }
-
- return total;
- }
- /* Readfile Function: Reads the object file given by the command line */
- /* It puts ascii values into a char[] and then sends them to ReadInput. Then it goes to execute*/
- /* Input: File, should not be NULL */
- /* Return: None */
- void readFile(FILE *input) {
- int i = 0;
- // introduce an int to count up how many characters have been put
- // into values
- short address;
- short value;
- char values1[3];
- char values2[3];
- char c = getc(input);
- accumulator = 0;
- skip = 0;
- link_bit = 0;
- // go through file
- while(c != EOF) {
- // get address
- while(c != ':') {
- values1[i] = c;
- i++;
- c = getc(input);
- }
- // if we did get ep or 3 hex numbers, continue
- if((i == 2) || (i == 3))
- address = readInput(values1);
- else {
- fprintf(stderr, "Error in object file. Too many or too few characters in address space. Exiting\n");
- exit(-1);
- }
- i = 0;
- // skip over space
- c = getc(input);
- // if space is not there, we exit
- if(c != ' ') {
- fprintf(stderr, "Error in objec file. No space between : and address field. Exiting\n");
- exit(-1);
- }
- // get next character to read
- c = getc(input);
-
- // get value
- while(c != '\n') {
- values2[i] = c;
- i++;
- c = getc(input);
- }
- if(i != 3) {
- fprintf(stderr, "Error in object file. Not correct amount of characters in value field. Exiting\n");
- exit(-1);
- }
- i = 0;
- value = readInput(values2);
-
- /* Begin putting values into memory */
- // if we found the ep
- if(address == -1)
- pc = value;
- // else we got an address that we need to put a value in
- else
- memory[address] = value;
- c = getc(input);
- }
- execute();
- }
- // scans argument looking for verbose
- void scanargs(char *s) {
- s++;
- if(*s == 'v')
- mode = 1;
- else
- fprintf(stderr, "%c Flag not supported", *s);
- }
- // Main Driver of the program
- int main(int argc, char *argv[]) {
- char *read;
- FILE *input;
- while(argc > 1) {
- argc--, argv++;
- read = *argv;
- if(*read == '-')
- scanargs(read);
- else {
- input = fopen(read, "r");
- if(input == NULL) {
- printf("File did not open; exitting");
- return(-1);
- }
- readFile(input);
- }
- }
- return 0;
- }