src/main.c

Sun, 28 Nov 2010 19:53:53 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 28 Nov 2010 19:53:53 +0000
changeset 7
7b98c7665aae
parent 4
21a7b07b6310
child 8
e2dcbabc7e1c
permissions
-rw-r--r--

set up ROM loader and state storage, add basic emulator core

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 #define ROM_SIZE (32768/4)
philpem@7 11
philpem@7 12 void state_done(void);
philpem@7 13
philpem@7 14 void FAIL(char *err)
philpem@7 15 {
philpem@7 16 state_done();
philpem@7 17 fprintf(stderr, "ERROR: %s\nExiting...\n", err);
philpem@7 18 exit(EXIT_FAILURE);
philpem@7 19 }
philpem@7 20
philpem@7 21
philpem@7 22 struct {
philpem@7 23 // Boot PROM can be up to 32Kbytes total size
philpem@7 24 uint32_t rom[ROM_SIZE];
philpem@7 25
philpem@7 26 // Main system RAM
philpem@7 27 uint32_t *ram;
philpem@7 28 size_t ram_size; // number of RAM bytes allocated
philpem@7 29 uint32_t ram_addr_mask; // address mask
philpem@7 30
philpem@7 31 // GENERAL CONTROL REGISTER
philpem@7 32 bool romlmap;
philpem@7 33 } state;
philpem@7 34
philpem@7 35 int state_init()
philpem@7 36 {
philpem@7 37 // Free RAM if it's allocated
philpem@7 38 if (state.ram != NULL)
philpem@7 39 free(state.ram);
philpem@7 40
philpem@7 41 // Initialise hardware registers
philpem@7 42 state.romlmap = false;
philpem@7 43
philpem@7 44 // Allocate RAM
philpem@7 45 // TODO: make sure ram size selection is valid!
philpem@7 46 state.ram = malloc(state.ram_size);
philpem@7 47 if (state.ram == NULL)
philpem@7 48 return -1;
philpem@7 49 state.ram_addr_mask = state.ram_size - 1;
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@7 66 if ((romlen / 4) > (ROM_SIZE / 2)) FAIL("ROM 14C is too big!");
philpem@7 67 if ((romlen2 / 4) > (ROM_SIZE / 2)) FAIL("ROM 15C is too big!");
philpem@7 68
philpem@7 69 // sanity checks completed; load the ROMs!
philpem@7 70 uint8_t *romdat1, *romdat2;
philpem@7 71 romdat1 = malloc(romlen);
philpem@7 72 romdat2 = malloc(romlen2);
philpem@7 73 fread(romdat1, 1, romlen, r15c);
philpem@7 74 fread(romdat2, 1, romlen2, r14c);
philpem@7 75
philpem@7 76 // convert the ROM data
philpem@7 77 for (size_t i=0; i<romlen; i+=2) {
philpem@7 78 state.rom[i/2] = (
philpem@7 79 (romdat1[i+0] << 24) |
philpem@7 80 (romdat2[i+0] << 16) |
philpem@7 81 (romdat1[i+1] << 8) |
philpem@7 82 (romdat2[i+1]));
philpem@7 83 }
philpem@7 84
philpem@7 85 for (int i=0; i<8; i++)
philpem@7 86 printf("%02X %02X ", romdat1[i], romdat2[i]);
philpem@7 87 printf("\n%08X %08X\n", state.rom[0], state.rom[1]);
philpem@7 88
philpem@7 89 // free the data arrays and close the files
philpem@7 90 free(romdat1);
philpem@7 91 free(romdat2);
philpem@7 92 fclose(r14c);
philpem@7 93 fclose(r15c);
philpem@7 94
philpem@7 95 return 0;
philpem@7 96 }
philpem@7 97
philpem@7 98 void state_done()
philpem@7 99 {
philpem@7 100 if (state.ram != NULL)
philpem@7 101 free(state.ram);
philpem@7 102 }
philpem@4 103
philpem@4 104 // read m68k memory
philpem@7 105 // TODO: refactor musashi to use stdint, and properly sized integers!
philpem@7 106 // TODO: find a way to make musashi use function pointers instead of hard coded callbacks, maybe use a context struct too
philpem@4 107 uint32_t m68k_read_memory_32(uint32_t address)
philpem@4 108 {
philpem@7 109 // If ROMLMAP is set, force system to access ROM
philpem@7 110 if (!state.romlmap)
philpem@7 111 address |= 0x800000;
philpem@7 112
philpem@7 113 if (address >= 0xC00000) {
philpem@7 114 // I/O Registers B
philpem@7 115 // TODO
philpem@7 116 } else if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@7 117 // ROM access
philpem@7 118 printf("%08X\n", state.rom[(address & (ROM_SIZE-1)) / 4]);
philpem@7 119 return state.rom[(address & (ROM_SIZE-1)) / 4];
philpem@7 120 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
philpem@7 121 // I/O Registers A
philpem@7 122 // TODO
philpem@7 123 } else if (address <= 0x3FFFFF) {
philpem@7 124 // RAM
philpem@7 125 return state.ram[(address & state.ram_addr_mask) / 4];
philpem@7 126 }
philpem@7 127 return 0xffffffff;
philpem@4 128 }
philpem@4 129
philpem@4 130 uint32_t m68k_read_memory_16(uint32_t address)
philpem@4 131 {
philpem@7 132 if (address & 2) {
philpem@7 133 return m68k_read_memory_32(address) & 0xFFFF;
philpem@7 134 } else {
philpem@7 135 return (m68k_read_memory_32(address) >> 16) & 0xFFFF;
philpem@7 136 }
philpem@4 137 }
philpem@4 138
philpem@4 139 uint32_t m68k_read_memory_8(uint32_t address)
philpem@4 140 {
philpem@7 141 // If ROMLMAP is set, force system to access ROM
philpem@7 142 if (!state.romlmap)
philpem@7 143 address |= 0x800000;
philpem@7 144
philpem@7 145 switch (address & 3) {
philpem@7 146 case 3: return m68k_read_memory_32(address) & 0xFF;
philpem@7 147 case 2: return (m68k_read_memory_32(address) >> 8) & 0xFF;
philpem@7 148 case 1: return (m68k_read_memory_32(address) >> 16) & 0xFF;
philpem@7 149 case 0: return (m68k_read_memory_32(address) >> 24) & 0xFF;
philpem@7 150 }
philpem@7 151 return 0xffffffff;
philpem@4 152 }
philpem@4 153
philpem@4 154 // write m68k memory
philpem@4 155 void m68k_write_memory_32(uint32_t address, uint32_t value)
philpem@4 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@7 161 if (address >= 0xC00000) {
philpem@7 162 // I/O Registers B
philpem@7 163 // TODO
philpem@7 164 } else if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@7 165 // ROM access
philpem@7 166 // TODO: bus error here? can't write to rom!
philpem@7 167 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
philpem@7 168 // I/O Registers A
philpem@7 169 // TODO
philpem@7 170 } else if (address <= 0x3FFFFF) {
philpem@7 171 // RAM
philpem@7 172 state.ram[(address & state.ram_addr_mask) / 4] = value;
philpem@7 173 }
philpem@4 174 }
philpem@4 175
philpem@4 176 void m68k_write_memory_16(uint32_t address, uint32_t value)
philpem@4 177 {
philpem@7 178 // If ROMLMAP is set, force system to access ROM
philpem@7 179 if (!state.romlmap)
philpem@7 180 address |= 0x800000;
philpem@7 181
philpem@7 182 if (address >= 0xC00000) {
philpem@7 183 // I/O Registers B
philpem@7 184 // TODO
philpem@7 185 } else if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@7 186 // ROM access
philpem@7 187 // TODO: bus error here? can't write to rom!
philpem@7 188 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
philpem@7 189 // I/O Registers A
philpem@7 190 // TODO
philpem@7 191 } else if (address <= 0x3FFFFF) {
philpem@7 192 // RAM
philpem@7 193 if (address & 2)
philpem@7 194 state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0xFFFF0000) | (value & 0xFFFF);
philpem@7 195 else
philpem@7 196 state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0x0000FFFF) | ((value & 0xFFFF) << 16);
philpem@7 197 }
philpem@4 198 }
philpem@4 199
philpem@4 200 void m68k_write_memory_8(uint32_t address, uint32_t value)
philpem@4 201 {
philpem@7 202 // If ROMLMAP is set, force system to access ROM
philpem@7 203 if (!state.romlmap)
philpem@7 204 address |= 0x800000;
philpem@7 205
philpem@7 206 if (address >= 0xC00000) {
philpem@7 207 // I/O Registers B
philpem@7 208 // TODO
philpem@7 209 } else if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@7 210 // ROM access
philpem@7 211 // TODO: bus error here? can't write to rom!
philpem@7 212 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
philpem@7 213 // I/O Registers A
philpem@7 214 // TODO
philpem@7 215 } else if (address <= 0x3FFFFF) {
philpem@7 216 // RAM
philpem@7 217 switch (address & 3) {
philpem@7 218 case 3: state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0xFFFFFF00) | (value & 0xFF);
philpem@7 219 case 2: state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0xFFFF00FF) | ((value & 0xFF) << 8);
philpem@7 220 case 1: state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0xFF00FFFF) | ((value & 0xFF) << 16);
philpem@7 221 case 0: state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0x00FFFFFF) | ((value & 0xFF) << 24);
philpem@7 222 }
philpem@7 223 }
philpem@4 224 }
philpem@4 225
philpem@0 226 int main(void)
philpem@0 227 {
philpem@7 228 // copyright banner
philpem@7 229 printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator\n");
philpem@7 230 printf("Copyright (C) 2010 P. A. Pemberton.\n");
philpem@7 231 printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
philpem@7 232
philpem@7 233 // set up system state
philpem@7 234 // 512K of RAM
philpem@7 235 state.ram_size = 512*1024;
philpem@7 236 state_init();
philpem@7 237
philpem@7 238 // set up musashi
philpem@7 239 m68k_set_cpu_type(M68K_CPU_TYPE_68010);
philpem@7 240 m68k_pulse_reset();
philpem@7 241
philpem@7 242 // set up SDL
philpem@7 243
philpem@7 244 // emulation loop!
philpem@7 245 // repeat:
philpem@7 246 // m68k_execute()
philpem@7 247 // m68k_set_irq() every 60ms
philpem@7 248 m68k_execute(100000);
philpem@7 249
philpem@7 250 // shut down and exit
philpem@7 251
philpem@0 252 return 0;
philpem@0 253 }