Computer Architecture & Organization Programming Assignment

techguy
fwdcaosimulatorcodeproject1firstcopy.zip

apex_cpu_pipeline_simulator.zip

apex_cpu_pipeline_simulator/apex_macros.h

/* * apex_macros.h * Contains APEX cpu pipeline macros * * Author: * Copyright (c) 2020, Gaurav Kothari (gkothar1@binghamton.edu) * State University of New York at Binghamton */ #ifndef _MACROS_H_ #define _MACROS_H_ #define FALSE 0x0 #define TRUE 0x1 /* Integers */ #define DATA_MEMORY_SIZE 4096 /* Size of integer register file */ #define REG_FILE_SIZE 16 /* Numeric OPCODE identifiers for instructions */ #define OPCODE_ADD 0x0 #define OPCODE_SUB 0x1 #define OPCODE_MUL 0x2 #define OPCODE_DIV 0x3 #define OPCODE_AND 0x4 #define OPCODE_OR 0x5 #define OPCODE_XOR 0x6 #define OPCODE_MOVC 0x7 #define OPCODE_LOAD 0x8 #define OPCODE_STORE 0x9 #define OPCODE_BZ 0xa #define OPCODE_BNZ 0xb #define OPCODE_HALT 0xc /* Set this flag to 1 to enable debug messages */ #define ENABLE_DEBUG_MESSAGES 1 /* Set this flag to 1 to enable cycle single-step mode */ #define ENABLE_SINGLE_STEP 1 #endif

__MACOSX/apex_cpu_pipeline_simulator/._apex_macros.h

apex_cpu_pipeline_simulator/Makefile

# # Makefile # # Author: # Copyright (c) 2020, Gaurav Kothari (gkothar1@binghamton.edu) # State University of New York at Binghamton # Enables debug messages while compiling COMPILE_DEBUG=@ VERSION=2.0 # Compile and Link flags, libraries CC=$(CROSS_PREFIX)gcc CFLAGS= -g -Wall -O0 -DVERSION=$(VERSION) LDFLAGS= LIBS= PROGS= apex_sim all: clean $(PROGS) # Add all object files to be linked in sequence APEX_OBJS:=file_parser.o apex_cpu.o main.o apex_sim: $(APEX_OBJS) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) %.o: %.c $(COMPILE_DEBUG)$(CC) $(CFLAGS) -c -o $@ $< $(COMPILE_DEBUG)echo "CC $<" clean: rm -f *.o *.d *~ $(PROGS)

__MACOSX/apex_cpu_pipeline_simulator/._Makefile

apex_cpu_pipeline_simulator/apex_cpu.h

/* * apex_cpu.h * Contains APEX cpu pipeline declarations * * Author: * Copyright (c) 2020, Gaurav Kothari (gkothar1@binghamton.edu) * State University of New York at Binghamton */ #ifndef _APEX_CPU_H_ #define _APEX_CPU_H_ #include "apex_macros.h" /* Format of an APEX instruction */ typedef struct APEX_Instruction { char opcode_str[128]; int opcode; int rd; int rs1; int rs2; int imm; } APEX_Instruction; /* Model of CPU stage latch */ typedef struct CPU_Stage { int pc; char opcode_str[128]; int opcode; int rs1; int rs2; int rd; int imm; int rs1_value; int rs2_value; int result_buffer; int memory_address; int has_insn; } CPU_Stage; /* Model of APEX CPU */ typedef struct APEX_CPU { int pc; /* Current program counter */ int clock; /* Clock cycles elapsed */ int insn_completed; /* Instructions retired */ int regs[REG_FILE_SIZE]; /* Integer register file */ int code_memory_size; /* Number of instruction in the input file */ APEX_Instruction *code_memory; /* Code Memory */ int data_memory[DATA_MEMORY_SIZE]; /* Data Memory */ int single_step; /* Wait for user input after every cycle */ int zero_flag; /* {TRUE, FALSE} Used by BZ and BNZ to branch */ int fetch_from_next_cycle; /* Pipeline stages */ CPU_Stage fetch; CPU_Stage decode; CPU_Stage execute; CPU_Stage memory; CPU_Stage writeback; } APEX_CPU; APEX_Instruction *create_code_memory(const char *filename, int *size); APEX_CPU *APEX_cpu_init(const char *filename); void APEX_cpu_run(APEX_CPU *cpu); void APEX_cpu_stop(APEX_CPU *cpu); #endif

__MACOSX/apex_cpu_pipeline_simulator/._apex_cpu.h

apex_cpu_pipeline_simulator/README.md

# APEX Pipeline Simulator v2.0 A template for 5 Stage APEX In-order Pipeline ## Notes: - This code is a simple implementation template of a working 5-Stage APEX In-order Pipeline - Implementation is in `C` language - Stages: Fetch -> Decode -> Execute -> Memory -> Writeback - You can read, modify and build upon given code-base to add other features as required in project description - You are also free to write your own implementation from scratch - All the stages have latency of one cycle - There is a single functional unit in Execute stage which perform all the arithmetic and logic operations - Logic to check data dependencies has not be included - Includes logic for `ADD`, `LOAD`, `BZ`, `BNZ`, `MOVC` and `HALT` instructions - On fetching `HALT` instruction, fetch stage stop fetching new instructions - When `HALT` instruction is in commit stage, simulation stops - You can modify the instruction semantics as per the project description ## Files: - `Makefile` - `file_parser.c` - Functions to parse input file - `apex_cpu.h` - Data structures declarations - `apex_cpu.c` - Implementation of APEX cpu - `apex_macros.h` - Macros used in the implementation - `main.c` - Main function which calls APEX CPU interface - `input.asm` - Sample input file ## How to compile and run Go to terminal, `cd` into project directory and type: ``` make ``` Run as follows: ``` ./apex_sim <input_file_name> ``` ## Author - Copyright (C) Gaurav Kothari (gkothar1@binghamton.edu) - State University of New York, Binghamton ## Bugs - Please contact your TAs for any assistance or query - Report bugs at: gkothar1@binghamton.edu

