src/main.c

Sun, 28 Nov 2010 23:29:00 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 28 Nov 2010 23:29:00 +0000
changeset 17
138cb2576dbc
parent 16
6773a87e27b1
child 18
320dc6206f52
permissions
-rw-r--r--

add license clarification to boot banner

philpem@0 1 #include <stdio.h>
philpem@7 2 #include <stdlib.h>
philpem@4 3 #include <stdint.h>
philpem@7 4 #include <stdbool.h>
philpem@7 5 #include <malloc.h>
philpem@7 6 #include <string.h>
philpem@4 7 #include "musashi/m68k.h"
philpem@7 8 #include "version.h"
philpem@7 9
philpem@7 10 void state_done(void);
philpem@7 11
philpem@7 12 void FAIL(char *err)
philpem@7 13 {
philpem@7 14 state_done();
philpem@7 15 fprintf(stderr, "ERROR: %s\nExiting...\n", err);
philpem@7 16 exit(EXIT_FAILURE);
philpem@7 17 }
philpem@7 18
philpem@10 19 // Maximum size of the Boot PROMs. Must be a binary power of two.
philpem@10 20 #define ROM_SIZE 32768
philpem@7 21
philpem@7 22 struct {
philpem@7 23 // Boot PROM can be up to 32Kbytes total size
philpem@10 24 uint8_t rom[ROM_SIZE];
philpem@7 25
philpem@7 26 // Main system RAM
philpem@10 27 uint8_t *ram;
philpem@7 28 size_t ram_size; // number of RAM bytes allocated
philpem@7 29
philpem@7 30 // GENERAL CONTROL REGISTER
philpem@7 31 bool romlmap;
philpem@7 32 } state;
philpem@7 33
philpem@7 34 int state_init()
philpem@7 35 {
philpem@7 36 // Free RAM if it's allocated
philpem@7 37 if (state.ram != NULL)
philpem@7 38 free(state.ram);
philpem@7 39
philpem@7 40 // Initialise hardware registers
philpem@7 41 state.romlmap = false;
philpem@7 42
philpem@11 43 // Allocate RAM, making sure the user has specified a valid RAM amount first
philpem@11 44 // Basically: 512KiB minimum, 4MiB maximum, in increments of 512KiB.
philpem@11 45 if ((state.ram_size < 512*1024) || ((state.ram_size % (512*1024)) != 0))
philpem@11 46 return -1;
philpem@7 47 state.ram = malloc(state.ram_size);
philpem@7 48 if (state.ram == NULL)
philpem@11 49 return -2;
philpem@4 50
philpem@7 51 // Load ROMs
philpem@7 52 FILE *r14c, *r15c;
philpem@7 53 r14c = fopen("roms/14c.bin", "rb");
philpem@7 54 if (r14c == NULL) FAIL("unable to open roms/14c.bin");
philpem@7 55 r15c = fopen("roms/15c.bin", "rb");
philpem@7 56 if (r15c == NULL) FAIL("unable to open roms/15c.bin");
philpem@7 57
philpem@7 58 // get ROM file size
philpem@7 59 fseek(r14c, 0, SEEK_END);
philpem@7 60 size_t romlen = ftell(r14c);
philpem@7 61 fseek(r14c, 0, SEEK_SET);
philpem@7 62 fseek(r15c, 0, SEEK_END);
philpem@7 63 size_t romlen2 = ftell(r15c);
philpem@7 64 fseek(r15c, 0, SEEK_SET);
philpem@7 65 if (romlen2 != romlen) FAIL("ROMs are not the same size!");
philpem@10 66 if ((romlen + romlen2) > ROM_SIZE) FAIL("ROMs are too large to fit in memory!");
philpem@7 67
philpem@7 68 // sanity checks completed; load the ROMs!
philpem@7 69 uint8_t *romdat1, *romdat2;
philpem@7 70 romdat1 = malloc(romlen);
philpem@7 71 romdat2 = malloc(romlen2);
philpem@7 72 fread(romdat1, 1, romlen, r15c);
philpem@7 73 fread(romdat2, 1, romlen2, r14c);
philpem@7 74
philpem@7 75 // convert the ROM data
philpem@10 76 for (size_t i=0; i<(romlen + romlen2); i+=2) {
philpem@10 77 state.rom[i+0] = romdat1[i/2];
philpem@10 78 state.rom[i+1] = romdat2[i/2];
philpem@7 79 }
philpem@7 80
philpem@12 81 // TODO: if ROM buffer not filled, repeat the ROM data we read until it is (wraparound emulation)
philpem@10 82
philpem@7 83 // free the data arrays and close the files
philpem@7 84 free(romdat1);
philpem@7 85 free(romdat2);
philpem@7 86 fclose(r14c);
philpem@7 87 fclose(r15c);
philpem@7 88
philpem@7 89 return 0;
philpem@7 90 }
philpem@7 91
philpem@7 92 void state_done()
philpem@7 93 {
philpem@7 94 if (state.ram != NULL)
philpem@7 95 free(state.ram);
philpem@7 96 }
philpem@4 97
philpem@4 98 // read m68k memory
philpem@4 99 uint32_t m68k_read_memory_32(uint32_t address)
philpem@4 100 {
philpem@9 101 uint32_t data = 0xFFFFFFFF;
philpem@9 102
philpem@9 103 printf("RD32 %08X %d", address, state.romlmap);
philpem@9 104
philpem@7 105 // If ROMLMAP is set, force system to access ROM
philpem@7 106 if (!state.romlmap)
philpem@7 107 address |= 0x800000;
philpem@7 108
philpem@9 109 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@7 110 // ROM access
philpem@10 111 data = (((uint32_t)state.rom[(address + 0) & (ROM_SIZE - 1)] << 24) |
philpem@10 112 ((uint32_t)state.rom[(address + 1) & (ROM_SIZE - 1)] << 16) |
philpem@10 113 ((uint32_t)state.rom[(address + 2) & (ROM_SIZE - 1)] << 8) |
philpem@10 114 ((uint32_t)state.rom[(address + 3) & (ROM_SIZE - 1)]));
philpem@10 115 } else if (address < state.ram_size - 1) {
philpem@7 116 // RAM
philpem@10 117 data = (((uint32_t)state.ram[address + 0] << 24) |
philpem@10 118 ((uint32_t)state.ram[address + 1] << 16) |
philpem@10 119 ((uint32_t)state.ram[address + 2] << 8) |
philpem@10 120 ((uint32_t)state.ram[address + 3]));
philpem@7 121 }
philpem@9 122
philpem@10 123 printf(" ==> %08X\n", data);
philpem@9 124 return data;
philpem@4 125 }
philpem@4 126
philpem@4 127 uint32_t m68k_read_memory_16(uint32_t address)
philpem@4 128 {
philpem@9 129 uint16_t data = 0xFFFF;
philpem@9 130
philpem@9 131 printf("RD16 %08X %d", address, state.romlmap);
philpem@9 132
philpem@9 133 // If ROMLMAP is set, force system to access ROM
philpem@9 134 if (!state.romlmap)
philpem@9 135 address |= 0x800000;
philpem@9 136
philpem@10 137 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@10 138 // ROM access
philpem@10 139 data = ((state.rom[(address + 0) & (ROM_SIZE - 1)] << 8) |
philpem@10 140 (state.rom[(address + 1) & (ROM_SIZE - 1)]));
philpem@10 141 } else if (address < state.ram_size - 1) {
philpem@10 142 // RAM
philpem@10 143 data = ((state.ram[address + 0] << 8) |
philpem@10 144 (state.ram[address + 1]));
philpem@10 145 }
philpem@9 146
philpem@9 147 printf(" ==> %04X\n", data);
philpem@9 148 return data;
philpem@4 149 }
philpem@4 150
philpem@4 151 uint32_t m68k_read_memory_8(uint32_t address)
philpem@4 152 {
philpem@9 153 uint8_t data = 0xFF;
philpem@9 154
philpem@9 155 printf("RD 8 %08X %d ", address, state.romlmap);
philpem@9 156
philpem@7 157 // If ROMLMAP is set, force system to access ROM
philpem@7 158 if (!state.romlmap)
philpem@7 159 address |= 0x800000;
philpem@7 160
philpem@10 161 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@10 162 // ROM access
philpem@10 163 data = state.rom[(address + 0) & (ROM_SIZE - 1)];
philpem@10 164 } else if (address < state.ram_size) {
philpem@10 165 // RAM access
philpem@10 166 data = state.ram[address + 0];
philpem@10 167 }
philpem@9 168
philpem@9 169 printf("==> %02X\n", data);
philpem@9 170 return data;
philpem@4 171 }
philpem@4 172
philpem@4 173 // write m68k memory
philpem@4 174 void m68k_write_memory_32(uint32_t address, uint32_t value)
philpem@4 175 {
philpem@7 176 // If ROMLMAP is set, force system to access ROM
philpem@7 177 if (!state.romlmap)
philpem@7 178 address |= 0x800000;
philpem@7 179
philpem@9 180 printf("WR32 %08X %d %02X\n", address, state.romlmap, value);
philpem@9 181
philpem@9 182 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@7 183 // ROM access
philpem@7 184 // TODO: bus error here? can't write to rom!
philpem@10 185 } else if (address < state.ram_size) {
philpem@10 186 // RAM access
philpem@10 187 state.ram[address + 0] = (value >> 24) & 0xff;
philpem@10 188 state.ram[address + 1] = (value >> 16) & 0xff;
philpem@10 189 state.ram[address + 2] = (value >> 8) & 0xff;
philpem@10 190 state.ram[address + 3] = value & 0xff;
philpem@9 191 } else {
philpem@9 192 switch (address) {
philpem@9 193 case 0xE43000: state.romlmap = ((value & 0x8000) == 0x8000);
philpem@9 194 }
philpem@7 195 }
philpem@4 196 }
philpem@4 197
philpem@4 198 void m68k_write_memory_16(uint32_t address, uint32_t value)
philpem@4 199 {
philpem@7 200 // If ROMLMAP is set, force system to access ROM
philpem@7 201 if (!state.romlmap)
philpem@7 202 address |= 0x800000;
philpem@7 203
philpem@9 204 printf("WR16 %08X %d %02X\n", address, state.romlmap, value);
philpem@9 205
philpem@9 206 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@7 207 // ROM access
philpem@7 208 // TODO: bus error here? can't write to rom!
philpem@10 209 } else if (address < state.ram_size) {
philpem@10 210 // RAM access
philpem@10 211 state.ram[address + 0] = (value >> 8) & 0xff;
philpem@10 212 state.ram[address + 1] = value & 0xff;
philpem@9 213 } else {
philpem@9 214 switch (address) {
philpem@9 215 case 0xE43000: state.romlmap = ((value & 0x8000) == 0x8000);
philpem@9 216 }
philpem@7 217 }
philpem@4 218 }
philpem@4 219
philpem@4 220 void m68k_write_memory_8(uint32_t address, uint32_t value)
philpem@4 221 {
philpem@7 222 // If ROMLMAP is set, force system to access ROM
philpem@7 223 if (!state.romlmap)
philpem@7 224 address |= 0x800000;
philpem@7 225
philpem@9 226 printf("WR 8 %08X %d %02X\n", address, state.romlmap, value);
philpem@9 227
philpem@9 228 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@7 229 // ROM access
philpem@7 230 // TODO: bus error here? can't write to rom!
philpem@10 231 } else if (address < state.ram_size) {
philpem@10 232 state.ram[address] = value & 0xff;
philpem@9 233 } else {
philpem@9 234 switch (address) {
philpem@9 235 case 0xE43000: state.romlmap = ((value & 0x80) == 0x80);
philpem@9 236 }
philpem@7 237 }
philpem@4 238 }
philpem@4 239
philpem@10 240 // for the disassembler
philpem@9 241 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
philpem@9 242 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
philpem@9 243 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
philpem@9 244
philpem@0 245 int main(void)
philpem@0 246 {
philpem@7 247 // copyright banner
philpem@16 248 printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator. Version %s, %s mode.\n", VER_FULLSTR, VER_BUILD_TYPE);
philpem@17 249 printf("Copyright (C) 2010 P. A. Pemberton. All rights reserved.\nLicensed under the Apache License Version 2.0.\n");
philpem@17 250 printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
philpem@16 251 printf("Built %s by %s@%s.\n", VER_COMPILE_DATETIME, VER_COMPILE_BY, VER_COMPILE_HOST);
philpem@16 252 printf("Compiler: %s\n", VER_COMPILER);
philpem@16 253 printf("CFLAGS: %s\n", VER_CFLAGS);
philpem@17 254 printf("\n");
philpem@7 255
philpem@7 256 // set up system state
philpem@7 257 // 512K of RAM
philpem@7 258 state.ram_size = 512*1024;
philpem@7 259 state_init();
philpem@7 260
philpem@7 261 // set up musashi
philpem@7 262 m68k_set_cpu_type(M68K_CPU_TYPE_68010);
philpem@7 263 m68k_pulse_reset();
philpem@7 264
philpem@9 265 char dasm[512];
philpem@9 266 m68k_disassemble(dasm, 0x80001a, M68K_CPU_TYPE_68010);
philpem@9 267 printf("%s\n", dasm);
philpem@9 268
philpem@7 269 // set up SDL
philpem@7 270
philpem@7 271 // emulation loop!
philpem@7 272 // repeat:
philpem@7 273 // m68k_execute()
philpem@7 274 // m68k_set_irq() every 60ms
philpem@16 275 int32_t dwTimerTickCounter, dwCpuCycles;
philpem@16 276 const int32_t CLOCKS_PER_TIMER_TICK = 10e6/60; //< number of clocks per 60Hz timer tick
philpem@16 277
philpem@16 278 // initialise emulation variables
philpem@16 279 dwTimerTickCounter = CLOCKS_PER_TIMER_TICK;
philpem@16 280 bool exitEmu = false;
philpem@16 281 for (;;) {
philpem@16 282 dwCpuCycles = m68k_execute(10e6/60);
philpem@16 283 dwTimerTickCounter -= dwCpuCycles;
philpem@16 284
philpem@16 285 // check for timer tick expiry
philpem@16 286 if (dwTimerTickCounter <= 0) {
philpem@16 287 // TODO: Timer Tick IRQ
philpem@16 288
philpem@16 289 }
philpem@16 290
philpem@16 291 if (exitEmu) break;
philpem@16 292 }
philpem@7 293
philpem@7 294 // shut down and exit
philpem@7 295
philpem@0 296 return 0;
philpem@0 297 }