The homework deals with implementing a simulator for a simplified MIPS computer using C. The program loads a MIPS assembly program and simulates its execution trace through the pipeline stages. The program can simulate data forwarding and stall due to data or control hazards. Have a look at the following solution where our C programming homework help doers demonstrate MIPS computer simulation.
Simulating Forwarding and Pipelining Processes in MIPS and C Programming
Source Code
#include
#include
#include
#include
#define MAX_LABEL_LEN 32
#define MAX_LABELS 100
#define MAX_INSTRUCTIONS 1000
#define MAX_MEMORY 32
#define MAX_OP_LINE 50
#define MAX_LINE 100
#define I_CACHE_BLOCKS 4
#define I_CACHE_BLKSIZE 8
#define D_CACHE_BLOCKS 4
#define D_CACHE_BLKSIZE 4
#define MEM_DELAY 3
#define WRITE_BUFFER_SIZE 100
enum
{
INVALID=-1, NOP=0, J, BEQ, BNE, LI,
AND, ANDI, OR, ORI, LW, SW, ADD,
ADDI, SUB, SUBI, MULT, MULTI, HLT
};
enum {
IF_ID, ID_EX1, EX1_EX2, EX2_EX3, EX3_MEM, MEM_WB, LAST
};
char *instructions[] =
{
"NOP", "J", "BEQ", "BNE", "LI", "AND", "ANDI", "OR", "ORI",
"LW", "SW", "ADD", "ADDI", "SUB", "SUBI", "MULT", "MULTI", "HLT"
};
int ninstructions = 18;
typedef struct
{
char name[MAX_LABEL_LEN];
int addr;
}label_t;
typedef struct
{
int label;
int opcode;
int rdest;
int rsrc;
int rsrc2;
int imm;
int addr;
int ex_stages;
int wb;
int mem_rd;
int mem_wr;
int mem_data;
int mem_addr;
int PC;
int rsrc_req;
int rsrc2_req;
int rsrc_val;
int rsrc2_val;
int rdest_val;
int if_cycle;
int id_cycle;
int ex_cycle;
int mem_cycle;
int wb_cycle;
int stalled;
}inst_t;
inst_t nop;
/* Label table*/
label_t labels[MAX_LABELS];
int nlabels;
/* Instruction table */
inst_t inst_table[MAX_INSTRUCTIONS];
int ninst;
/* register file */
int registers[32];
/* Data memory */
int memory[MAX_MEMORY];
int mem_size;
/* cache definitions */
typedef struct
{
int valid;
int tag;
inst_t data[I_CACHE_BLKSIZE];
}i_cache_entry_t;
typedef struct
{
int valid;
int tag;
int data[D_CACHE_BLKSIZE];
}d_cache_entry_t;
/* instruction cache */
i_cache_entry_t i_cache[I_CACHE_BLOCKS];
int i_cache_accesses = 0;
int i_cache_hits = 0;
int i_cache_reading = 0;
int i_cache_index;
int i_cache_offset;
int i_cache_mem_addr;
/* data cache */
d_cache_entry_t d_cache[D_CACHE_BLOCKS];
int d_cache_accesses = 0;
int d_cache_hits = 0;
int d_cache_reading = 0;
int d_cache_index;
int d_cache_offset;
int d_cache_mem_addr;
int d_cache_writing = 0;
int d_cache_index_w;
int d_cache_offset_w;
int d_cache_mem_addr_w;
/* Write buffer */
typedef struct
{
int addr;
int data;
}buffer_entry_t;
buffer_entry_t write_buffer[WRITE_BUFFER_SIZE];
int buffer_pos = 0;
int buffer_updating = 0;
/* Instruction statistics */
typedef struct
{
int pos;
char line[MAX_LINE];
}stats_entry_t;
stats_entry_t stats[MAX_INSTRUCTIONS];
int n_stats = 0;
/* Remove whitespace at start and end of string */
char *trim(char *str)
{
char *ptr = str, *end;
while (*ptr && isspace(*ptr))
ptr++;
if (!(*ptr))
return ptr;
end = &str[strlen(str) - 1];
while(end != ptr && isspace(*end))
end--;
end[1] = 0;
return ptr;
}
/* Convert string to uppercase */
void str_to_upper(char *str)
{
char *ptr = str;
while(*ptr)
{
*ptr = toupper(*ptr);
ptr++;
}
}
/* get the pointer to the first space after the current word, inserts a zero
at the end of the word to separate it from the next one */
char *get_next_word(char *str)
{
char *ptr = str;
while(*ptr && !isspace(*ptr))
ptr++;
if (*ptr)
*(ptr++) = 0;
return ptr;
}
/* make a first pass on the input file by loading all labels on a label table */
void first_pass(FILE *input)
{
char buffer[BUFSIZ], *line;
int nline = 0;
while (!feof(input))
{
if (fgets(buffer, BUFSIZ, input))
{
line = trim(buffer);
if (line[0])
{
get_next_word(line);
if (line[strlen(line) - 1] == ':')
{
line[strlen(line) - 1] = 0;
strcpy(labels[nlabels].name, line);
labels[nlabels].addr = nline;
nlabels++;
}
nline++;
}
}
}
}
/* parse the operands for the instruction, which are separated by commas,
returns the number of operands or -1 if they are invalid or more than 3 */
int parse_operand(char *oper, char *operands[])
{
char *token;
int ntokens = 0;
token = strtok(oper, ",");
while(token)
{
if (ntokens >= 3)
return -1;
operands[ntokens] = trim(token);
ntokens++;
token = strtok(NULL, ",");
}
return ntokens;
}
/* Search for an instruction in the instruction table and returns the opcode */
int search_instruction(char *inst)
{
int i;
int opcode = INVALID;
for (i = 0; i < ninstructions; i++)
if (!strcmp(inst, instructions[i]))
{
opcode = i;
break;
}
return opcode;
}
/* Search for a label in the label table and returns the address */
int search_label(char *label)
{
int i;
int addr = INVALID;
for (i = 0; i < nlabels; i++)
if (!strcmp(label, labels[i].name))
{
addr = i;
break;
}
return addr;
}
/* checks if the string is a valid number, returns 1 if valid, 0 otherwise */
int valid_number(char *str)
{
char *ptr = str;
if (*ptr == '-')
{
str++;
ptr++;
}
while(*ptr)
{
if (!isdigit(*ptr))
return 0;
ptr++;
}
if (ptr != str)
return 1;
else
return 0;
}
/* Validates the string by checking if it corresponds to a valid register name */
int validate_register(char *sreg)
{
int reg = INVALID;
if (sreg[0]!='R')
return INVALID;
if (!valid_number(&sreg[1]))
return INVALID;
reg = atoi(&sreg[1]);
if (reg < 0 || reg >= 32)
return INVALID;
return reg;
}
/* Parses the J instruction with given operands */
inst_t parse_J(char *operands[], int nops, int nline)
{
int addr;
inst_t instruction;
if (nops != 1)
{
fprintf(stderr, "Incorrect number of operands for J instruction in line %d\n", nline);
exit(1);
}
addr = search_label(operands[0]);
if (addr == INVALID)
{
fprintf(stderr, "Unknown label for J instruction in line %d\n", nline);
exit(1);
}
instruction.opcode = J;
instruction.addr = addr;
return instruction;
}
/* Parses the branch instruction with given operands */
inst_t parse_B(int opcode, char *operands[], int nops, int nline)
{
inst_t instruction;
if (nops != 3)
{
fprintf(stderr, "Incorrect number of operands for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
instruction.opcode = opcode;
instruction.addr = search_label(operands[2]);
if (instruction.addr == INVALID)
{
fprintf(stderr, "Unknown label for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
instruction.rsrc = validate_register(operands[0]);
if (instruction.rsrc == INVALID)
{
fprintf(stderr, "Invalid source register for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
instruction.rsrc2 = validate_register(operands[1]);
if (instruction.rsrc2 == INVALID)
{
fprintf(stderr, "Invalid source register for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
return instruction;
}
/* Parses the LI instruction with given operands */
inst_t parse_LI(char *operands[], int nops, int nline)
{
inst_t instruction;
if (nops != 2)
{
fprintf(stderr, "Incorrect number of operands for LI instruction in line %d\n", nline);
exit(1);
}
instruction.opcode = LI;
instruction.rdest = validate_register(operands[0]);
if (instruction.rdest == INVALID)
{
fprintf(stderr, "Invalid register for LI instruction in line %d\n", nline);
exit(1);
}
if (!valid_number(operands[1]))
{
fprintf(stderr, "Invalid immediate value for LI instruction in line %d\n", nline);
exit(1);
}
instruction.imm = atoi(operands[1]);
return instruction;
}
/* Parses the register arithmetic/logic instruction with given operands */
inst_t parse_R(int opcode, char *operands[], int nops, int nline)
{
inst_t instruction;
if (nops != 3)
{
fprintf(stderr, "Incorrect number of operands for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
instruction.opcode = opcode;
instruction.rdest = validate_register(operands[0]);
if (instruction.rdest == INVALID)
{
fprintf(stderr, "Invalid destination register for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
instruction.rsrc = validate_register(operands[1]);
if (instruction.rsrc == INVALID)
{
fprintf(stderr, "Invalid source register for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
instruction.rsrc2 = validate_register(operands[2]);
if (instruction.rsrc2 == INVALID)
{
fprintf(stderr, "Invalid source register for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
return instruction;
}
/* Parses the immediate arithmetic/logic instruction with given operands */
inst_t parse_I(int opcode, char *operands[], int nops, int nline)
{
inst_t instruction;
if (nops != 3)
{
fprintf(stderr, "Incorrect number of operands for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
instruction.opcode = opcode;
instruction.rdest = validate_register(operands[0]);
if (instruction.rdest == INVALID)
{
fprintf(stderr, "Invalid destination register for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
instruction.rsrc = validate_register(operands[1]);
if (instruction.rsrc == INVALID)
{
fprintf(stderr, "Invalid source register for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
if (!valid_number(operands[2]))
{
fprintf(stderr, "Invalid immediate value for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
instruction.imm = atoi(operands[2]);
return instruction;
}
/* Parses the memory instruction with given operands */
inst_t parse_M(int opcode, char *operands[], int nops, int nline)
{
int rsrc, rdest;
inst_t instruction;
char *end, *reg, *off;
if (nops != 2)
{
fprintf(stderr, "Incorrect number of operands for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
instruction.opcode = opcode;
rdest = validate_register(operands[0]);
if (rdest == INVALID)
{
fprintf(stderr, "Invalid destination register for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
if (opcode == LW)
instruction.rdest = rdest;
else
instruction.rsrc = rdest;
end = &operands[1][strlen(operands[1])-1];
if (*end != ')')
{
fprintf(stderr, "Invalid format for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
*(end--) = 0;
while(end > operands[1] && *end != '(')
end--;
if (*end != '(' || end <= operands[1])
{
fprintf(stderr, "Invalid format for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
*end = 0;
reg = trim(end + 1);
rsrc = validate_register(reg);
if (rsrc == INVALID)
{
fprintf(stderr, "Invalid base register for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
if (opcode == LW)
instruction.rsrc = rsrc;
else
instruction.rsrc2 = rsrc;
off = operands[1];
if (!valid_number(off))
{
fprintf(stderr, "Invalid offset value for %s instruction in line %d\n",
instructions[opcode], nline);
exit(1);
}
instruction.imm = atoi(off);
return instruction;
}
/* Parses the HLT instruction with given operands */
inst_t parse_HLT(char *operands[], int nops, int nline)
{
inst_t instruction;
if (nops != 0)
{
fprintf(stderr, "Incorrect number of operands for HLT instruction in line %d\n", nline);
exit(1);
}
instruction.opcode = HLT;
return instruction;
}
/* Parses the instruction with the name inst and operands oper, returns a
inst_t structure with the opcode and operands of instruction */
inst_t parse_instruction(char *inst, char *oper, int nline)
{
int opcode, nops;
char *operands[3];
inst_t instruction;
opcode = search_instruction(inst);
if (opcode == INVALID)
{
fprintf(stderr, "Invalid instruction %s found in line %d\n", inst, nline);
exit(1);
}
nops = parse_operand(oper, operands);
if (nops == INVALID)
{
fprintf(stderr, "Too many operands for instruction %s in line %d\n",
instructions[opcode], nline);
exit(1);
}
switch(opcode)
{
case J:
instruction = parse_J(operands, nops, nline);
instruction.rsrc_req = 0;
instruction.rsrc2_req = 0;
break;
case BEQ:
case BNE:
instruction = parse_B(opcode, operands, nops, nline);
instruction.rsrc_req = 1;
instruction.rsrc2_req = 1;
break;
case LI:
instruction = parse_LI(operands, nops, nline);
instruction.rsrc_req = 0;
instruction.rsrc2_req = 0;
break;
case AND:
case OR:
case ADD:
case SUB:
case MULT:
instruction = parse_R(opcode, operands, nops, nline);
instruction.rsrc_req = 1;
instruction.rsrc2_req = 1;
break;
case ANDI:
case ORI:
case ADDI:
case SUBI:
case MULTI:
instruction = parse_I(opcode, operands, nops, nline);
instruction.rsrc_req = 1;
instruction.rsrc2_req = 0;
break;
case LW:
instruction = parse_M(opcode, operands, nops, nline);
instruction.rsrc_req = 1;
instruction.rsrc2_req = 0;
break;
case SW:
instruction = parse_M(opcode, operands, nops, nline);
instruction.rsrc_req = 1;
instruction.rsrc2_req = 1;
break;
case HLT:
instruction = parse_HLT(operands, nops, nline);
instruction.rsrc_req = 0;
instruction.rsrc2_req = 0;
break;
}
switch(opcode)
{
case J:
case BEQ:
case BNE:
case LI:
case HLT:
instruction.ex_stages = 0;
break;
case AND:
case OR:
case ANDI:
case ORI:
case LW:
case SW:
instruction.ex_stages = 1;
break;
case ADD:
case SUB:
case ADDI:
case SUBI:
instruction.ex_stages = 2;
break;
case MULT:
case MULTI:
instruction.ex_stages = 3;
break;
}
instruction.stalled = 0;
return instruction;
}
/* makes a second pass to parse all instructions, save them on the instruction table
translating all label references to addresses */
void second_pass(FILE *input)
{
char buffer[BUFSIZ], *line;
char *next, *inst, *oper;
int nline = 1;
inst_t instruction;
int lbl;
ninst = 0;
while (!feof(input))
{
if (fgets(buffer, BUFSIZ, input))
{
line = trim(buffer);
if (line[0])
{
str_to_upper(line);
next = get_next_word(line);
if (line[strlen(line) - 1] == ':')
{
line[strlen(line) - 1] = 0;
lbl = search_label(line);
inst = trim(next);
oper = get_next_word(inst);
}
else
{
lbl = -1;
inst = line;
oper = trim(next);
}
instruction = parse_instruction(inst, oper, nline);
instruction.label = lbl;
inst_table[ninst++] = instruction;
}
nline++;
}
}
}
/* Loads all the instructions from the given file into the instruction table */
void load_instructions(char *filename)
{
FILE *input;
input = fopen(filename, "rt");
if (input == NULL)
{
fprintf(stderr, "Unable to open instruction file \"%s\"\n", filename);
exit(1);
}
first_pass(input);
rewind(input);
second_pass(input);
fclose(input);
}
/* Loads all the memory data from the given file */
void load_memory_data(char *filename)
{
FILE *input;
char buffer[BUFSIZ], *line;
int data, bit;
input = fopen(filename, "rt");
if (input == NULL)
{
fprintf(stderr, "Unable to open memory file \"%s\"\n", filename);
exit(1);
}
while (!feof(input))
{
if (fgets(buffer, BUFSIZ, input))
{
line = trim(buffer);
if (line[0])
{
if (strlen(line)!=32)
{
fprintf(stderr, "Invalid word size found in memory file\n");
exit(1);
}
data = 0;
for (bit=0; bit<32; bit++)
{
if (line[bit] != '0' && line[bit] != '1')
{
fprintf(stderr, "Invalid bit value found in memory file\n");
exit(1);
}
data = (data << 1) | (line[bit] - '0');
}
memory[mem_size++] = data;
}
}
}
fclose(input);
}
/* save the instruction stats */
void save_instruction_stats(inst_t inst)
{
char label[MAX_LABEL_LEN + 2];
char ops[MAX_OP_LINE];
char cycles[5][MAX_OP_LINE];
stats_entry_t stat;
int i, j;
if (inst.label != INVALID)
sprintf(label, "%s:",labels[inst.label].name);
else
sprintf(label, " ");
switch(inst.opcode)
{
case J:
sprintf(ops, "%s", labels[inst.addr].name);
inst.ex_cycle = 0;
inst.mem_cycle = 0;
inst.wb_cycle = 0;
break;
case BEQ:
case BNE:
sprintf(ops, "R%d, R%d, %s", inst.rsrc, inst.rsrc2, labels[inst.addr].name);
inst.ex_cycle = 0;
inst.mem_cycle = 0;
inst.wb_cycle = 0;
break;
case LI:
sprintf(ops, "R%d, %d", inst.rdest, inst.imm);
break;
case AND:
case OR:
case ADD:
case SUB:
case MULT:
sprintf(ops, "R%d, R%d, R%d", inst.rdest, inst.rsrc, inst.rsrc2);
break;
case ANDI:
case ORI:
case ADDI:
case SUBI:
case MULTI:
sprintf(ops, "R%d, R%d, %d", inst.rdest, inst.rsrc, inst.imm);
break;
case LW:
sprintf(ops, "R%d, %d(R%d)", inst.rdest, inst.imm, inst.rsrc);
break;
case SW:
sprintf(ops, "R%d, %d(R%d)", inst.rsrc, inst.imm, inst.rsrc2);
break;
case HLT:
sprintf(ops, " ");
inst.ex_cycle = 0;
inst.mem_cycle = 0;
inst.wb_cycle = 0;
break;
}
for (i = 0; i < 5; i++)
cycles[i][0] = 0;
if (inst.if_cycle != 0)
sprintf(cycles[0], "%-6d", inst.if_cycle);
if (inst.id_cycle != 0)
sprintf(cycles[1], "%-6d", inst.id_cycle);
if (inst.ex_cycle != 0)
sprintf(cycles[2], "%-6d", inst.ex_cycle);
if (inst.mem_cycle != 0)
sprintf(cycles[3], "%-6d", inst.mem_cycle);
if (inst.wb_cycle != 0)
sprintf(cycles[4], "%-6d", inst.wb_cycle);
sprintf(stat.line, "%-8s %-8s %-20s %s %s %s %s %s", label, instructions[inst.opcode],
ops, cycles[0], cycles[1], cycles[2], cycles[3], cycles[4]);
stat.pos = inst.if_cycle;
if (n_stats == 0)
stats[n_stats++] = stat;
else
{
for (i = 0; i < n_stats; i++)
{
if (stats[i].pos > stat.pos)
break;
}
for (j = n_stats; j>i; j--)
stats[j] = stats[j - 1];
stats[i] = stat;
n_stats++;
}
}
/* Simulates one cycle of an instruction cache read */
inst_t i_cache_read(int PC)
{
int tag = PC >> 5;
int index = (PC >> 3) & 0x3;
int offset = PC & 0x7;
int i;
if (!i_cache_reading)
{
i_cache_accesses++;
if (i_cache[index].valid && i_cache[index].tag == tag)
{
i_cache_hits++;
return i_cache[index].data[offset];
}
else
{
i_cache_reading = I_CACHE_BLKSIZE*MEM_DELAY;
i_cache_index = index;
i_cache_offset = offset;
i_cache_mem_addr = (PC >> 3) << 3;
i_cache[index].tag = tag;
return nop;
}
}
else
{
i_cache_reading--;
if (i_cache_reading == 0)
{
i_cache[i_cache_index].valid = 1;
for (i = 0; i < I_CACHE_BLKSIZE; i++)
i_cache[i_cache_index].data[i] = inst_table[i_cache_mem_addr + i];
return i_cache[i_cache_index].data[i_cache_offset];
}
else
return nop;
}
}
/* Simulates one cycle of a data cache read */
int d_cache_read(int addr, int *miss)
{
int real_addr;
int tag;
int index;
int offset;
int i;
real_addr = (addr - 0x100) >> 2;
tag = real_addr >> 4;
index = (real_addr >> 2) & 0x3;
offset = real_addr & 0x3;
if (!d_cache_reading)
{
d_cache_accesses++;
if (d_cache[index].valid && d_cache[index].tag == tag)
{
d_cache_hits++;
*miss = 0;
return d_cache[index].data[offset];
}
else
{
d_cache_reading = D_CACHE_BLKSIZE*MEM_DELAY+1;
d_cache_index = index;
d_cache_offset = offset;
d_cache_mem_addr = (real_addr >> 2) << 2;
d_cache[index].tag = tag;
*miss = 1;
return 0;
}
}
else
{
if (!i_cache_reading && !d_cache_writing)
d_cache_reading--;
if (d_cache_reading == 0)
{
d_cache[d_cache_index].valid = 1;
for (i = 0; i < D_CACHE_BLKSIZE; i++)
d_cache[d_cache_index].data[i] = memory[d_cache_mem_addr + i];
*miss = 0;
return d_cache[d_cache_index].data[d_cache_offset];
}
else
{
*miss = 1;
return 0;
}
}
}
/* Simulates one cycle of a data cache write */
int d_cache_write(int val, int addr)
{
int real_addr;
int tag;
int index;
int offset;
int i;
real_addr = (addr - 0x100) >> 2;
tag = real_addr >> 4;
index = (real_addr >> 2) & 0x3;
offset = real_addr & 0x3;
if (!d_cache_writing)
{
d_cache_accesses++;
if (d_cache[index].valid && d_cache[index].tag == tag)
{
d_cache_hits++;
d_cache[index].data[offset] = val;
write_buffer[buffer_pos].data = val;
write_buffer[buffer_pos].addr = real_addr;
buffer_pos++;
return 0;
}
else
{
d_cache_writing = D_CACHE_BLKSIZE*MEM_DELAY+1;
d_cache_index_w = index;
d_cache_offset_w = offset;
d_cache_mem_addr_w = (real_addr >> 2) << 2;
d_cache[index].tag = tag;
return 1;
}
}
else
{
if (!i_cache_reading)
d_cache_writing--;
if (d_cache_writing == 0)
{
d_cache[d_cache_index_w].valid = 1;
for (i = 0; i < D_CACHE_BLKSIZE; i++)
d_cache[d_cache_index_w].data[i] = memory[d_cache_mem_addr_w + i];
d_cache[d_cache_index_w].data[d_cache_offset_w] = val;
write_buffer[buffer_pos].data = val;
write_buffer[buffer_pos].addr = d_cache_mem_addr_w;
buffer_pos++;
return 0;
}
else
return 1;
}
}
/* updates the memory using the write buffer one word at a time */
void update_memory()
{
int i;
if (!i_cache_reading && !d_cache_reading && !d_cache_writing)
{
if (!buffer_updating && buffer_pos)
buffer_updating = 3;
else
{
buffer_updating--;
if (buffer_updating == 0)
{
memory[write_buffer[0].addr] = write_buffer[0].data;
buffer_pos--;
for (i = 0; i < buffer_pos; i++)
write_buffer[i] = write_buffer[i + 1];
}
}
}
}
/* Simulates the execution of the instruction */
inst_t execute(inst_t inst)
{
inst.PC = 0;
inst.wb = 1;
inst.mem_rd = 0;
inst.mem_wr = 0;
switch (inst.opcode)
{
case J:
inst.PC = labels[inst.addr].addr;
inst.wb = 0;
break;
case BEQ:
if (inst.rsrc_val == inst.rsrc2_val)
inst.PC = labels[inst.addr].addr;
inst.wb = 0;
break;
case BNE:
if (inst.rsrc_val != inst.rsrc2_val)
inst.PC = labels[inst.addr].addr;
inst.wb = 0;
break;
case LI:
inst.rdest_val = inst.imm;
break;
case AND:
inst.rdest_val = inst.rsrc_val & inst.rsrc2_val;
break;
case OR:
inst.rdest_val = inst.rsrc_val | inst.rsrc2_val;
break;
case ADD:
inst.rdest_val = inst.rsrc_val + inst.rsrc2_val;
break;
case SUB:
inst.rdest_val = inst.rsrc_val - inst.rsrc2_val;
break;
case MULT:
inst.rdest_val = inst.rsrc_val * inst.rsrc2_val;
break;
case ANDI:
inst.rdest_val = inst.rsrc_val & inst.imm;
break;
case ORI:
inst.rdest_val = inst.rsrc_val | inst.imm;
break;
case ADDI:
inst.rdest_val = inst.rsrc_val + inst.imm;
break;
case SUBI:
inst.rdest_val = inst.rsrc_val - inst.imm;
break;
case MULTI:
inst.rdest_val = inst.rsrc_val * inst.imm;
break;
case LW:
inst.mem_rd = 1;
inst.mem_addr = inst.rsrc_val + inst.imm;
break;
case SW:
inst.wb = 0;
inst.mem_wr = 1;
inst.mem_data = inst.rsrc_val;
inst.mem_addr = inst.rsrc2_val + inst.imm;
break;
case HLT:
case NOP:
inst.wb = 0;
break;
}
return inst;
}
/* Simulate the loaded program */
void simulate()
{
int PC;
int halted, stalled;
inst_t pipeline[7];
int i, cycles = 0;
int enable_if, miss, data, slot;
nop.opcode = NOP;
nop.rdest = INVALID;
nop.rsrc = INVALID;
nop.rsrc2 = INVALID;
nop.rsrc_req = 0;
nop.rsrc2_req = 0;
nop.wb = 0;
nop.if_cycle = 0;
nop.ex_stages = 0;
nop.stalled = 0;
for(i=0; i<7; i++)
pipeline[i] = nop;
PC = 0;
halted = 0;
stalled = 0;
enable_if = 1;
while (!halted)
{
if (pipeline[ID_EX1].opcode != HLT && enable_if && !stalled)
{
pipeline[IF_ID] = i_cache_read(PC);
if (pipeline[IF_ID].opcode != NOP)
{
pipeline[IF_ID].if_cycle = cycles + 1;
pipeline[IF_ID].id_cycle = 0;
pipeline[IF_ID].ex_cycle = 0;
pipeline[IF_ID].mem_cycle = 0;
pipeline[IF_ID].wb_cycle = 0;
pipeline[IF_ID].stalled = 0;
PC++;
}
}
pipeline[ID_EX1].stalled = 0;
if (pipeline[ID_EX1].opcode == HLT)
enable_if = 0;
slot =(pipeline[ID_EX1].ex_stages == 0)? 1 : 0;
if(pipeline[ID_EX1].rsrc_req)
{
if (pipeline[ID_EX1].rsrc == pipeline[EX1_EX2].rdest)
{
if (pipeline[EX1_EX2].ex_stages <= 1 - slot && !pipeline[EX1_EX2].mem_rd)
pipeline[ID_EX1].rsrc_val = pipeline[EX1_EX2].rdest_val;
else
pipeline[ID_EX1].stalled = 1;
}
else if (pipeline[ID_EX1].rsrc == pipeline[EX2_EX3].rdest)
{
if (pipeline[EX2_EX3].ex_stages <= 2 - slot && !pipeline[EX2_EX3].mem_rd)
pipeline[ID_EX1].rsrc_val = pipeline[EX2_EX3].rdest_val;
else
pipeline[ID_EX1].stalled = 1;
}
else if (pipeline[ID_EX1].rsrc == pipeline[EX3_MEM].rdest)
{
if (!pipeline[EX3_MEM].mem_rd)
pipeline[ID_EX1].rsrc_val = pipeline[EX3_MEM].rdest_val;
else
pipeline[ID_EX1].stalled = 1;
}
else if (pipeline[ID_EX1].rsrc == pipeline[MEM_WB].rdest)
{
if (!pipeline[MEM_WB].mem_rd)
pipeline[ID_EX1].rsrc_val = pipeline[MEM_WB].rdest_val;
else
pipeline[ID_EX1].stalled = 1;
}
else if (pipeline[ID_EX1].rsrc == pipeline[LAST].rdest)
pipeline[ID_EX1].rsrc_val = pipeline[LAST].rdest_val;
else
pipeline[ID_EX1].rsrc_val = registers[pipeline[ID_EX1].rsrc];
}
if(pipeline[ID_EX1].rsrc2_req)
{
if (pipeline[ID_EX1].rsrc2 == pipeline[EX1_EX2].rdest)
{
if (pipeline[EX1_EX2].ex_stages <= 1 -slot && !pipeline[EX1_EX2].mem_rd)
pipeline[ID_EX1].rsrc2_val = pipeline[EX1_EX2].rdest_val;
else
pipeline[ID_EX1].stalled = 1;
}
else if (pipeline[ID_EX1].rsrc2 == pipeline[EX2_EX3].rdest)
{
if (pipeline[EX2_EX3].ex_stages <= 2-slot && !pipeline[EX2_EX3].mem_rd)
pipeline[ID_EX1].rsrc2_val = pipeline[EX2_EX3].rdest_val;
else
pipeline[ID_EX1].stalled = 1;
}
else if (pipeline[ID_EX1].rsrc2 == pipeline[EX3_MEM].rdest)
{
if (!pipeline[EX3_MEM].mem_rd)
pipeline[ID_EX1].rsrc2_val = pipeline[EX3_MEM].rdest_val;
else
pipeline[ID_EX1].stalled = 1;
}
else if (pipeline[ID_EX1].rsrc2 == pipeline[MEM_WB].rdest)
{
if (!pipeline[MEM_WB].mem_rd)
pipeline[ID_EX1].rsrc2_val = pipeline[MEM_WB].rdest_val;
else
pipeline[ID_EX1].stalled = 1;
}
else if (pipeline[ID_EX1].rsrc2 == pipeline[LAST].rdest)
pipeline[ID_EX1].rsrc2_val = pipeline[LAST].rdest_val;
else
pipeline[ID_EX1].rsrc2_val = registers[pipeline[ID_EX1].rsrc2];
}
if (!pipeline[ID_EX1].stalled)
{
pipeline[ID_EX1] = execute(pipeline[ID_EX1]);
if (pipeline[ID_EX1].PC)
{
PC = pipeline[ID_EX1].PC;
save_instruction_stats(pipeline[IF_ID]);
pipeline[IF_ID] = nop;
}
}
pipeline[ID_EX1].id_cycle = cycles + 1;
pipeline[EX1_EX2].stalled = 0;
pipeline[EX1_EX2].ex_cycle = cycles + 1;
pipeline[EX2_EX3].stalled = 0;
pipeline[EX2_EX3].ex_cycle = cycles + 1;
pipeline[EX3_MEM].stalled = 0;
pipeline[EX3_MEM].ex_cycle = cycles + 1;
pipeline[MEM_WB].stalled = 0;
if (pipeline[MEM_WB].mem_wr)
{
data = d_cache_write(pipeline[MEM_WB].mem_data, pipeline[MEM_WB].mem_addr);
if (miss)
pipeline[MEM_WB].stalled = 1;
}
else if (pipeline[MEM_WB].mem_rd)
{
data = d_cache_read(pipeline[MEM_WB].mem_addr, &miss);
if (!miss)
{
pipeline[MEM_WB].rdest_val = data;
pipeline[MEM_WB].mem_rd = 0;
}
else
pipeline[MEM_WB].stalled = 1;
}
pipeline[MEM_WB].mem_cycle = cycles + 1;
pipeline[LAST].stalled = 0;
if (pipeline[LAST].wb)
registers[pipeline[LAST].rdest] = pipeline[LAST].rdest_val;
pipeline[LAST].wb_cycle = cycles + 1;
if (pipeline[LAST].opcode != NOP)
{
save_instruction_stats(pipeline[LAST]);
if (pipeline[LAST].opcode == HLT)
halted = 1;
pipeline[LAST] = nop;
}
update_memory();
/* Advance pipeline */
stalled = 0;
for (i = 6; i > 0; i--)
{
if(pipeline[i].opcode == NOP)
stalled = 0;
if (!pipeline[i-1].stalled)
{
if (!stalled)
{
pipeline[i] = pipeline[i-1];
pipeline[i-1] = nop;
}
}
else
stalled = 1;
}
cycles++;
}
}
/* Print the instruction statistics on a file */
void print_results(FILE *output)
{
int i;
for (i = 0; i < n_stats; i++)
fprintf(output, "%s\n", stats[i].line);
fprintf(output, "\nTotal number of access requests for instruction cache: %d\n",
i_cache_accesses);
fprintf(output, "Number of instruction cache hits: %d\n", i_cache_hits);
fprintf(output, "\nTotal number of access requests for data cache: %d\n",
d_cache_accesses);
fprintf(output, "Number of data cache hits: %d\n", d_cache_hits);
}
int main(int argc, char **argv)
{
FILE *output;
if (argc != 4)
{
printf("Invalid number of arguments!\n");
printf("Usage:\n");
printf(" %s inst.txt data.txt output.txt\n", argv[0]);
exit(1);
}
load_instructions(argv[1]);
load_memory_data(argv[2]);
simulate();
output = fopen(argv[3], "wt");
print_results(output);
fclose(output);
print_results(stdout);
return 0;
}
Related Samples
At ProgrammingHomeworkHelp.com, we offer specialized assignment support for students across various programming languages. Our website provides a range of sample assignments to aid your studies, including comprehensive examples in Programming, C, and Assembly Language. These samples are crafted by experts to help you understand key concepts and tackle your assignments effectively. Whether you need assistance with complex algorithms, coding practices, or debugging, our expertly designed samples serve as valuable resources to enhance your learning experience and academic success. Visit us today for tailored support and quality examples.
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming
Programming