__MACOSX/apex_cpu_pipeline_simulator/._README.md

apex_cpu_pipeline_simulator/main.c

/* * main.c * * Author: * Copyright (c) 2020, Gaurav Kothari (gkothar1@binghamton.edu) * State University of New York at Binghamton */ #include <stdio.h> #include <stdlib.h> #include "apex_cpu.h" int main(int argc, char const *argv[]) { APEX_CPU *cpu; fprintf(stderr, "APEX CPU Pipeline Simulator v%0.1lf\n", VERSION); if (argc != 2) { fprintf(stderr, "APEX_Help: Usage %s <input_file>\n", argv[0]); exit(1); } cpu = APEX_cpu_init(argv[1]); if (!cpu) { fprintf(stderr, "APEX_Error: Unable to initialize CPU\n"); exit(1); } APEX_cpu_run(cpu); APEX_cpu_stop(cpu); return 0; }

__MACOSX/apex_cpu_pipeline_simulator/._main.c

apex_cpu_pipeline_simulator/apex_v2.0.pdf

CS520: APEX CPU Simulator v2.0

Gaurav Kothari <gkothar1@binghamton.edu>

Department of Computer Science State University of New York at Binghamton

November 2, 2020

gkothar1@binghamton.edu APEX CPU Simulator November 2, 2020 1 / 5

Overview

A template for a working 5-Stage APEX In-order Pipeline

Implementation in C language

You can read, modify and build upon given code-base

You are also free to write your own implementation from scratch

gkothar1@binghamton.edu APEX CPU Simulator November 2, 2020 2 / 5

Micro-architecture

Stages: Fetch → Decode → Execute → Memory → Writeback

All the stages have latency of one clock cycle

Includes logic for ADD, LOAD, BZ, BNZ and HALT instructions

On fetching HALT instruction, fetch stage stop fetching new instructions

When HALT instruction is in commit stage, simulation stops

Logic to check data dependencies not included

gkothar1@binghamton.edu APEX CPU Simulator November 2, 2020 3 / 5

Files

Makefile

file parser.c → Functions to parse input file, add new instructions

apex cpu.h → Data structures declarations, model of CPU, Pipeline stages, code and data memory

apex cpu.c → Implementation of APEX cpu

apex macros.h → Macros used in the implementation

main.c → Main function which calls APEX CPU interface

input.asm → Sample input file

gkothar1@binghamton.edu APEX CPU Simulator November 2, 2020 4 / 5

How to compile and run ?

Go to terminal, cd into project directory and type:

$ make

To run:

$ ./apex_sim <input_file_name>

Report bugs at: gkothar1@binghamton.edu

gkothar1@binghamton.edu APEX CPU Simulator November 2, 2020 5 / 5

__MACOSX/apex_cpu_pipeline_simulator/._apex_v2.0.pdf

apex_cpu_pipeline_simulator/input.asm

MOVC R3,#27 MOVC R4,#9 HALT

__MACOSX/apex_cpu_pipeline_simulator/._input.asm

apex_cpu_pipeline_simulator/apex_cpu.c

