risc5emu.c (9648B)
1 // Copyright © 2014 Peter De Wachter 2 // 3 // Permission to use, copy, modify, and/or distribute this software for 4 // any purpose with or without fee is hereby granted, provided that the 5 // above copyright notice and this permission notice appear in all 6 // copies. 7 // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 9 // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 // WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 11 // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 // DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 13 // PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 14 // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 // PERFORMANCE OF THIS SOFTWARE. 16 17 // based on src/risc5.c from git@github.com:pdewacht/oberon-risc-emu.git 18 19 #include <stdint.h> 20 #include <stdbool.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <stdio.h> 24 #include <unistd.h> 25 26 #include "risc5emu.h" 27 #include "risc5emu-fp.h" 28 #include "risc5.h" 29 30 static void disasm(uint32_t pc, uint32_t ins) { 31 char buf[256]; 32 risc5dis(pc, ins, buf); 33 printf("%08x: %08x %s\n", pc, ins, buf); 34 } 35 36 // Our memory layout is slightly different from the FPGA implementation: 37 // The FPGA uses a 20-bit address bus and thus ignores the top 12 bits, 38 // while we use all 32 bits. This allows us to have more than 1 megabyte 39 // of RAM. 40 41 #define DefaultMemSize 0x00100000 42 #define IOStart 0xFFFF0000 43 44 struct RISC { 45 uint32_t PC; 46 uint32_t R[16]; 47 uint32_t H; 48 bool Z, N, C, V; 49 50 uint32_t *RAM; 51 uint32_t mem_size; 52 bool TRACE; 53 }; 54 55 enum { 56 MOV, LSL, ASR, ROR, 57 AND, ANN, IOR, XOR, 58 ADD, SUB, MUL, DIV, 59 FAD, FSB, FML, FDV, 60 }; 61 62 static uint32_t risc_load_io(struct RISC *risc, uint32_t address); 63 static void risc_store_io(struct RISC *risc, uint32_t address, uint32_t value); 64 65 struct RISC *risc_new(bool trace) { 66 struct RISC *risc = calloc(1, sizeof(*risc)); 67 risc->mem_size = DefaultMemSize; 68 risc->RAM = calloc(1, risc->mem_size); 69 risc->TRACE = trace; 70 risc_reset(risc); 71 return risc; 72 } 73 74 void risc_trace(struct RISC *risc, bool trace) { 75 risc->TRACE = trace; 76 } 77 78 void risc_reset(struct RISC *risc) { 79 risc->PC = 0; 80 } 81 82 void risc_run(struct RISC *risc, int cycles) { 83 // The progress value is used to detect that the RISC cpu is busy 84 // waiting on the millisecond counter or on the keyboard ready 85 // bit. In that case it's better to just pause emulation until the 86 // next frame. 87 for (int i = 0; i < cycles; i++) { 88 risc_single_step(risc); 89 } 90 } 91 92 void risc_single_step(struct RISC *risc) { 93 uint32_t ir; 94 if (risc->PC < risc->mem_size / 4) { 95 ir = risc->RAM[risc->PC]; 96 } else { 97 fprintf(stderr, "Branched into the void (PC=0x%08X), resetting...\n", risc->PC); 98 exit(-1); 99 //risc_reset(risc); 100 return; 101 } 102 103 if (risc->TRACE) disasm(risc->PC << 2, ir); 104 risc->PC++; 105 106 const uint32_t pbit = 0x80000000; 107 const uint32_t qbit = 0x40000000; 108 const uint32_t ubit = 0x20000000; 109 const uint32_t vbit = 0x10000000; 110 111 if ((ir & pbit) == 0) { 112 // Register instructions 113 uint32_t a = (ir & 0x0F000000) >> 24; 114 uint32_t b = (ir & 0x00F00000) >> 20; 115 uint32_t op = (ir & 0x000F0000) >> 16; 116 uint32_t im = ir & 0x0000FFFF; 117 uint32_t c = ir & 0x0000000F; 118 119 uint32_t a_val, b_val, c_val; 120 b_val = risc->R[b]; 121 if ((ir & qbit) == 0) { 122 c_val = risc->R[c]; 123 } else if ((ir & vbit) == 0) { 124 c_val = im; 125 } else { 126 c_val = 0xFFFF0000 | im; 127 } 128 129 switch (op) { 130 case MOV: { 131 if ((ir & ubit) == 0) { 132 a_val = c_val; 133 } else if ((ir & qbit) != 0) { 134 a_val = c_val << 16; 135 } else if ((ir & vbit) != 0) { 136 a_val = 0xD0 | // ??? 137 (risc->N * 0x80000000U) | 138 (risc->Z * 0x40000000U) | 139 (risc->C * 0x20000000U) | 140 (risc->V * 0x10000000U); 141 } else { 142 a_val = risc->H; 143 } 144 break; 145 } 146 case LSL: { 147 a_val = b_val << (c_val & 31); 148 break; 149 } 150 case ASR: { 151 a_val = ((int32_t)b_val) >> (c_val & 31); 152 break; 153 } 154 case ROR: { 155 a_val = (b_val >> (c_val & 31)) | (b_val << (-c_val & 31)); 156 break; 157 } 158 case AND: { 159 a_val = b_val & c_val; 160 break; 161 } 162 case ANN: { 163 a_val = b_val & ~c_val; 164 break; 165 } 166 case IOR: { 167 a_val = b_val | c_val; 168 break; 169 } 170 case XOR: { 171 a_val = b_val ^ c_val; 172 break; 173 } 174 case ADD: { 175 a_val = b_val + c_val; 176 if ((ir & ubit) != 0) { 177 a_val += risc->C; 178 } 179 risc->C = a_val < b_val; 180 risc->V = ((a_val ^ c_val) & (a_val ^ b_val)) >> 31; 181 break; 182 } 183 case SUB: { 184 a_val = b_val - c_val; 185 if ((ir & ubit) != 0) { 186 a_val -= risc->C; 187 } 188 risc->C = a_val > b_val; 189 risc->V = ((b_val ^ c_val) & (a_val ^ b_val)) >> 31; 190 break; 191 } 192 case MUL: { 193 uint64_t tmp; 194 if ((ir & ubit) == 0) { 195 tmp = (int64_t)(int32_t)b_val * (int64_t)(int32_t)c_val; 196 } else { 197 tmp = (uint64_t)b_val * (uint64_t)c_val; 198 } 199 a_val = (uint32_t)tmp; 200 risc->H = (uint32_t)(tmp >> 32); 201 break; 202 } 203 case DIV: { 204 if ((int32_t)c_val > 0) { 205 if ((ir & ubit) == 0) { 206 a_val = (int32_t)b_val / (int32_t)c_val; 207 risc->H = (int32_t)b_val % (int32_t)c_val; 208 if ((int32_t)risc->H < 0) { 209 a_val--; 210 risc->H += c_val; 211 } 212 } else { 213 a_val = b_val / c_val; 214 risc->H = b_val % c_val; 215 } 216 } else { 217 struct idiv q = idiv(b_val, c_val, ir & ubit); 218 a_val = q.quot; 219 risc->H = q.rem; 220 } 221 break; 222 } 223 case FAD: { 224 a_val = fp_add(b_val, c_val, ir & ubit, ir & vbit); 225 break; 226 } 227 case FSB: { 228 a_val = fp_add(b_val, c_val ^ 0x80000000, ir & ubit, ir & vbit); 229 break; 230 } 231 case FML: { 232 a_val = fp_mul(b_val, c_val); 233 break; 234 } 235 case FDV: { 236 a_val = fp_div(b_val, c_val); 237 break; 238 } 239 default: { 240 abort(); // unreachable 241 } 242 } 243 risc_set_register(risc, a, a_val); 244 } 245 else if ((ir & qbit) == 0) { 246 // Memory instructions 247 uint32_t a = (ir & 0x0F000000) >> 24; 248 uint32_t b = (ir & 0x00F00000) >> 20; 249 int32_t off = ir & 0x000FFFFF; 250 off = (off ^ 0x00080000) - 0x00080000; // sign-extend 251 252 uint32_t address = risc->R[b] + off; 253 if ((ir & ubit) == 0) { 254 uint32_t a_val; 255 if ((ir & vbit) == 0) { 256 a_val = risc_load_word(risc, address); 257 } else { 258 a_val = risc_load_byte(risc, address); 259 } 260 risc_set_register(risc, a, a_val); 261 } else { 262 if ((ir & vbit) == 0) { 263 risc_store_word(risc, address, risc->R[a]); 264 } else { 265 risc_store_byte(risc, address, (uint8_t)risc->R[a]); 266 } 267 } 268 } 269 else { 270 // Branch instructions 271 bool t = (ir >> 27) & 1; 272 switch ((ir >> 24) & 7) { 273 case 0: t ^= risc->N; break; 274 case 1: t ^= risc->Z; break; 275 case 2: t ^= risc->C; break; 276 case 3: t ^= risc->V; break; 277 case 4: t ^= risc->C | risc->Z; break; 278 case 5: t ^= risc->N ^ risc->V; break; 279 case 6: t ^= (risc->N ^ risc->V) | risc->Z; break; 280 case 7: t ^= true; break; 281 default: abort(); // unreachable 282 } 283 if (t) { 284 if ((ir & vbit) != 0) { 285 risc_set_register(risc, 15, risc->PC * 4); 286 } 287 if ((ir & ubit) == 0) { 288 uint32_t c = ir & 0x0000000F; 289 risc->PC = risc->R[c] / 4; 290 } else { 291 int32_t off = ir & 0x00FFFFFF; 292 off = (off ^ 0x00800000) - 0x00800000; // sign-extend 293 risc->PC = risc->PC + off; 294 } 295 } 296 } 297 } 298 299 void risc_set_register(struct RISC *risc, int reg, uint32_t value) { 300 if (risc->TRACE) printf(" R%d = 0x%08x\n", reg, value); 301 risc->R[reg] = value; 302 risc->Z = value == 0; 303 risc->N = (int32_t)value < 0; 304 } 305 306 uint32_t risc_load_word(struct RISC *risc, uint32_t address) { 307 if (address < risc->mem_size) { 308 return risc->RAM[address/4]; 309 } else { 310 return risc_load_io(risc, address); 311 } 312 } 313 314 uint8_t risc_load_byte(struct RISC *risc, uint32_t address) { 315 uint32_t w = risc_load_word(risc, address); 316 return (uint8_t)(w >> (address % 4 * 8)); 317 } 318 319 void risc_store_word(struct RISC *risc, uint32_t address, uint32_t value) { 320 if (address < risc->mem_size) { 321 if (risc->TRACE) printf(" mem@ 0x%08x = 0x%08x\n", address, value); 322 risc->RAM[address/4] = value; 323 } else { 324 risc_store_io(risc, address, value); 325 } 326 } 327 328 void risc_store_byte(struct RISC *risc, uint32_t address, uint8_t value) { 329 if (address < risc->mem_size) { 330 uint32_t w = risc_load_word(risc, address); 331 uint32_t shift = (address & 3) * 8; 332 w &= ~(0xFFu << shift); 333 w |= (uint32_t)value << shift; 334 risc_store_word(risc, address, w); 335 } else { 336 risc_store_io(risc, address, (uint32_t)value); 337 } 338 } 339 340 static uint32_t risc_load_io(struct RISC *risc, uint32_t address) { 341 return 0; 342 } 343 344 static void risc_store_io(struct RISC *risc, uint32_t address, uint32_t value) { 345 if (risc->TRACE) printf(" io@ 0x%08x = 0x%08x\n", address, value); 346 switch (address - IOStart) { 347 case 0x100: { 348 printf("X %08x\n", value); 349 exit(0); 350 break; 351 case 0x104: 352 printf("D %08x\n", value); 353 break; 354 case 0x108: { 355 uint8_t x = value; 356 write(0, &x, 1); 357 break; 358 } 359 } 360 } 361 } 362