src/main.c

Sun, 28 Nov 2010 22:04:14 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 28 Nov 2010 22:04:14 +0000
changeset 11
67bf6abb6e79
parent 10
dbf4ba9563c9
child 12
0c5bddf0289e
permissions
-rw-r--r--

enforce RAM size requirements

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@10 81 for (size_t i=0; i<16; i++) printf("%02X ", state.rom[i]);
philpem@10 82 printf("\n");
philpem@10 83
philpem@10 84 // TODO: if ROM buffer not filled, repeat the ROM data we read until it is.
philpem@10 85
philpem@7 86 // free the data arrays and close the files
philpem@7 87 free(romdat1);
philpem@7 88 free(romdat2);
philpem@7 89 fclose(r14c);
philpem@7 90 fclose(r15c);
philpem@7 91
philpem@7 92 return 0;
philpem@7 93 }
philpem@7 94
philpem@7 95 void state_done()
philpem@7 96 {
philpem@7 97 if (state.ram != NULL)
philpem@7 98 free(state.ram);
philpem@7 99 }
philpem@4 100
philpem@4 101 // read m68k memory
philpem@4 102 uint32_t m68k_read_memory_32(uint32_t address)
philpem@4 103 {
philpem@9 104 uint32_t data = 0xFFFFFFFF;
philpem@9 105
philpem@9 106 printf("RD32 %08X %d", address, state.romlmap);
philpem@9 107
philpem@7 108 // If ROMLMAP is set, force system to access ROM
philpem@7 109 if (!state.romlmap)
philpem@7 110 address |= 0x800000;
philpem@7 111
philpem@9 112 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@7 113 // ROM access
philpem@10 114 data = (((uint32_t)state.rom[(address + 0) & (ROM_SIZE - 1)] << 24) |
philpem@10 115 ((uint32_t)state.rom[(address + 1) & (ROM_SIZE - 1)] << 16) |
philpem@10 116 ((uint32_t)state.rom[(address + 2) & (ROM_SIZE - 1)] << 8) |
philpem@10 117 ((uint32_t)state.rom[(address + 3) & (ROM_SIZE - 1)]));
philpem@10 118 } else if (address < state.ram_size - 1) {
philpem@7 119 // RAM
philpem@10 120 data = (((uint32_t)state.ram[address + 0] << 24) |
philpem@10 121 ((uint32_t)state.ram[address + 1] << 16) |
philpem@10 122 ((uint32_t)state.ram[address + 2] << 8) |
philpem@10 123 ((uint32_t)state.ram[address + 3]));
philpem@7 124 }
philpem@9 125
philpem@10 126 printf(" ==> %08X\n", data);
philpem@9 127 return data;
philpem@4 128 }
philpem@4 129
philpem@4 130 uint32_t m68k_read_memory_16(uint32_t address)
philpem@4 131 {
philpem@9 132 uint16_t data = 0xFFFF;
philpem@9 133
philpem@9 134 printf("RD16 %08X %d", address, state.romlmap);
philpem@9 135
philpem@9 136 // If ROMLMAP is set, force system to access ROM
philpem@9 137 if (!state.romlmap)
philpem@9 138 address |= 0x800000;
philpem@9 139
philpem@10 140 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@10 141 // ROM access
philpem@10 142 data = ((state.rom[(address + 0) & (ROM_SIZE - 1)] << 8) |
philpem@10 143 (state.rom[(address + 1) & (ROM_SIZE - 1)]));
philpem@10 144 } else if (address < state.ram_size - 1) {
philpem@10 145 // RAM
philpem@10 146 data = ((state.ram[address + 0] << 8) |
philpem@10 147 (state.ram[address + 1]));
philpem@10 148 }
philpem@9 149
philpem@9 150 printf(" ==> %04X\n", data);
philpem@9 151 return data;
philpem@4 152 }
philpem@4 153
philpem@4 154 uint32_t m68k_read_memory_8(uint32_t address)
philpem@4 155 {
philpem@9 156 uint8_t data = 0xFF;
philpem@9 157
philpem@9 158 printf("RD 8 %08X %d ", address, state.romlmap);
philpem@9 159
philpem@7 160 // If ROMLMAP is set, force system to access ROM
philpem@7 161 if (!state.romlmap)
philpem@7 162 address |= 0x800000;
philpem@7 163
philpem@10 164 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@10 165 // ROM access
philpem@10 166 data = state.rom[(address + 0) & (ROM_SIZE - 1)];
philpem@10 167 } else if (address < state.ram_size) {
philpem@10 168 // RAM access
philpem@10 169 data = state.ram[address + 0];
philpem@10 170 }
philpem@9 171
philpem@9 172 printf("==> %02X\n", data);
philpem@9 173 return data;
philpem@4 174 }
philpem@4 175
philpem@4 176 // write m68k memory
philpem@4 177 void m68k_write_memory_32(uint32_t address, uint32_t value)
philpem@4 178 {
philpem@7 179 // If ROMLMAP is set, force system to access ROM
philpem@7 180 if (!state.romlmap)
philpem@7 181 address |= 0x800000;
philpem@7 182
philpem@9 183 printf("WR32 %08X %d %02X\n", address, state.romlmap, value);
philpem@9 184
philpem@9 185 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@7 186 // ROM access
philpem@7 187 // TODO: bus error here? can't write to rom!
philpem@10 188 } else if (address < state.ram_size) {
philpem@10 189 // RAM access
philpem@10 190 state.ram[address + 0] = (value >> 24) & 0xff;
philpem@10 191 state.ram[address + 1] = (value >> 16) & 0xff;
philpem@10 192 state.ram[address + 2] = (value >> 8) & 0xff;
philpem@10 193 state.ram[address + 3] = value & 0xff;
philpem@9 194 } else {
philpem@9 195 switch (address) {
philpem@9 196 case 0xE43000: state.romlmap = ((value & 0x8000) == 0x8000);
philpem@9 197 }
philpem@7 198 }
philpem@4 199 }
philpem@4 200
philpem@4 201 void m68k_write_memory_16(uint32_t address, uint32_t value)
philpem@4 202 {
philpem@7 203 // If ROMLMAP is set, force system to access ROM
philpem@7 204 if (!state.romlmap)
philpem@7 205 address |= 0x800000;
philpem@7 206
philpem@9 207 printf("WR16 %08X %d %02X\n", address, state.romlmap, value);
philpem@9 208
philpem@9 209 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@7 210 // ROM access
philpem@7 211 // TODO: bus error here? can't write to rom!
philpem@10 212 } else if (address < state.ram_size) {
philpem@10 213 // RAM access
philpem@10 214 state.ram[address + 0] = (value >> 8) & 0xff;
philpem@10 215 state.ram[address + 1] = value & 0xff;
philpem@9 216 } else {
philpem@9 217 switch (address) {
philpem@9 218 case 0xE43000: state.romlmap = ((value & 0x8000) == 0x8000);
philpem@9 219 }
philpem@7 220 }
philpem@4 221 }
philpem@4 222
philpem@4 223 void m68k_write_memory_8(uint32_t address, uint32_t value)
philpem@4 224 {
philpem@7 225 // If ROMLMAP is set, force system to access ROM
philpem@7 226 if (!state.romlmap)
philpem@7 227 address |= 0x800000;
philpem@7 228
philpem@9 229 printf("WR 8 %08X %d %02X\n", address, state.romlmap, value);
philpem@9 230
philpem@9 231 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
philpem@7 232 // ROM access
philpem@7 233 // TODO: bus error here? can't write to rom!
philpem@10 234 } else if (address < state.ram_size) {
philpem@10 235 state.ram[address] = value & 0xff;
philpem@9 236 } else {
philpem@9 237 switch (address) {
philpem@9 238 case 0xE43000: state.romlmap = ((value & 0x80) == 0x80);
philpem@9 239 }
philpem@7 240 }
philpem@4 241 }
philpem@4 242
philpem@10 243 // for the disassembler
philpem@9 244 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
philpem@9 245 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
philpem@9 246 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
philpem@9 247
philpem@0 248 int main(void)
philpem@0 249 {
philpem@7 250 // copyright banner
philpem@7 251 printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator\n");
philpem@7 252 printf("Copyright (C) 2010 P. A. Pemberton.\n");
philpem@7 253 printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
philpem@7 254
philpem@7 255 // set up system state
philpem@7 256 // 512K of RAM
philpem@7 257 state.ram_size = 512*1024;
philpem@7 258 state_init();
philpem@7 259
philpem@7 260 // set up musashi
philpem@7 261 m68k_set_cpu_type(M68K_CPU_TYPE_68010);
philpem@7 262 m68k_pulse_reset();
philpem@7 263
philpem@9 264 char dasm[512];
philpem@9 265 m68k_disassemble(dasm, 0x80001a, M68K_CPU_TYPE_68010);
philpem@9 266 printf("%s\n", dasm);
philpem@9 267
philpem@7 268 // set up SDL
philpem@7 269
philpem@7 270 // emulation loop!
philpem@7 271 // repeat:
philpem@7 272 // m68k_execute()
philpem@7 273 // m68k_set_irq() every 60ms
philpem@8 274 printf("ran for %d cycles\n", m68k_execute(100000));
philpem@7 275
philpem@7 276 // shut down and exit
philpem@7 277
philpem@0 278 return 0;
philpem@0 279 }