/* * apex_cpu.c * Contains APEX cpu pipeline implementation * * Author: * Copyright (c) 2020, Gaurav Kothari (gkothar1@binghamton.edu) * State University of New York at Binghamton */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "apex_cpu.h" #include "apex_macros.h" /* Converts the PC(4000 series) into array index for code memory * * Note: You are not supposed to edit this function */ static int get_code_memory_index_from_pc(const int pc) { return (pc - 4000) / 4; } static void print_instruction(const CPU_Stage *stage) { switch (stage->opcode) { case OPCODE_ADD: case OPCODE_SUB: case OPCODE_MUL: case OPCODE_DIV: case OPCODE_AND: case OPCODE_OR: case OPCODE_XOR: { printf("%s,R%d,R%d,R%d ", stage->opcode_str, stage->rd, stage->rs1, stage->rs2); break; } case OPCODE_MOVC: { printf("%s,R%d,#%d ", stage->opcode_str, stage->rd, stage->imm); break; } case OPCODE_LOAD: { printf("%s,R%d,R%d,#%d ", stage->opcode_str, stage->rd, stage->rs1, stage->imm); break; } case OPCODE_STORE: { printf("%s,R%d,R%d,#%d ", stage->opcode_str, stage->rs1, stage->rs2, stage->imm); break; } case OPCODE_BZ: case OPCODE_BNZ: { printf("%s,#%d ", stage->opcode_str, stage->imm); break; } case OPCODE_HALT: { printf("%s", stage->opcode_str); break; } } } /* Debug function which prints the CPU stage content * * Note: You can edit this function to print in more detail */ static void print_stage_content(const char *name, const CPU_Stage *stage) { printf("%-15s: pc(%d) ", name, stage->pc); print_instruction(stage); printf("\n"); } /* Debug function which prints the register file * * Note: You are not supposed to edit this function */ static void print_reg_file(const APEX_CPU *cpu) { int i; printf("----------\n%s\n----------\n", "Registers:"); for (int i = 0; i < REG_FILE_SIZE / 2; ++i) { printf("R%-3d[%-3d] ", i, cpu->regs[i]); } printf("\n"); for (i = (REG_FILE_SIZE / 2); i < REG_FILE_SIZE; ++i) { printf("R%-3d[%-3d] ", i, cpu->regs[i]); } printf("\n"); } /* * Fetch Stage of APEX Pipeline * * Note: You are free to edit this function according to your implementation */ static void APEX_fetch(APEX_CPU *cpu) { APEX_Instruction *current_ins; if (cpu->fetch.has_insn) { /* This fetches new branch target instruction from next cycle */ if (cpu->fetch_from_next_cycle == TRUE) { cpu->fetch_from_next_cycle = FALSE; /* Skip this cycle*/ return; } /* Store current PC in fetch latch */ cpu->fetch.pc = cpu->pc; /* Index into code memory using this pc and copy all instruction fields * into fetch latch */ current_ins = &cpu->code_memory[get_code_memory_index_from_pc(cpu->pc)]; strcpy(cpu->fetch.opcode_str, current_ins->opcode_str); cpu->fetch.opcode = current_ins->opcode; cpu->fetch.rd = current_ins->rd; cpu->fetch.rs1 = current_ins->rs1; cpu->fetch.rs2 = current_ins->rs2; cpu->fetch.imm = current_ins->imm; /* Update PC for next instruction */ cpu->pc += 4; /* Copy data from fetch latch to decode latch*/ cpu->decode = cpu->fetch; if (ENABLE_DEBUG_MESSAGES) { print_stage_content("Fetch", &cpu->fetch); } /* Stop fetching new instructions if HALT is fetched */ if (cpu->fetch.opcode == OPCODE_HALT) { cpu->fetch.has_insn = FALSE; } } } /* * Decode Stage of APEX Pipeline * * Note: You are free to edit this function according to your implementation */ static void APEX_decode(APEX_CPU *cpu) { if (cpu->decode.has_insn) { /* Read operands from register file based on the instruction type */ switch (cpu->decode.opcode) { case OPCODE_ADD: { cpu->decode.rs1_value = cpu->regs[cpu->decode.rs1]; cpu->decode.rs2_value = cpu->regs[cpu->decode.rs2]; break; } case OPCODE_LOAD: { cpu->decode.rs1_value = cpu->regs[cpu->decode.rs1]; break; } case OPCODE_MOVC: { /* MOVC doesn't have register operands */ break; } } /* Copy data from decode latch to execute latch*/ cpu->execute = cpu->decode; cpu->decode.has_insn = FALSE; if (ENABLE_DEBUG_MESSAGES) { print_stage_content("Decode/RF", &cpu->decode); } } } /* * Execute Stage of APEX Pipeline * * Note: You are free to edit this function according to your implementation */ static void APEX_execute(APEX_CPU *cpu) { if (cpu->execute.has_insn) { /* Execute logic based on instruction type */ switch (cpu->execute.opcode) { case OPCODE_ADD: { cpu->execute.result_buffer = cpu->execute.rs1_value + cpu->execute.rs2_value; /* Set the zero flag based on the result buffer */ if (cpu->execute.result_buffer == 0) { cpu->zero_flag = TRUE; } else { cpu->zero_flag = FALSE; } break; } case OPCODE_LOAD: { cpu->execute.memory_address = cpu->execute.rs1_value + cpu->execute.imm; break; } case OPCODE_BZ: { if (cpu->zero_flag == TRUE) { /* Calculate new PC, and send it to fetch unit */ cpu->pc = cpu->execute.pc + cpu->execute.imm; /* Since we are using reverse callbacks for pipeline stages, * this will prevent the new instruction from being fetched in the current cycle*/ cpu->fetch_from_next_cycle = TRUE; /* Flush previous stages */ cpu->decode.has_insn = FALSE; /* Make sure fetch stage is enabled to start fetching from new PC */ cpu->fetch.has_insn = TRUE; } break; } case OPCODE_BNZ: { if (cpu->zero_flag == FALSE) { /* Calculate new PC, and send it to fetch unit */ cpu->pc = cpu->execute.pc + cpu->execute.imm; /* Since we are using reverse callbacks for pipeline stages, * this will prevent the new instruction from being fetched in the current cycle*/ cpu->fetch_from_next_cycle = TRUE; /* Flush previous stages */ cpu->decode.has_insn = FALSE; /* Make sure fetch stage is enabled to start fetching from new PC */ cpu->fetch.has_insn = TRUE; } break; } case OPCODE_MOVC: { cpu->execute.result_buffer = cpu->execute.imm; /* Set the zero flag based on the result buffer */ if (cpu->execute.result_buffer == 0) { cpu->zero_flag = TRUE; } else { cpu->zero_flag = FALSE; } break; } } /* Copy data from execute latch to memory latch*/ cpu->memory = cpu->execute; cpu->execute.has_insn = FALSE; if (ENABLE_DEBUG_MESSAGES) { print_stage_content("Execute", &cpu->execute); } } } /* * Memory Stage of APEX Pipeline * * Note: You are free to edit this function according to your implementation */ static void APEX_memory(APEX_CPU *cpu) { if (cpu->memory.has_insn) { switch (cpu->memory.opcode) { case OPCODE_ADD: { /* No work for ADD */ break; } case OPCODE_LOAD: { /* Read from data memory */ cpu->memory.result_buffer = cpu->data_memory[cpu->memory.memory_address]; break; } } /* Copy data from memory latch to writeback latch*/ cpu->writeback = cpu->memory; cpu->memory.has_insn = FALSE; if (ENABLE_DEBUG_MESSAGES) { print_stage_content("Memory", &cpu->memory); } } } /* * Writeback Stage of APEX Pipeline * * Note: You are free to edit this function according to your implementation */ static int APEX_writeback(APEX_CPU *cpu) { if (cpu->writeback.has_insn) { /* Write result to register file based on instruction type */ switch (cpu->writeback.opcode) { case OPCODE_ADD: { cpu->regs[cpu->writeback.rd] = cpu->writeback.result_buffer; break; } case OPCODE_LOAD: { cpu->regs[cpu->writeback.rd] = cpu->writeback.result_buffer; break; } case OPCODE_MOVC: { cpu->regs[cpu->writeback.rd] = cpu->writeback.result_buffer; break; } } cpu->insn_completed++; cpu->writeback.has_insn = FALSE; if (ENABLE_DEBUG_MESSAGES) { print_stage_content("Writeback", &cpu->writeback); } if (cpu->writeback.opcode == OPCODE_HALT) { /* Stop the APEX simulator */ return TRUE; } } /* Default */ return 0; } /* * This function creates and initializes APEX cpu. * * Note: You are free to edit this function according to your implementation */ APEX_CPU * APEX_cpu_init(const char *filename) { int i; APEX_CPU *cpu; if (!filename) { return NULL; } cpu = calloc(1, sizeof(APEX_CPU)); if (!cpu) { return NULL; } /* Initialize PC, Registers and all pipeline stages */ cpu->pc = 4000; memset(cpu->regs, 0, sizeof(int) * REG_FILE_SIZE); memset(cpu->data_memory, 0, sizeof(int) * DATA_MEMORY_SIZE); cpu->single_step = ENABLE_SINGLE_STEP; /* Parse input file and create code memory */ cpu->code_memory = create_code_memory(filename, &cpu->code_memory_size); if (!cpu->code_memory) { free(cpu); return NULL; } if (ENABLE_DEBUG_MESSAGES) { fprintf(stderr, "APEX_CPU: Initialized APEX CPU, loaded %d instructions\n", cpu->code_memory_size); fprintf(stderr, "APEX_CPU: PC initialized to %d\n", cpu->pc); fprintf(stderr, "APEX_CPU: Printing Code Memory\n"); printf("%-9s %-9s %-9s %-9s %-9s\n", "opcode_str", "rd", "rs1", "rs2", "imm"); for (i = 0; i < cpu->code_memory_size; ++i) { printf("%-9s %-9d %-9d %-9d %-9d\n", cpu->code_memory[i].opcode_str, cpu->code_memory[i].rd, cpu->code_memory[i].rs1, cpu->code_memory[i].rs2, cpu->code_memory[i].imm); } } /* To start fetch stage */ cpu->fetch.has_insn = TRUE; return cpu; } /* * APEX CPU simulation loop * * Note: You are free to edit this function according to your implementation */ void APEX_cpu_run(APEX_CPU *cpu) { char user_prompt_val; while (TRUE) { if (ENABLE_DEBUG_MESSAGES) { printf("--------------------------------------------\n"); printf("Clock Cycle #: %d\n", cpu->clock); printf("--------------------------------------------\n"); } if (APEX_writeback(cpu)) { /* Halt in writeback stage */ printf("APEX_CPU: Simulation Complete, cycles = %d instructions = %d\n", cpu->clock, cpu->insn_completed); break; } APEX_memory(cpu); APEX_execute(cpu); APEX_decode(cpu); APEX_fetch(cpu); print_reg_file(cpu); if (cpu->single_step) { printf("Press any key to advance CPU Clock or <q> to quit:\n"); scanf("%c", &user_prompt_val); if ((user_prompt_val == 'Q') || (user_prompt_val == 'q')) { printf("APEX_CPU: Simulation Stopped, cycles = %d instructions = %d\n", cpu->clock, cpu->insn_completed); break; } } cpu->clock++; } } /* * This function deallocates APEX CPU. * * Note: You are free to edit this function according to your implementation */ void APEX_cpu_stop(APEX_CPU *cpu) { free(cpu->code_memory); free(cpu); }

