forked from darcykimball/best_cpu
/
cpu.c
172 lines (139 loc) · 4.51 KB
/
cpu.c
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <stdio.h>
#include "cpu.h"
#define DEBUG
const char* reg_names[] = { "A", "B", "C", "D", "E", "F", "G", "H" };
/* Instruction table */
typedef void (*instr_ptr) (void*, void*, void*);
instr_ptr instr_table[] = {
fetch,
store,
set,
add,
sub,
mul,
divide,
setc
};
/* Dump contents of registers */
void dump_registers(registers* regs) {
int i; /* to iterate through general-purpose registers */
if (regs == NULL) {
fprintf(stderr, "dump_registers: null pointer!!");
return;
}
/* Dump general-purpose registers */
fprintf(stdout, "General purpose:\n");
for (i = 0; i < N_REGIS; i++) {
if (i < sizeof(reg_names)) {
printf("Register %s: ", reg_names[i]);
}
DUMPINT(stdout, regs->general[i]);
}
/* Dump various special-purpose registers */
printf("Program counter:\n");
DUMPINT(stdout, regs->prog_counter);
printf("Memory address:\n");
DUMPINT(stdout, regs->mem_addr);
printf("Memory data:\n");
DUMPINT(stdout, regs->mem_data);
printf("Flags:\n");
DUMPINT(stdout, regs->flags);
}
/* Dump contents of memory */
void dump_memory(memory* mem) {
int i; /* to iterate over 32-bit words */
uint32_t* word; /* temp word to print */
/* Print out word-by-word */
printf("Main memory:\n");
word = (uint32_t*) mem->data;
for (i = 0; i < MEMSIZE/32; i++) {
printf("%08x\n", *word++);
}
}
void execute(registers* regs, memory* mem) {
int instr_index; /* Instruction index (for table) */
int nreg1; /* Index of first register in instruction */
int nreg2; /* Index of second register in instruction */
int nreg3; /* Index of second register in instruction */
/* 'Decode' instruction */
instr_index = GETINSTR(regs->prog_counter);
#ifdef DEBUG
fprintf(stderr, "prog_counter = %08x\n", regs->prog_counter);
fprintf(stderr, "Executing instruction # %u\n", instr_index);
#endif
/* Get register args */
nreg1 = GETOP1(regs->prog_counter);
nreg2 = GETOP2(regs->prog_counter);
nreg3 = GETOP3(regs->prog_counter);
#ifdef DEBUG
fprintf(stderr, "nreg1 = %u, reg1 = %08x\n", nreg1, regs->general[nreg1]);
fprintf(stderr, "nreg2 = %u, reg2 = %08x\n", nreg2, regs->general[nreg2]);
fprintf(stderr, "nreg3 = %u, reg3 = %08x\n", nreg3, regs->general[nreg3]);
#endif
/* 'Execute' the instruction */
if (instr_index == GETINSTR(FE_OP) || instr_index == GETINSTR(ST_OP)) {
/* This is a fetch/store instruction; need to pass in the memory */
instr_table[instr_index](mem, regs->general + nreg1, regs->general + nreg2);
} else if (instr_index == GETINSTR(SETC_OP)) {
/* This is a set constant instruction; have to pass the constant value */
instr_table[instr_index]((void*)GETCONST(regs->prog_counter),
regs->general + nreg1, NULL);
} else {
instr_table[instr_index](regs->general + nreg1, regs->general + nreg2,
regs->general + nreg3);
}
}
void fetch(void* mem, void* addr, void* dest) {
/* Set the value using the 'real' location in memory; the address stored in
* 'addr' is the simulated value, i.e. relative to the beginning of the
* simulated memory */
*(uint32_t*)dest =
*((uint32_t*)(((memory*)mem)->data + *(uint32_t*)addr));
}
void store(void* mem, void* src, void* addr) {
/* The offset calculation must be done in bytes here */
uint32_t* dest_addr = (uint32_t*)(((memory*)mem)->data + *(uint32_t*)addr);
#ifdef DEBUG
fprintf(stderr, "store: mem = %016x, addr = %08x, dest_addr = %016x\n",
mem, addr, dest_addr);
#endif
*dest_addr = *(uint32_t*)src;
}
void set(void* src, void* dest, void* unused) {
*(uint32_t*)dest = *(uint32_t*)src;
}
/* FIXME: add code for setting condition bits in flags register after each
* arithmetic operation */
void add(void* op1, void* op2, void* dest) {
*(int32_t*)dest = *(int32_t*)op1 + *(int32_t*)op2;
}
void sub(void* op1, void* op2, void* dest) {
*(int32_t*)dest = *(int32_t*)op1 - *(int32_t*)op2;
}
void mul(void* op1, void* op2, void* dest) {
*(int32_t*)dest = *(int32_t*)op1 * (*(int32_t*)op2);
}
void divide(void* op1, void* op2, void* dest) {
*(int32_t*)dest = *(int32_t*)op1 / *(int32_t*)op2;
}
void setc(void* num, void* dest, void* unused) {
#ifdef DEBUG
fprintf(stderr, "store: constant = %08x\n", (uint32_t)num);
#endif
*(uint32_t*)dest = (uint32_t)num;
}
/* TODO */
void sll(void* num, void* src, void* dest) {
}
/* TODO */
void srl(void* num, void* src, void* dest) {
}
/* TODO */
void andb(void* op1, void* op2, void* dest) {
}
/* TODO */
void orb(void* op1, void* op2, void* dest) {
}
/* TODO */
void xorb(void* op1, void* op2, void* dest) {
}