/************* NOTE THIS CODE HAS AN UNFIXED BUG! Msg from Dan Kartzman, May 1 2004: I have a quick question about the code in http://cs.nyu.edu/courses/spring04/V22.0202-003/project3/c/out1-d2 that's "./std -d 2 primesx.stm". At machine cycle 104 the last line says "Reading from page 2" there is no page fault and it moves onto the next instruction. However, the last time we see the pagetable at machine process 90, Page 2 is not in memory because it is not addressed to any frame. The results of my code are identical with that of the posted code until Machine Cycle 104. At that point there is a pagefault in my code at page 2. How can you read from a page that is not in memory? That seems to be what is happening here with page 2. If that isn't it, can anyone shed some light on what's going on here? *******************/ #include #include #include /************ CONSTANTS ****************************/ #define VASPACE 262144 /* 2**18 virtual address space */ #define RAMSIZE 65536 /* Size of physical memory */ #define NUMREGS 16 #define NAMESIZE 32 /* maximum size of process name */ #define MAXPROCS 20 /* maximum number of processes */ #define MINPAGESIZE 512 /* minimum size of page */ #define DISKFREQ 4 /* Avg frequency with which the disk handles a request. */ #define MAXFRAMES (RAMSIZE / MINPAGESIZE) /* Maximum number of frames */ #define MAXPAGES (VASPACE / MINPAGESIZE) /* Maximum number of frames */ /************* TYPE DEFINITIONS ******************/ /* Definition of Page Table Entry */ struct pte { int frame, /* Corresponding frame in RAM */ disk, /* Location on simulated "disk" */ rbit, mbit, timestamp; }; /* Definition of Process Table Entry */ struct process { /* entry in process table */ char name[NAMESIZE]; struct pte pagetable[MAXPAGES]; int regs[NUMREGS]; int status; /* 0 if ready, 1 if blocked, 2 if terminated */ }; /* Definition of FIFO queue */ struct fifo {int front, back, data[MAXPROCS+1];}; /* Definition of DiskTask, the data structure used to communicate between the simulated disk and the CPU. */ struct DiskTask { int diskAddress, /* Address on disk */ memAddress, /* Address in memory */ write; /* 1 if write to disk, 0 if read */ }; /***** Definition of InvTableEntry, an entry in the inverted page table ***/ struct InvTableEntry { int page, process, /* page and process currently in frame */ holdingPage, holdingProcess; /* page and process that will be loaded */ }; /* into frame */ /********************* GLOBAL VARIABLES ***********************/ /* Global variables for the simulated architecture --- DO NOT CHANGE */ int mem[RAMSIZE], /* Core memory */ regs[NUMREGS], /* Number of registers */ disk[MAXPROCS * VASPACE]; char codes[16][4] = /* Abbreviations for opcodes */ { "LOA", "STO", "CPR", "LOI", "STI", "ADD", "SUB", "MUL", "DIV", "ICR", "DCR", "GTR", "JMP", "IFZ", "JMI", "TRP" }; struct fifo readyq; /* queue of processes */ struct process proctable[MAXPROCS]; /* process table */ struct pte pagetable[MAXPAGES]; /* Page table for current process */ struct InvTableEntry InvTable[MAXFRAMES]; /* Inverted page table */ int NPAGES, /* Number of pages */ NFRAMES = 8, /* Number of frames */ PAGESIZE; /* Size of page */ /* Other global variables */ int debug = 0, /* Level of debugging */ error = 0, /* Error flag */ terminate = 0, /* Termination flag */ finished = 0, /* Flag that all process are done */ idle = 0, /* Flag that all processes are idle */ maxinst = -1, /* Maximum number of instructions */ procindex = 0, /* Index of active process */ stmclock = 0, /* Global clock */ PageFault = -1; /* the page that has faulted; -1 if no page fault */ char procname[NAMESIZE]; int quantum = 5, /* Quantum */ qleft, /* Time left in quantum */ nprocs; /* Number of processes */ int replacealg = 0; /* 0 if global, 1 if local */ int freeList[MAXFRAMES]; /* free list of frames: 1 if occupied, 0 if free. */ struct DiskTask Requests[MAXPROCS]; /* Array of Disk Requests */ int NRequests; /* Number of requests in Requests */ /***************** Queue Management Utility ****************/ void initqueue (queue) struct fifo *queue; { int i; for (i=0; idata[i] = 0; queue->front = 0; queue->back = 0; } void addqueue(queue,i) struct fifo *queue; int i; { queue->data[queue->back]= i; queue->back = (queue->back+1) % (MAXPROCS+1); if (queue->back==queue->front) printf(" QUEUE OVERFLOW\n"); } int emptyqueue(queue) struct fifo *queue; { return(queue->front == queue->back); } int popqueue(queue) struct fifo *queue; { int z; if (emptyqueue(queue)) return(-1); else { z = queue->data[queue->front]; queue->front = (queue->front+1)%(MAXPROCS+1); return(z); } } /********************* Code for Simulated Disk ****************/ void initDisk() { int i; for (i=0; i < MAXPROCS*VASPACE; i++) disk[i]=0; for (i=0; i < MAXPROCS; i++) Requests[i].write = -1; NRequests = 0; } /* Post a request to the disk. We use the fact that any process can post only one request at a time to index requests by process in the array Requests. */ void PostRequest(proc, da, ad, wr) int proc, da, ad, wr; { Requests[proc].diskAddress = da; Requests[proc].memAddress = ad; Requests[proc].write = wr; NRequests++; } /* Read from disk to memory */ void DiskRead(n) int n; { int da, ad, j; ad = Requests[n].memAddress; da = Requests[n].diskAddress; if (debug) printf("Reading from disk address %i to RAM address %i\n", da, ad); for (j=0; j= 0) && (reladd < VASPACE)) { PageFault = -1; page = reladd / PAGESIZE; frame = pagetable[page].frame; pagetable[page].rbit = 1; if (write) pagetable[page].mbit = 1; if (debug==2) { if (write) printf("Writing to page %i\n", page); else printf("Reading from page %i\n", page); } pagetable[page].timestamp = stmclock; if (frame == -1) { PageFault = page; return (-1); } else return(frame*PAGESIZE + reladd % PAGESIZE); } else { error = 1; printf("Error: Address out of bounds\n"); return(0); } } /* Display STM instruction for level-2 debugging */ void show_inst(op, ra, ad, rb, rc, rd) int op, ra, ad, rb, rc, rd; { printf("Process %i %s instruction 0x%X : %3s", procindex, procname, regs[0], codes[op]); switch(op) { case 0: case 1: case 13: printf(" R%i Address 0x%X", ra, ad); break; case 12: printf(" Address 0x%X", ad); break; case 2: case 3: case 4: printf(" R%i R%i", ra, rb); break; case 5: case 6: case 7: case 11: printf(" R%i R%i R%i", ra, rb, rc); break; case 8: printf(" R%i R%i R%i R%i", ra, rb, rc, rd); break; case 9: case 10: case 14: printf(" R%i ", ra); break; } printf("\n"); } /* Decompose an STM instruction into its components */ /* Note: This is considered part of the "hardware" of the virtual machine. You may not change it in any of the projects. */ void get_inst(inst, pop, pra, pad, prb, prc, prd) int inst, *pop, *pra, *pad, *prb, *prc, *prd; { *pop = inst % 16; inst = inst / 16; *pra = inst % 16; inst = inst / 16; *pad = inst % RAMSIZE; *prb = inst % 16; inst = inst / 16; *prc = inst % 16; inst = inst / 16; *prd = inst % 16; if (debug == 2) show_inst(*pop, *pra, *pad, *prb, *prc, *prd); } /* Execute an STM instruction. This is what does the actual work of carrying out the STM code */ /* Note: This is considered part of the "hardware" of the virtual machine. You may not change it in any of the projects. */ int exec_inst(op, ra, ad, rb, rc, rd) int op, ra, ad, rb, rc, rd; { int trap = 0, jump = 0, pa; switch (op) { case 0: pa = phys_address(ad,0); if (PageFault == -1) regs[ra] = mem[pa]; break; case 1: pa = phys_address(ad,1); if (PageFault == -1) mem[pa] = regs[ra]; break; case 2: regs[ra] = regs[rb]; break; case 3: pa = phys_address(regs[rb],0); if (PageFault == -1) regs[ra] = mem[pa]; break; case 4: pa = phys_address(regs[ra],1); if (PageFault == -1) mem[pa] = regs[rb]; break; case 5: regs[rc] = regs[ra] + regs[rb]; break; case 6: regs[rc] = regs[ra] - regs[rb]; break; case 7: regs[rc] = regs[ra] * regs[rb]; break; case 8: if (regs[rb] == 0) { printf("Arithmetic error: Divide by zero\n"); error = 1; } else { regs[rc] = regs[ra] / regs[rb]; regs[rd] = regs[ra] % regs[rb]; } break; case 9: regs[ra]++; break; case 10: regs[ra]--; break; case 11: regs[rc] = (regs[ra] > regs[rb]); break; case 12: regs[0] = ad; jump = 1; break; case 13: if (regs[ra] == 0) {regs[0] = ad; jump=1;} break; case 14: regs[0] = regs[ra]; break; case 15: trap = 1; break; } stmclock++; if (!jump && (PageFault == -1)) regs[0]++; return(trap); } /********************* OPERATING SYSTEM **************************/ /* freeFrame returns an index of the first free frame and marks it as no longer free. If no frames are free, it returns -1. */ int freeFrame() { int i; for (i = 0; i < NFRAMES; i++) if (!freeList[i]) { freeList[i] = 1; return(i); } return(-1); } /***************** Extract flags from command line **************/ int parse_flags(argc,argv) int argc; char *argv[]; { int iquantum= 0, idebug = 0, imax=0, ialg=0, iframe=0, ifilename=1; /* Positions of arguments in command line */ int i; for (i=1; i<9; i=i+2) { if (argv[i][0] == '-') switch (argv[i][1]) { case 'q': iquantum= i+1; break; case 'd': idebug = i+1; break; case 'm': imax = i+1; break; case 'a': ialg = i+1; break; case 'f': iframe = i+1; break; } else { ifilename = i; break; } } if (iquantum) quantum=atoi(argv[iquantum]); if (idebug) debug=atoi(argv[idebug]); if (imax) maxinst=atoi(argv[imax]); if (ialg) replacealg = (argv[ialg][0] == 'G'); if (iframe) NFRAMES=atoi(argv[iframe]); return(ifilename); } void init_pagetable(pagetable) struct pte pagetable[]; { int i; for (i=0; i < NPAGES; i++) { pagetable[i].frame = -1; pagetable[i].disk = -1; pagetable[i].rbit = 0; pagetable[i].mbit = 0; } } /* Load the STML code into memory */ /* It is assumed that STML files are correctly formatted; therefore, this does no error checking */ /* NOTE: You are allowed to change this function for project 1; however, there is no need to do so. */ void load_stm(filename) char filename[]; { int offset = PAGESIZE, /* Address */ inst; /* Instruction */ char line[240]; /* max length of line in STM file */ int page = 0, frame, address; int i, va=0; FILE *fp; fp=fopen(filename, "r"); /* Open the STM file */ if (fp == NULL) { printf("File name error %s\n", filename); error = 1; } fgets(procname, NAMESIZE, fp); /* read process name */ procname[strlen(procname)-1] = '\0'; /* get rid of carriage return at end */ fgets(line,240,fp); /* read length of partition; not used */ if (debug == 2) { printf("Process %s index %i loading\n", procname, nprocs); printf("Physical address / Virtual address / Instruction\n"); } while (!feof(fp)) { /* read code and load into memory */ fgets(line,240,fp); if (isdigit(line[0])) { if (offset == PAGESIZE) { /* Start new page for program text */ frame = freeFrame(); address = frame * PAGESIZE; offset = 0; proctable[nprocs].pagetable[page].frame = frame; proctable[nprocs].pagetable[page].mbit = 1; InvTable[frame].page = page; InvTable[frame].process = nprocs; InvTable[frame].holdingPage = InvTable[frame].holdingProcess = -1; if (debug == 2) printf("Loading page %i into frame %i\n", page, frame); page++; } sscanf(line, "%i", &mem[address]); if (debug==2) printf("Ox%x 0x%x 0x%x\n",address, va, mem[address]); offset++; address++; va++; } } fclose(fp); } /* Load the STM files into memory, and initialize process table */ void load_procs(ifilename, argc, argv) int ifilename, argc; char *argv[]; { int i,j; initqueue(&readyq); init_pagetable(pagetable); nprocs=0; for (i=ifilename; i < argc; i++) { init_pagetable(proctable[nprocs].pagetable); load_stm(argv[i]); strcpy(proctable[nprocs].name, procname); for (j=0; j < NUMREGS; j++) proctable[nprocs].regs[j] = 0; addqueue(&readyq,nprocs); nprocs++; } } /* resumes a new process by resetting registers, other global variables */ void activate_proc(p) int p; { int i; for (i=0; i