__MACOSX/apex_cpu_pipeline_simulator/._apex_cpu.c

apex_cpu_pipeline_simulator/file_parser.c

/* * file_parser.c * Contains functions to parse input file and create code memory, you can edit * this file to add new instructions * * Author: * Copyright (c) 2020, Gaurav Kothari (gkothar1@binghamton.edu) * State University of New York at Binghamton */ #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "apex_cpu.h" #include "apex_macros.h" /* * This function is related to parsing input file * * Note : You are not supposed to edit this function */ static int get_num_from_string(const char *buffer) { char str[16]; int i, j = 0; for (i = 1; buffer[i] != '\0'; ++i) { str[j] = buffer[i]; j++; } str[j] = '\0'; return atoi(str); } /* * This function sets the numeric opcode to an instruction based on string value * * Note : you can edit this function to add new instructions */ static int set_opcode_str(const char *opcode_str) { if (strcmp(opcode_str, "ADD") == 0) { return OPCODE_ADD; } if (strcmp(opcode_str, "SUB") == 0) { return OPCODE_SUB; } if (strcmp(opcode_str, "MUL") == 0) { return OPCODE_MUL; } if (strcmp(opcode_str, "DIV") == 0) { return OPCODE_DIV; } if (strcmp(opcode_str, "AND") == 0) { return OPCODE_AND; } if (strcmp(opcode_str, "OR") == 0) { return OPCODE_OR; } if (strcmp(opcode_str, "EXOR") == 0) { return OPCODE_XOR; } if (strcmp(opcode_str, "MOVC") == 0) { return OPCODE_MOVC; } if (strcmp(opcode_str, "LOAD") == 0) { return OPCODE_LOAD; } if (strcmp(opcode_str, "STORE") == 0) { return OPCODE_STORE; } if (strcmp(opcode_str, "BZ") == 0) { return OPCODE_BZ; } if (strcmp(opcode_str, "BNZ") == 0) { return OPCODE_BNZ; } if (strcmp(opcode_str, "HALT") == 0) { return OPCODE_HALT; } assert(0 && "Invalid opcode"); return 0; } static void split_opcode_from_insn_string(char *buffer, char tokens[2][128]) { int token_num = 0; char *token = strtok(buffer, " "); while (token != NULL) { strcpy(tokens[token_num], token); token_num++; token = strtok(NULL, " "); } } /* * This function is related to parsing input file * * Note : you can edit this function to add new instructions */ static void create_APEX_instruction(APEX_Instruction *ins, char *buffer) { int i, token_num = 0; char tokens[6][128]; char top_level_tokens[2][128]; for (i = 0; i < 2; ++i) { strcpy(top_level_tokens[i], ""); } split_opcode_from_insn_string(buffer, top_level_tokens); char *token = strtok(top_level_tokens[1], ","); while (token != NULL) { strcpy(tokens[token_num], token); token_num++; token = strtok(NULL, ","); } strcpy(ins->opcode_str, top_level_tokens[0]); ins->opcode = set_opcode_str(ins->opcode_str); switch (ins->opcode) { case OPCODE_ADD: case OPCODE_SUB: case OPCODE_MUL: case OPCODE_DIV: case OPCODE_AND: case OPCODE_OR: case OPCODE_XOR: { ins->rd = get_num_from_string(tokens[0]); ins->rs1 = get_num_from_string(tokens[1]); ins->rs2 = get_num_from_string(tokens[2]); break; } case OPCODE_MOVC: { ins->rd = get_num_from_string(tokens[0]); ins->imm = get_num_from_string(tokens[1]); break; } case OPCODE_LOAD: { ins->rd = get_num_from_string(tokens[0]); ins->rs1 = get_num_from_string(tokens[1]); ins->imm = get_num_from_string(tokens[2]); break; } case OPCODE_STORE: { ins->rs1 = get_num_from_string(tokens[0]); ins->rs2 = get_num_from_string(tokens[1]); ins->imm = get_num_from_string(tokens[2]); break; } case OPCODE_BZ: case OPCODE_BNZ: { ins->imm = get_num_from_string(tokens[0]); break; } } /* Fill in rest of the instructions accordingly */ } /* * This function is related to parsing input file * * Note : You are not supposed to edit this function */ APEX_Instruction * create_code_memory(const char *filename, int *size) { FILE *fp; ssize_t nread; size_t len = 0; char *line = NULL; int code_memory_size = 0; int current_instruction = 0; APEX_Instruction *code_memory; if (!filename) { return NULL; } fp = fopen(filename, "r"); if (!fp) { return NULL; } while ((nread = getline(&line, &len, fp)) != -1) { code_memory_size++; } *size = code_memory_size; if (!code_memory_size) { fclose(fp); return NULL; } code_memory = calloc(code_memory_size, sizeof(APEX_Instruction)); if (!code_memory) { fclose(fp); return NULL; } rewind(fp); while ((nread = getline(&line, &len, fp)) != -1) { create_APEX_instruction(&code_memory[current_instruction], line); current_instruction++; } free(line); fclose(fp); return code_memory; }

