사용방법
- 리눅스 시스템에서 해당 c 파일을 컴파일을 한다.
- 만약 그냥 컴파일 한다면 a.out으로 나온다.
- ./a.out runme.hex [0|1] 을 입력하면 된다.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
//clock cycles
long long cycles = 0;
// registers
long long int regs[32];
// program counter
unsigned long pc = 0;
// memory
#define INST_MEM_SIZE 32*1024
#define DATA_MEM_SIZE 32*1024
unsigned long inst_mem[INST_MEM_SIZE]; //instruction memory
unsigned long long data_mem[DATA_MEM_SIZE]; //data memory
//misc. function
int init(char* filename);
void print_cycles();
void print_reg();
void print_pc();
// define architecture size
#define arch_size 32
#define OPCODE 0
#define RS1 1
#define RS2 2
#define RD 3
#define IMM 4
#define RESULT 5
// instruction
unsigned long inst;
// for execution, opcode, rs1, rs2, rd, imm, result
int control[6];
// covert binary number to decimal number
int convert_bin2dec(unsigned short int* bit, int start, int end){
int value = 0;
int times = 1;
for (int i = start; i < end; i++){
value += bit[i] * times;
times *= 2;
}
return value;
}
// covert decimal number to binary number
unsigned short int* convert_dec2bin(unsigned long inst){
int rem = 0;
// unsigned short int bit[32] = {0,}; // instruction bit and initialize
unsigned short int* bit = (unsigned short int *)malloc(sizeof(int) * arch_size);
for (int i = 0; i < arch_size; i++) {
rem = inst % 2;
bit[i] = rem;
inst = inst / 2;
}
return bit;
}
void convert_1to0(unsigned short int* bit, int start, int end) {
for (int i = start; i < end; i++) {
if (bit[i] == 0)
bit[i] = 1;
else
bit[i] = 0;
}
}
//fetch an instruction from a instruction memory
void fetch() {
inst = inst_mem[pc / 4];
}
//decode the instruction and read data from register file
void decode() {
// unsigned short
unsigned short int* bit = convert_dec2bin(inst);
// only check add, addi, jal, jalr, lw, sw, beq
// add 0110011(51), 000, 0000000 R-Type need add, rs1, rs2, rd
// addi 0010011(19), 000, n.a I-Type need add, rs1, imm, rd
// jal 1101111(111), n.a, n.a UJ-Type need add, imm, rd
// jalr 1100111(103), 000, n.a I-Type need add, rs1, imm, rd
// lw 0000011(3), 010, n.a I-Type need add, rs1, imm, rd
// sw 0100011(35), 010, n.a S-Type need add, rs1, rs2, imm
// beq 1100011(99), 000, n.a SB-Type need add, rs1, rs2, imm
int opcode = convert_bin2dec(bit, 0, 7);
int rs1 = convert_bin2dec(bit, 15, 20);
int rs2 = convert_bin2dec(bit, 20, 25);
int rd = convert_bin2dec(bit, 7, 12);
int imm = 0;
switch (opcode)
{
case 51: // add
break;
case 19: // addi
if (bit[31] == 0)
imm = convert_bin2dec(bit, 20, 32);
else {
convert_1to0(bit, 20, 32);
imm = convert_bin2dec(bit, 20, 32);
imm = ~imm;
}
break;
case 111: // jal
if (bit[31] == 0){
imm = (convert_bin2dec(bit, 21 ,31) +
bit[20] * 2048 +
convert_bin2dec(bit, 12, 20) * 4096 +
bit[31] * 1048576) * 2;
}
else{
convert_1to0(bit, 21, 31);
convert_1to0(bit, 12, 20);
convert_1to0(bit, 31, 32);
convert_1to0(bit, 20, 21);
imm = convert_bin2dec(bit, 21 ,31) +
bit[20] * 2048 +
convert_bin2dec(bit, 12, 20) * 4096 +
bit[31] * 1048576;
imm = ~imm;
imm *= 2;
}
break;
case 103: // jalr
imm = convert_bin2dec(bit, 20, 32);
break;
case 3: // lw
imm = convert_bin2dec(bit, 20, 32);
break;
case 35: // sw
imm = convert_bin2dec(bit, 25, 32);
imm = imm * 32 + rd;
break;
case 99: // beq
if (bit[31] == 0){
imm = (convert_bin2dec(bit, 8, 12) +
convert_bin2dec(bit, 25, 31) * 32 +
bit[7] * 2048 +
bit[31] * 4096) * 2;
}
else{
convert_1to0(bit, 8, 12);
convert_1to0(bit, 25, 31);
convert_1to0(bit, 7, 8);
convert_1to0(bit, 31, 32);
imm = convert_bin2dec(bit, 8, 12) +
convert_bin2dec(bit, 25, 31) * 32 +
bit[7] * 2048 +
bit[31] * 4096;
imm = ~imm;
imm *= 2;
}
break;
default:
printf("Error Code!\n");
break;
}
control[OPCODE] = opcode;
control[RS1] = rs1;
control[RS2] = rs2;
control[RD] = rd;
control[IMM] = imm;
}
//perform the appropriate operation
void exe() {
switch (control[OPCODE])
{
case 51: // add
control[RESULT] = regs[control[RS1]] + regs[control[RS2]];
break;
case 19: // addi
control[RESULT] = regs[control[RS1]] + control[IMM];
break;
case 111: // jal
break;
case 103: // jalr
control[RESULT] = regs[control[RS1]] + control[IMM];
break;
case 3: // lw
control[RESULT] = regs[control[RS1]] + control[IMM];
break;
case 35: // sw
control[RESULT] = regs[control[RS1]] + control[IMM];
break;
case 99: // beq
control[RESULT] = regs[control[RS1]] - regs[control[RS2]];
break;
default:
printf("Error Code!\n");
break;
}
}
//access the data memory
void mem() {
switch (control[OPCODE])
{
case 51: // add
pc += 4;
break;
case 19: // addi
pc += 4;
break;
case 111: // jal
pc += control[IMM];
break;
case 103: // jalr
pc = control[RESULT];
break;
case 3: // lw
pc += 4;
control[RESULT] = data_mem[control[RESULT]];
break;
case 35: // sw
pc += 4;
data_mem[control[RESULT]] = regs[control[RS2]];
break;
case 99: //beq
if (control[RESULT] == 0)
pc += control[IMM];
else
pc += 4;
break;
default:
printf("Error Code!\n");
break;
}
}
//write result of arithmetic operation or data read from the data memory if required
void wb() {
switch (control[OPCODE])
{
case 51: // add
if (control[RD] != 0)
regs[control[RD]] = control[RESULT];
break;
case 19: // addi
if (control[RD] != 0)
regs[control[RD]] = control[RESULT];
break;
case 111: // jal
if (control[RD] != 0)
regs[control[RD]] = pc - control[IMM] + 4;
break;
case 103: // jalr
if (control[RD] != 0)
regs[control[RD]] = control[RESULT];
break;
case 3: // lw
regs[control[RD]] = control[RESULT];
break;
case 35: // sw
break;
case 99: // beq
break;
default:
printf("Error Code!\n");
break;
}
}
int main(int ac, char* av[])
{
if (ac < 3) // 인자가 3개 이하로 들어오면 오류 출력
{
printf("./riscv_sim filename mode\n");
return -1;
}
char done = 0;
if (init(av[1]) != 0) // av[1]에는 filename이 들어감
return -1;
// for (int k = 0; k < 5; k++)
while(!done)
{
fetch();
decode();
exe();
mem();
wb();
cycles++; //increase clock cycle
//if debug mode, print clock cycle, pc, reg
if (*av[2] == '0') {
print_cycles(); //print clock cycles
print_pc(); //print pc
print_reg(); //print registers
}
// check the exit condition, do not delete!!
if (regs[9] == 10) //if value in $t1 is 10, finish the simulation
done = 1;
}
if (*av[2] == '1')
{
print_cycles(); //print clock cycles
print_pc(); //print pc
print_reg(); //print registers
}
return 0;
}
/* initialize all datapat elements
//fill the instruction and data memory
//reset the registers
*/
int init(char* filename)
{
FILE* fp = fopen(filename, "r");
int i;
long inst;
if (fp == NULL)
{
fprintf(stderr, "Error opening file.\n");
return -1;
}
/* fill instruction memory */
i = 0;
while (fscanf(fp, "%lx", &inst) == 1)
{
inst_mem[i++] = inst; // 10 진수로 저장됨
}
/*reset the registers*/
for (i = 0; i < 32; i++)
{
regs[i] = 0;
}
/*reset pc*/
pc = 0;
/*reset clock cycles*/
cycles = 0;
return 0;
}
void print_cycles()
{
printf("---------------------------------------------------\n");
printf("Clock cycles = %lld\n", cycles);
}
void print_pc()
{
printf("PC = %ld\n\n", pc);
}
void print_reg()
{
printf("x0 = %d\n", regs[0]);
printf("x1 = %d\n", regs[1]);
printf("x2 = %d\n", regs[2]);
printf("x3 = %d\n", regs[3]);
printf("x4 = %d\n", regs[4]);
printf("x5 = %d\n", regs[5]);
printf("x6 = %d\n", regs[6]);
printf("x7 = %d\n", regs[7]);
printf("x8 = %d\n", regs[8]);
printf("x9 = %d\n", regs[9]);
printf("x10 = %d\n", regs[10]);
printf("x11 = %d\n", regs[11]);
printf("x12 = %d\n", regs[12]);
printf("x13 = %d\n", regs[13]);
printf("x14 = %d\n", regs[14]);
printf("x15 = %d\n", regs[15]);
printf("x16 = %d\n", regs[16]);
printf("x17 = %d\n", regs[17]);
printf("x18 = %d\n", regs[18]);
printf("x19 = %d\n", regs[19]);
printf("x20 = %d\n", regs[20]);
printf("x21 = %d\n", regs[21]);
printf("x22 = %d\n", regs[22]);
printf("x23 = %d\n", regs[23]);
printf("x24 = %d\n", regs[24]);
printf("x25 = %d\n", regs[25]);
printf("x26 = %d\n", regs[26]);
printf("x27 = %d\n", regs[27]);
printf("x28 = %d\n", regs[28]);
printf("x29 = %d\n", regs[29]);
printf("x30 = %d\n", regs[30]);
printf("x31 = %d\n", regs[31]);
printf("\n");
}
'Computer Science > 컴퓨터 구조' 카테고리의 다른 글
[컴퓨터 구조] Memory Technologies (0) | 2022.11.22 |
---|---|
[컴퓨터 구조] Introduction to the Memory Hierarchy (0) | 2022.11.22 |
[컴퓨터 구조] Control Hazard in Pipelined Datapath (0) | 2022.11.16 |
[컴퓨터 구조] Data Hazard in Pipelined Datapath (0) | 2022.11.16 |
[컴퓨터 구조] Pipelined Control (0) | 2022.11.16 |