WRITTEN IN C LANGUAGE MUST ACCEPT FILE NAME VIA COMMAND LINE ARGUMENT SO ARGV WI
ID: 3818590 • Letter: W
Question
WRITTEN IN C LANGUAGE
MUST ACCEPT FILE NAME VIA COMMAND LINE ARGUMENT SO ARGV WILL PROBABLY BE USED
The P-machine:
In this assignment, you will implement a virtual machine (VM) known as the P-machine (PM/0). The P-machine is a stack machine with two memory stores: the “stack,” which is organized as a stack and contains the data to be used by the PM/0 CPU, and the “code,” which is organized as a list and contains the instructions for the VM. The PM/0 CPU has four registers. The registers are named base pointer (BP), stack pointer (SP), program counter (PC) and instruction register (IR). They will be explained in detail later on in this document.
The Instruction Set Architecture (ISA) of the PM/0 has 23 instructions and the instruction format is as follows: “OP L M”
Each instruction contains three components (OP, L, M) that are separated by one space.
OP is the operation code.
L indicates the lexicographical level.
M depending of the operators it indicates:
- A number (instructions: LIT, INC).
- A program address (instructions: JMP, JPC, CAL).
- A data address (instructions: LOD, STO)
- The identity of the operator OPR
(e.g. OPR 0, 2 (ADD) or OPR 0, 4 (MUL)).
The list of instructions for the ISA can be found in Appendix A and B.
P-Machine Cycles
The PM/0 instruction cycle is carried out in two steps. This means that it executes two steps for each instruction. The first step is the Fetch Cycle, where the actual instruction is fetched from the “code” memory store. The second step is the Execute Cycle, where the instruction that was fetched is executed using the “stack” memory store. This does not mean the instruction is stored in the “stack.”
Fetch Cycle:
In the Fetch Cycle, an instruction is fetched from the “code” store and placed in the IR register (IR code[PC]). Afterwards, the program counter is incremented by 1 to point to the next instruction to be executed (PC PC + 1).
Execute Cycle:
In the Execute Cycle, the instruction that was fetched is executed by the VM. The OP component that is stored in the IR register (IR.OP) indicates the operation to be executed. For example, if IR.OP is the ISA instruction OPR (IR.OP = 02), then the M component of the instruction in the IR register (IR.M) is used to identify the operator and execute the appropriate arithmetic or logical instruction.
PM/0 Initial/Default Values:
Initial values for PM/0 CPU registers:
SP = 0;
BP = 1;
PC = 0;
IR = 0;
Initial “stack” store values: We just show the first three stack locations:
stack[1] =0;
stack[2] =0;
stack[3] =0;
Constant Values:
MAX_STACK_HEIGHT is 2000
MAX_CODE_LENGTH is 500
MAX_LEXI_LEVELS is 3
Assignment Instructions and Guidelines:
1. The VM must be written in C and must run on Eustis.
2. Submit to Webcourses:
a) A readme document indicating how to compile and run the VM.
b) The source code of your PM/0 VM.
c) The output of a test program running in the virtual machine. Please provide a copy of the initial state of the stack and the state of stack after the execution of each instruction. Please see the example in Appendix C.
Appendix A
Instruction Set Architecture (ISA)
There are 13 arithmetic/logical operations that manipulate the data within stack. These operations are indicated by the OP component = 2 (OPR). When an OPR instruction is encountered, the M component of the instruction is used to select the particular arithmetic/logical operation to be executed (e.g. to multiply the two elements at the top of the stack, write the instruction “2 0 4”).
ISA:
01 – LIT0, MPush constant value (literal) M onto the stack
02 – OPR0, MOperation to be performed on the data at the top of the stack
(detailed in Appendix B)
03 – LODL, MLoad value to top of stack from the stack location at offset M from
L lexicographical levels down
04 – STOL, MStore value at top of stack in the stack location at offset M from
L lexicographical levels down
05 – CALL, MCall procedure at code index M (generates new Activation Record
and pc M)
06 – INC0, MAllocate M locals (increment sp by M). First three are Static Link
(SL), Dynamic Link (DL), and Return Address (RA)
07 – JMP0, MJump to instruction M
08 – JPC0, MJump to instruction M if top stack element is 0
09 – SIO0, 1Write the top stack element to the screen
09 – SIO0, 2Read in input from the user and store it at the top of the stack
09 – SIO0, 3Halt = False (stop CPU)
Appendix B
ISA Pseudo Code
01 – LIT 0, M sp sp + 1;
stack[sp] M;
02 – OPR 0, # ( 0 # 13 )
0 RET (sp bp -1 and pc stack[sp + 4] and bp stack[sp + 3])
1 NEG(-stack[sp])
2 ADD (sp sp – 1 and stack[sp] stack[sp] + stack[sp + 1])
3 SUB (sp sp – 1 and stack[sp] stack[sp] - stack[sp + 1])
4 MUL (sp sp – 1 and stack[sp] stack[sp] * stack[sp + 1])
5 DIV (sp sp – 1 and stack[sp] stack[sp] / stack[sp + 1])
6 ODD(stack[sp] stack[sp] mod 2) or ord(odd(stack[sp]))
7 MOD(sp sp – 1 and stack[sp] stack[sp] mod stack[sp + 1])
8 EQL (sp sp – 1 and stack[sp] stack[sp] = = stack[sp + 1])
9 NEQ (sp sp – 1 and stack[sp] stack[sp] != stack[sp + 1])
10 LSS (sp sp – 1 and stack[sp] stack[sp] < stack[sp + 1])
11 LEQ (sp sp – 1 and stack[sp] stack[sp] <= stack[sp + 1])
12 GTR (sp sp – 1 and stack[sp] stack[sp] > stack[sp + 1])
13 GEQ (sp sp – 1 and stack[sp] stack[sp] >= stack[sp + 1])
03 – LOD L, M sp sp + 1;
stack[sp] stack[ base(L, bp) + M];
04 – STO L, M stack[ base(L, bp) + M] stack[sp];
sp sp - 1;
05 - CAL L, M stack[sp + 1] 0/* space to return value
stack[sp + 2] base(L, bp); /* static link (SL)
stack[sp + 3] bp;/* dynamic link (DL)
stack[sp + 4] pc /* return address (RA)
bp sp + 1;
pc M;
06 – INC 0, M sp sp + M;
07 – JMP 0, M pc M;
08 – JPC 0, M if stack[sp] == 0 then {
pc M;
}
sp sp - 1;
09 – SIO 0, 1 print(stack[sp]);
sp sp – 1;
09 - SIO 0, 2sp sp + 1;
read(stack[sp]);
09- SIO 0, 3halt = false;
NOTE: The result of a logical operation such as (A > B) is defined as 1 if
the condition was met and 0 otherwise.
Appendix C
Example of Execution
This example shows how to print the stack after the execution of each instruction. The following PL/0 program, once compiled, will be translated into a sequence code for the virtual machine PM/0 as shown below in the INPUT FILE.
const n = 13;
int i,h;
procedure sub;
const k = 7;
int j,h;
begin
j:=n;
i:=1;
h:=k;
end;
begin
i:=3; h:=0;
call sub;
end.
INPUT FILE
For every line, there must be 3 integers representing OP, Land M.
7 0 10
7 0 2
6 0 6we recommend using the following structure for your instructions:
1 0 13
4 0 4struct {
1 0 1 int op; /* opcode
4 1 4 int l; /* L
1 0 7 int m; /* M
4 0 5}instruction;
2 0 0
6 0 6
1 0 3
4 0 4
1 0 0
4 0 5
5 0 2
9 0 3
OUTPUT FILE
1) Print out the program in interpreted assembly language with line numbers:
LineOPLM
0 jmp010
1 jmp02
2 inc06
3 lit013
4 sto04
5 lit01
6 sto14
7 lit07
8 sto05
9 opr00
10 inc06
11 lit03
12 sto04
13 lit00
14 sto05
15 cal02
16 sio03
2) Print out the execution of the program in the virtual machine, showing the stack and registers pc, bp, and sp:
pcbpspstack
Initial values010
0jmp0101010
10inc0611160 0 0 0 0 0
11lit0312170 0 0 0 0 0 3
12sto0413160 0 0 0 3 0
13lit0014170 0 0 0 3 0 0
14sto0515160 0 0 0 3 0
15cal022760 0 0 0 3 0 | 0 1 1 16
2inc0637120 0 0 0 3 0 | 0 1 1 16 0 0
3lit01347130 0 0 0 30 | 0 1 1 16 0 0 13
4sto0457120 0 0 0 3 0 | 0 1 1 16 13 0
5lit0167130 0 0 0 3 0 | 0 1 1 16 13 0 1
6sto1477120 0 0 0 1 0 | 0 1 1 16 13 0
7lit0787130 0 0 0 1 0 | 0 1 1 16 13 0 7
8sto0597120 0 0 0 1 0 | 0 1 1 16 13 7
9opr0016160 0 0 0 1 0
16sio03000
NOTE: It is necessary to separate each Activation Record with a bracket “|”.
Appendix D
Helpful Tips
This function will be helpful to find a variable in a different Activation Record some L levels down:
/**********************************************/
/*Find base L levels down */
/* */
/**********************************************/
int base(l, base) // l stand for L in the instruction format
{
int b1; //find base L levels down
b1 = base;
while (l > 0)
{
b1 = stack[b1 + 1];
l--;
}
return b1;
}
For example in the instruction:
STO L, M - you can do stack[base(ir[pc].L, bp) + ir[pc].M] = stack[sp] to store a variable L levels down.
Explanation / Answer
Let me know how below code work. I believe it should work as expected. All the best!
//Include necessary header files.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<strings.h>
//Declare maximum values for inputs/code.
#define MAX_STACK_HEIGHT 2000
#define MAX_CODE_LENGTH 500
#define MAX_LEX_LEVELS 3
//Declaring a struct that will hold the separate fields for a line of code
//utilizing format: OP R L M.
//OP - Operation Code, R - Register, L - Lexicographical Level
//M - Operation Data (depends on specific Operation)
struct instruction{
int OP, R, L, M;};
//Declare + Initialize the Program Counter, Instruction Register,
//Base Pointer, and Stack Pointer to their initial values.
int pc, sp = 0;
int bp = 1;
//Initialize the stack.
int stack[MAX_STACK_HEIGHT] = {0};
//Declare CPU Registers
int r[16] = {0};
//Declare Halt flag. Initialize to zero (do not halt).
int halt = 0;
//Declare input and output files
FILE *ifp;
FILE *ofp;
void print(int cnt);
void fetch();
void execute();
int base(int L, int base);
void printStack( int flag);
//Initialize our array of code. This will hold all the code we execute for the program.
struct instruction code[MAX_CODE_LENGTH];
//Declare the instruction register.
struct instruction ir;
//Main function
int VM(int flag){
//Open input and output files
ifp = fopen("code.txt", "r");
ofp = fopen("output.txt", "w");
//If the file isn't there or could not open properly, end the program.
if(ifp == NULL){
printf("File could not open. Program halted. ");
return;
}
//Keep track of number of instructions the input file.
int cnt = 0;
//Read in the lines from the input file.
while(!feof(ifp))
{ fscanf(ifp, "%d", &code[cnt].OP);
fscanf(ifp, "%d", &code[cnt].R);
fscanf(ifp, "%d", &code[cnt].L);
fscanf(ifp, "%d", &code[cnt].M);
cnt++;
}
//Call our initial printing function named "print".
print(cnt);
cnt = 0;
//Print the column headers for the stack tracing
if(flag){
printf(" Execution of Program: ");
printf(" Initial Values pc bp sp ");
}
fprintf(ofp, " Execution of Program: ");
fprintf(ofp, " Initial Values pc bp sp ");
//Fetch - Execute Cycle. Runs until the halt flag is set to stop the loop.
while(halt == 0){
//Start the fetch part of the fetch-execute cycle.
fetch();
//Start the execution process of the
execute();
if(flag){
printf("%d %d %d ", ir.R, ir.L, ir.M);
printf("%d %d %d ", pc, bp, sp);
}
fprintf(ofp, "%d %d %d ", ir.R, ir.L, ir.M);
fprintf(ofp, "%d %d %d ", pc, bp, sp);
printStack(flag);
if(( (pc==0) && (bp==0) && (sp==0) ))
halt = 1;
}
//Close files.
fclose(ifp);
fclose(ofp);
//End main function.
return;
}
//Pre: Print takes in the number of instructions in the code array.
//Post: The OP codes (operation code) of all instructions will be
// interpreted and the input code as a whole will be printed out to the
// output file designated for the entire program.
void print(int cnt){
int i;
fprintf(ofp, "Interpreted Assembly Language ");
fprintf(ofp, " Line OP R L M");
for(i=0; i<cnt; i++){
int op = code[i].OP;
//Interpret the operation.
switch(op){
case 1: fprintf(ofp, " %d ", i); fprintf(ofp, "lit "); break;
case 2: fprintf(ofp, " %d ", i); fprintf(ofp, "rtn "); break;
case 3: fprintf(ofp, " %d ", i); fprintf(ofp, "lod "); break;
case 4: fprintf(ofp, " %d ", i); fprintf(ofp, "sto "); break;
case 5: fprintf(ofp, " %d ", i); fprintf(ofp, "cal "); break;
case 6: fprintf(ofp, " %d ", i); fprintf(ofp, "inc "); break;
case 7: fprintf(ofp, " %d ", i); fprintf(ofp, "jmp "); break;
case 8: fprintf(ofp, " %d ", i); fprintf(ofp, "jpc "); break;
case 9: fprintf(ofp, " %d ", i); fprintf(ofp, "sio "); break;
case 10:fprintf(ofp, " %d ", i); fprintf(ofp, "sio "); break;
case 11:fprintf(ofp, " %d ", i); fprintf(ofp, "sio "); break;
case 12:fprintf(ofp, " %d ", i); fprintf(ofp, "neg "); break;
case 13:fprintf(ofp, " %d ", i); fprintf(ofp, "add "); break;
case 14:fprintf(ofp, " %d ", i); fprintf(ofp, "sub "); break;
case 15:fprintf(ofp, " %d ", i); fprintf(ofp, "mul "); break;
case 16:fprintf(ofp, " %d ", i); fprintf(ofp, "div "); break;
case 17:fprintf(ofp, " %d ", i); fprintf(ofp, "odd "); break;
case 18:fprintf(ofp, " %d ", i); fprintf(ofp, "mod "); break;
case 19:fprintf(ofp, " %d ", i); fprintf(ofp, "eql "); break;
case 20:fprintf(ofp, " %d ", i); fprintf(ofp, "neq "); break;
case 21:fprintf(ofp, " %d ", i); fprintf(ofp, "lss "); break;
case 22:fprintf(ofp, " %d ", i); fprintf(ofp, "leq "); break;
case 23:fprintf(ofp, " %d ", i); fprintf(ofp, "gtr "); break;
case 24:fprintf(ofp, " %d ", i); fprintf(ofp, "geq "); break;
default: return;
}
//Print the three other fields: R, L, M.
fprintf(ofp, "%d ", code[i].R);
fprintf(ofp, "%d ", code[i].L);
fprintf(ofp, "%d ", code[i].M);
}
return;
}
//Fetch retrieves the instruction to be executed, then
void fetch(){
//Fetch current instruction
ir = code[pc];
//Print the program counter before it's incremented.
fprintf(ofp, "%d ", pc);
//Increment the Program Counter before we start execution.
//Program Counter points to the NEXT instruction.
pc++;
//Return to main function.
return;
}
void execute(){
switch(ir.OP){
//LIT
case 1:
fprintf(ofp, "lit ");
r[ir.R] = ir.M;
break;
//RTN
case 2:
fprintf(ofp, "rtn ");
sp = bp -1;
bp = stack[sp+3];
pc = stack[sp+4];
break;
//LOD
case 3:
fprintf(ofp, "lod ");
r[ir.R] = stack[base(ir.L, bp) + ir.M];
break;
//STO
case 4:
fprintf(ofp, "sto ");
stack[ base(ir.L, bp) + ir.M] = r[ir.R];
break;
//CAL
case 5:
fprintf(ofp, "cal ");
stack[sp+1] = 0;
stack[sp+2] = base(ir.L, bp);
stack[sp+3] = bp;
stack[sp+4] = pc;
bp = sp+1;
pc = ir.M;
break;
//INC
case 6:
fprintf(ofp, "inc ");
sp = sp + ir.M;
break;
//JMP
case 7:
fprintf(ofp, "jmp ");
pc = ir.M;
break;
//JPC
case 8:
fprintf(ofp, "jpc ");
if(r[ir.R]==0)
pc = ir.M;
break;
//SIO - write register to screen
case 9:
fprintf(ofp, "sio ");
printf(" R[%d] = %d ", ir.R, r[ir.R]);
break;
//SIO - read in value from screen to register.
case 10:
fprintf(ofp, "sio ");
printf(" Please type in the number you wish to store in the register. Press enter when finished. ");
scanf("%d", &r[ir.R]);
break;
//SIO - set halt flag to 1.
case 11:
fprintf(ofp, "sio ");
halt = 1;
break;
//NEG
case 12:
fprintf(ofp, "neg ");
r[ir.R] = 0 - r[ir.L];
break;
//ADD
case 13:
fprintf(ofp, "add ");
r[ir.R] = r[ir.L] + r[ir.M];
break;
//SUB
case 14:
fprintf(ofp, "sub ");
r[ir.R] = r[ir.L] - r[ir.M];
break;
//MUL
case 15:
fprintf(ofp, "mul ");
r[ir.R] = r[ir.L] * r[ir.M];
break;
//DIV
case 16:
fprintf(ofp, "div ");
r[ir.R] = ((r[ir.L])/(r[ir.M]));
break;
//ODD
case 17:
fprintf(ofp, "odd ");
r[ir.R] = r[ir.R]%2;
break;
//MOD
case 18:
fprintf(ofp, "mod ");
r[ir.R] = (r[ir.L])%(r[ir.M]);
break;
//EQL
case 19:
fprintf(ofp, "eql ");
if(r[ir.L]==r[ir.M])
r[ir.R]=1;
else
r[ir.R]=0;
break;
//NEQ
case 20:
fprintf(ofp, "neq ");
if(r[ir.L]!=r[ir.M])
r[ir.R]=1;
else
r[ir.R]=0;
break;
//LSS
case 21:
fprintf(ofp, "lss ");
if(r[ir.L]<r[ir.M])
r[ir.R]=1;
else
r[ir.R]=0;
break;
//LEQ
case 22:
fprintf(ofp, "leq ");
if(r[ir.L]<=r[ir.M])
r[ir.R]=1;
else
r[ir.R]=0;
break;
//GTR
case 23:
fprintf(ofp, "gtr ");
if(r[ir.L]>r[ir.M])
r[ir.R]=1;
else
r[ir.R]=0;
break;
//GEQ
case 24:
fprintf(ofp, "geq ");
if(r[ir.L]>=r[ir.M])
r[ir.R]=1;
else
r[ir.R]=0;
break;
default:
fprintf(ofp, "err ");
return;
}
return;
}
int base(int L, int base){
int b1; //Find base L levels down
b1 = base;
while(L>0){
b1 = stack[b1 + 1];
L--;
}
return b1;
}
void printStack(int flag){
if(bp==0){
return;
}
else{
int i;
for(i=1; i<=sp; i++){
if(flag)
printf("%d ", stack[i]);
fprintf(ofp, "%d ", stack[i]);
}
if(flag)
printf(" ");
fprintf(ofp, " ");
return;
}
}
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.