__MACOSX/apex_cpu_pipeline_simulator/._file_parser.c

__MACOSX/._apex_cpu_pipeline_simulator

CAO Test Case.pdf

1. MOVC R1, #0

2. MOVC R2, #1

3. MOVC R3, #6

4. MOVC R4, #5

5. MOVC R5, #7

6. MOVC R6, #0

7. STORE R3, R1,#3

8. STORE R4, R1, #4

9. STORE R5, R1,#2

10. EXOR R7, R6, R2

11. CMP R7, R1

12. BNZ #16

13. LOAD R8, R1, #2

14. MUL R8, R8, R6

15. STR R8, R1, R2

16. LOAD R8, R1, #4

17. MUL R8, R8, R6

18. STORE R8, R1, #3

19. NOP

20. ADD R9, R8, R4

21. STORE R9, R1, #5

22. ADDL R6, R6, #1

23. CMP R6, R2

24. BZ #-56

25. HALT

CAO Test Case (1).xlsx

Sheet1

Part 1
Cycle 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
Register File Change R1 R2 R3 R4 R5 R6 R7 R8 R8(released) R8 R8 R8 R9 R6 R7 R8 R8 R8 R8 R8 R8 R6 R6
Fetch I1 I2 I3 I4 I5 I6 I7 I8 I9 I10 I11 I12 I12 I12 I13 I14 I16 I17 I18 I18 I18 I19 I19 I19 I20 I21 I22 I22 I22 I23 I24 I24 I24 I25 I10 I11 I12 I12 I12 I13 I14 I15 I15 I15 I16 I16 I16 I17 I18 I18 I18 I19 I19 I19 I20 I21 I22 I22 I22 I23 I24 I21 I24 I25
D/RF I1 I2 I3 I4 I5 I6 I7 I8 I9 I10 I11 I11 I11 I12 I13 I16 I17 I17 I17 I18 I18 I18 I19 I20 I21 I21 I21 I22 I23 I23 I23 I24 I25 I10 I11 I11 I11 I12 I13 I14 I14 I14 I15 I15 I15 I16 I17 I17 I17 I18 I18 I18 I19 I20 I21 I21 I21 I22 I23 I23 I23 I24 I25
EX I1 I2 I3 I4 I5 I6 I7 I8 I9 I10 I11 I12 I16 I17 I18 I19 I20 I21 I22 I23 I24 I10 I11 I12 I13 I14 I15 I16 I17 I18 I19 I20 I21 I22 I23 I24 I25
MEM I1 I2 I3 I4 I5 I6 I7 I8 I9 I10 I11 I12 I16 I17 I18 I19 I20 I21 I22 I23 I24 I10 I11 I12 I13 I14 I15 I16 I17 I18 I19 I20 I21 I22 I23 I24 I25
WB I1 I2 I3 I4 I5 I6 I7 I8 I9 I10 I11 I12 I16 I17 I18 I19 I20 I21 I22 I23 I24 I10 I11 I12 I13 I14 I15 I16 I17 I18 I19 I20 I21 I22 I23 I24 I25
Z Flag 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Memory Change MEM[3]=6 MEM[4]=5 MEM[2]=7 MEM[3]=0 MEM[5]=5 MEM[1]=7 MEM[3]=5 MEM[5]=10
Register File Update R1=0 R2=1 R3=6 R4=5 R5=7 R6=0 R7=1 R8=5 R8=0 R9=5 R6=1 R7=0 R8=7 R8=7 R8=5 R8=5 R9=10 R6=2
Part 2
Cycle 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
Fetch I1 I2 I3 I4 I5 I6 I7 I8 I9 I9 I9 I9 I10 I10 I10 I10 I11 I12 I12 I12 I12 I12 I13 I14 I16 I17 I18 I18 I18 I18 I18 I19 I19 I19 I19 I20 I21 I21 I21 I21 I22 I22 I24 I24 I24 I24 I24 I24 I25 I10 I11 I12 I12 I13 I14 I15 I15 I15 I15 I15 I16 I16 I16 I16 I17 I17 I17 I17 I18 I18 I18 I18 I18 I19 I19 I19 I19 I20 I21 I21 I21 I21 I22 I22 I23 I24 I24 I24 I24 I24 I25
D/RF I1 I2 I3 I4 I5 I6 I7 I8 I8 I8 I8 I9 I9 I9 I9 I10 I11 I11 I11 I11 I11 I12 I13 I16 I17 I17 I17 I17 I17 I18 I18 I18 I18 I19 I20 I20 I20 I20 I21 I21 I23 I23 I23 I23 I23 I23 I24 I25 I10 I11 I11 I12 I13 I14 I14 I14 I14 I14 I15 I15 I15 I15 I16 I16 I16 I16 I17 I17 I17 I17 I17 I18 I18 I18 I18 I19 I20 I20 I20 I20 I21 I21 I22 I23 I23 I23 I23 I23 I24 I25
Integer FU I1 I2 I3 I4 I5 I6 I10 I10 I10 I10 I11 I12 I19 I19 I19 I19 I20 I22 I22 I22 I22 I22 I23 I24 I10 I11 I12 I19 I19 I19 I19 I20 I22 I22 I22 I22 I23 I24 I25
Multiplication FU I14 I14 I14 I17 I17 I17
Load/Store FU I7 I7 I7 I7 I8 I8 I8 I8 I9 I9 I9 I9 I16 I16 I16 I16 I17 I17 I17 I18 I18 I18 I18 I21 I21 I21 I21 I13 I13 I13 I13 I15 I15 I15 I15 I16 I16 I16 I16 I18 I18 I18 I18 I21 I21 I21 I21
WB I1 I2 I3 I4 I5 I6 I7 I8 I9 I10 I11 I12 I16 I17 I18 I19 I20 I21 I22 I23 I24 I10 I11 I12 I13 I14 I15 I16 I17 I18 I19 I20 I21 I22 I23 I24 I25
Zero Flag 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Memory Change MEM[3]=6 MEM[4]=5 MEM[2]=7 MEM[3]=0 MEM[5]=5 MEM[1]=7 MEM[3]=5 MEM[5]=10
Register File Update R1=0 R2=1 R3=6 R4=5 R5=7 R6=0 R7=1 R8=5 R8=0 R9=5 R6=1 R7=0 R8=7 R8=7 R8=5 R8=5 R9=10 R6=2

P1 Display and submission guidelines.pdf

1. DISPLAY GUIDELINES

a. Sample Test Case

MOVC R0,#4000

MOVC R1,#1

MOVC R2,#2

MOVC R3,#3

MOVC R4,#1

ADD R5,R0,R1

SUB R3,R3,R4

CMP R3,R2

BZ #-12

MUL R7,R5,R2

MOVC R8,#0

AND R9,R7,R8

HALT

MOVC R10,#500

MOVC R11,#10

b. Expected Output for PART 1

CLOCK CYCLE 1

1. Instruction at FETCH STAGE ---> (I0: 4000) MOVC R0,#4000 2. Instruction at DECODE_RF_STAGE ---> EMPTY 3. Instruction at EX STAGE ---> EMPTY 4. Instruction at MEMORY STAGE ---> EMPTY 5. Instruction at WRITEBACK_STAGE ---> EMPTY

CLOCK CYCLE 2

1. Instruction at FETCH STAGE ---> (I1: 4004) MOVC R1,#1 2. Instruction at DECODE_RF_STAGE ---> (I0: 4000) MOVC R0,#4000 3. Instruction at EX STAGE ---> EMPTY

4. Instruction at MEMORY STAGE ---> EMPTY 5. Instruction at WRITEBACK_STAGE ---> EMPTY

CLOCK CYCLE 3

1. Instruction at FETCH STAGE ---> (I2: 4008) MOVC R2,#2 2. Instruction at DECODE_RF_STAGE ---> (I1: 4004) MOVC R1,#1 3. Instruction at EX STAGE ---> (I0: 4000) MOVC R0,#4000 4. Instruction at MEMORY STAGE ---> EMPTY

5. Instruction at WRITEBACK_STAGE ---> EMPTY

CLOCK CYCLE 4

1. Instruction at FETCH STAGE ---> (I3: 4012) MOVC R3,#3

2. Instruction at DECODE_RF_STAGE ---> (I2: 4008) MOVC R2,#2 3. Instruction at EX STAGE ---> (I1: 4004) MOVC R1,#1 4. Instruction at MEMORY STAGE ---> (I0: 4000) MOVC R0,#4000 5. Instruction at WRITEBACK_STAGE ---> EMPTY

CLOCK CYCLE 5

1. Instruction at FETCH STAGE ---> (I4: 4016) MOVC R4,#1 2. Instruction at DECODE_RF_STAGE ---> (I3: 4012) MOVC R3,#3 3. Instruction at EX STAGE ---> (I2: 4008) MOVC R2,#2 4. Instruction at MEMORY STAGE ---> (I1: 4004) MOVC R1,#1 5. Instruction at WRITEBACK_STAGE ---> (I0: 4000) MOVC R0,#4000

=============== STATE OF ARCHITECTURAL REGISTER FILE ==========

| REG[00] | Value = 4000 | Status = VALID | | REG[01] | Value = 1 | Status = VALID | | REG[02] | Value = 2 | Status = VALID | | REG[03] | Value = 2 | Status = VALID | | REG[04] | Value = 1 | Status = VALID | | REG[05] | Value = 4001 | Status = VALID | | REG[06] | Value = 00 | Status = VALID | | REG[07] | Value = 8002 | Status = VALID | | REG[08] | Value = 00 | Status = VALID | | REG[09] | Value = 00 | Status = VALID | | REG[10] | Value = 00 | Status = VALID | | REG[11] | Value = 00 | Status = VALID | | REG[12] | Value = 00 | Status = VALID | | REG[13] | Value = 00 | Status = VALID | | REG[14] | Value = 00 | Status = VALID | | REG[15] | Value = 00 | Status = VALID |

============== STATE OF DATA MEMORY =============

| |

|

MEM[00] MEM[01] MEM[02] .

| |

|

Data Value = 00 Data Value = 00 Data Value = 00

| |

|

.

.

| MEM[99] | Data Value = 00 |

c. Expected Output for PART 1

CLOCK CYCLE 1

1. Instruction at FETCH STAGE ---> (I0: 4000) MOVC R0,#4000 2. Instruction at DECODE_RF_STAGE ---> EMPTY 3. Instruction at INT_FU STAGE ---> EMPTY 4. Instruction at MUL_FU STAGE ---> EMPTY 5. Instruction at LS_FU STAGE ---> EMPTY 6. Instruction at WRITEBACK_STAGE ---> EMPTY

CLOCK CYCLE 2

1. Instruction at FETCH STAGE ---> (I1: 4004) MOVC R1,#1 2. Instruction at DECODE_RF_STAGE ---> (I0: 4000) MOVC R0,#4000 3. Instruction at INT_FU STAGE ---> EMPTY 4. Instruction at MUL_FU STAGE ---> EMPTY 5. Instruction at LS_FU STAGE ---> EMPTY

6. Instruction at WRITEBACK_STAGE --- EMPTY

CLOCK CYCLE 3

1. Instruction at FETCH STAGE ---> (I2: 4008) MOVC R2,#2 2. Instruction at DECODE_RF_STAGE ---> (I1: 4004) MOVC R1,#1 3. Instruction at INT_FU STAGE ---> (I0: 4000) MOVC R0,#4000 4. Instruction at MUL_FU STAGE ---> EMPTY 5. Instruction at LS_FU STAGE ---> EMPTY 6. Instruction at WRITEBACK_STAGE ---> EMPTY

CLOCK CYCLE 4

1. Instruction at FETCH STAGE ---> (I3: 4012) MOVC R3,#3

2. Instruction at DECODE_RF_STAGE ---> (I2: 4008) MOVC R2,#2 3. Instruction at INT_FU STAGE ---> (I1: 4004) MOVC R1,#1 4. Instruction at MUL_FU STAGE ---> EMPTY 5. Instruction at LS_FU STAGE ---> EMPTY 6. Instruction at WRITEBACK_STAGE ---> (I0: 4000) MOVC R0,#4000

CLOCK CYCLE 5

1. Instruction at FETCH STAGE ---> (I4: 4016) MOVC R4,#1 2. Instruction at DECODE_RF_STAGE ---> (I3: 4012) MOVC R3,#3

3. Instruction at INT_FU STAGE ---> (I2: 4008) MOVC R2,#2 4. Instruction at MUL_FU STAGE ---> EMPTY 5. Instruction at LS_FU STAGE ---> EMPTY 6. Instruction at WRITEBACK_STAGE ---> (I1: 4004) MOVC R1,#1

=============== STATE OF ARCHITECTURAL REGISTER FILE ==========

| REG[00] | Value = 4000 | Status = VALID | | REG[01] | Value = 1 | Status = VALID |

| REG[02] | Value = 2 | Status = VALID | | REG[03] | Value = 2 | Status = VALID | | REG[04] | Value = 1 | Status = VALID | | REG[05] | Value = 4001 | Status = VALID | | REG[06] | Value = 00 | Status = VALID | | REG[07] | Value = 8002 | Status = VALID | | REG[08] | Value = 00 | Status = VALID | | REG[09] | Value = 00 | Status = VALID | | REG[10] | Value = 00 | Status = VALID | | REG[11] | Value = 00 | Status = VALID | | REG[12] | Value = 00 | Status = VALID | | REG[13] | Value = 00 | Status = VALID | | REG[14] | Value = 00 | Status = VALID | | REG[15] | Value = 00 | Status = VALID |

============== STATE OF DATA MEMORY =============

| | |

MEM[00] MEM[01] MEM[02] .

| | |

Data Value = 00 Data Value = 00 Data Value = 00

| | |

.

.

| MEM[99] | Data Value = 00 |

2. Simulator Functions

1. There are four functions – simulate(), display(), single_step() and show_mem() which needs to be implemented as a part of project.

2. There should be second command line argument (simulate/display/single_step/show_mem) to distinguish these four functions:

a. Second command line argument is “simulate” which only shows State of Unified Physical Register File and Data Memory.

b. Second command line argument is “display” which shows Instruction Flow with all the states shown above, but DO NOT display State of Unified Physical Register File and Data Memory in each cycle (Note: Display State of Unified Physical Register File and Data Memory only at the end).

c. Second command line argument is “single_step” simulation by one cycle and shows Instruction Flow with all the states shown above, but DO NOT display State of Unified Physical Register File and Data Memory in each cycle (Note: Display State of Unified Physical Register File and Data Memory only at the end).

d. Second command line argument is “show_mem” which displays the content of a specific memory location, with the address of the memory location specific as an argument to this command.

3. There should be third command line argument as “number of cycles” means up to this number of cycles simulation should run and produce output.

4. Example with some of these command line arguments while running the program:

a. make b. ./apex_sim input.asm simulate 50

i. Simulate for 50 cycles and then show State of Unified Physical Register File and Data Memory at the end of 50 cycles or at the end of program (whichever comes first).

a. make c. ./apex_sim input.asm display 10

i. Simulate for 10 cycles and then show Instruction Flow as well as State of Unified Physical Register File and Data Memory at the end of 10 cycles or at the end of program (whichever comes first).

d. Make e. ./apex_sim input.asm single_step

i. Proceed one cycle and display all the states shown above, but DO NOT display State of Unified Physical Register File and Data Memory in each cycle (Note: Display State of Unified Physical Register File and Data Memory only at the end)

3. SUBMISSION GUIDELINES

In order get your grades as soon as possible and with more feedback, follow these

instructions, otherwise points will be deducted:

1. (-2 points) Check not to upload a corrupted file (you can download it and test it). 2. (-2 points) Submit a .tar.gz file (not a .tar nor .zip nor .rar) which should follow the

following naming convention: <lastname>_<firstname>_<bnumber>.tar.gz, after unpacking this .tar.gz it should have a directory named <lastname>_<firstname>_<bnumber>. Inside of this folder, you should have two folders: 1_part and 2_part (Note: Folder names should be exactly 1_part and _part) where corresponding simulators are located.

3. (-2 points) Check your code compile/run on bingsuns2.cc.binghamton.edu.

  • 1. DISPLAY GUIDELINES
    • a. Sample Test Case
    • b. Expected Output for PART 1
    • c. Expected Output for PART 1
  • 2. Simulator Functions
  • 3. SUBMISSION GUIDELINES