src/state.c

Wed, 16 Apr 2014 02:20:43 -0600

author
andrew@localhost
date
Wed, 16 Apr 2014 02:20:43 -0600
changeset 147
ad888290cdff
parent 138
d744db15cdf7
permissions
-rw-r--r--

fixed bus error handling for real this time (save registers before every instruction and push the saved registers if a bus error occurs, since the instruction may have changed registers before the bus error, and also stop the instruction immediately with longjmp so it won't change memory after the bus error)

This isn't actually what a real 68k does, but it is a good enough approximation. A real 68k will jump back into the middle of the faulted instruction and resume it from the memory access that faulted as opposed to restarting from the beginning like this CPU emulation does. It would be a lot harder to do that with the way this CPU library is designed. Newer versions of MESS basically do the same thing (they use a newer version of this library).

philpem@18 1 #define _STATE_C
philpem@18 2 #include <stddef.h>
philpem@18 3 #include <malloc.h>
philpem@18 4 #include <stdio.h>
philpem@52 5 #include "wd279x.h"
philpem@112 6 #include "wd2010.h"
philpem@80 7 #include "keyboard.h"
philpem@18 8 #include "state.h"
philpem@18 9
philpem@62 10 int state_init(size_t base_ram_size, size_t exp_ram_size)
philpem@18 11 {
philpem@18 12 // Free RAM if it's allocated
philpem@60 13 if (state.base_ram != NULL)
philpem@60 14 free(state.base_ram);
philpem@62 15 if (state.exp_ram != NULL)
philpem@62 16 free(state.exp_ram);
philpem@18 17
philpem@18 18 // Initialise hardware registers
philpem@18 19 state.romlmap = false;
philpem@75 20 state.idmarw = state.dmaen = state.dmaenb = false;
philpem@75 21 state.dma_count = state.dma_address = 0;
philpem@75 22 state.pie = 0;
philpem@101 23 state.ee = 0;
philpem@75 24 state.leds = 0;
philpem@75 25 state.genstat = 0; // FIXME: check this
philpem@75 26 state.bsr0 = state.bsr1 = 0; // FIXME: check this
philpem@97 27 state.timer_enabled = state.timer_asserted = false;
philpem@62 28 // Allocate Base RAM, making sure the user has specified a valid RAM amount first
philpem@62 29 // Basically: 512KiB minimum, 2MiB maximum, in increments of 512KiB.
philpem@62 30 if ((base_ram_size < 512*1024) || (base_ram_size > 2048*1024) || ((base_ram_size % (512*1024)) != 0))
philpem@18 31 return -1;
philpem@62 32 state.base_ram = malloc(base_ram_size);
philpem@60 33 if (state.base_ram == NULL)
philpem@18 34 return -2;
philpem@62 35 state.base_ram_size = base_ram_size;
philpem@62 36
philpem@62 37 // Now allocate expansion RAM
philpem@62 38 // The difference here is that we can have zero bytes of Expansion RAM; we're not limited to having a minimum of 512KiB.
philpem@62 39 if ((exp_ram_size > 2048*1024) || ((exp_ram_size % (512*1024)) != 0))
philpem@62 40 return -1;
philpem@62 41 state.exp_ram = malloc(exp_ram_size);
philpem@62 42 if (state.exp_ram == NULL)
philpem@62 43 return -2;
philpem@62 44 state.exp_ram_size = exp_ram_size;
philpem@18 45
philpem@18 46 // Load ROMs
philpem@18 47 FILE *r14c, *r15c;
philpem@18 48 r14c = fopen("roms/14c.bin", "rb");
philpem@55 49 if (r14c == NULL) {
philpem@55 50 fprintf(stderr, "[state] Error loading roms/14c.bin.\n");
philpem@55 51 return -3;
philpem@55 52 }
philpem@18 53 r15c = fopen("roms/15c.bin", "rb");
philpem@55 54 if (r15c == NULL) {
philpem@55 55 fprintf(stderr, "[state] Error loading roms/15c.bin.\n");
philpem@55 56 return -3;
philpem@55 57 }
philpem@18 58
philpem@18 59 // get ROM file size
philpem@18 60 fseek(r14c, 0, SEEK_END);
philpem@18 61 size_t romlen = ftell(r14c);
philpem@18 62 fseek(r14c, 0, SEEK_SET);
philpem@18 63 fseek(r15c, 0, SEEK_END);
philpem@18 64 size_t romlen2 = ftell(r15c);
philpem@18 65 fseek(r15c, 0, SEEK_SET);
philpem@55 66 if (romlen2 != romlen) {
philpem@55 67 fprintf(stderr, "[state] ROMs are not the same size!\n");
philpem@55 68 return -3;
philpem@55 69 }
philpem@55 70 if ((romlen + romlen2) > ROM_SIZE) {
philpem@55 71 fprintf(stderr, "[state] ROM files are too large!\n");
philpem@55 72 return -3;
philpem@55 73 }
philpem@18 74
philpem@18 75 // sanity checks completed; load the ROMs!
philpem@18 76 uint8_t *romdat1, *romdat2;
philpem@18 77 romdat1 = malloc(romlen);
philpem@18 78 romdat2 = malloc(romlen2);
philpem@138 79 if (fread(romdat1, 1, romlen, r15c) != romlen) {
philpem@138 80 fprintf(stderr, "[state] Error reading ROM 15C.\n");
philpem@138 81 return -3;
philpem@138 82 }
philpem@138 83 if (fread(romdat2, 1, romlen2, r14c) != romlen) {
philpem@138 84 fprintf(stderr, "[state] Error reading ROM 14C.\n");
philpem@138 85 return -3;
philpem@138 86 }
philpem@18 87
philpem@18 88 // convert the ROM data
philpem@18 89 for (size_t i=0; i<(romlen + romlen2); i+=2) {
philpem@18 90 state.rom[i+0] = romdat1[i/2];
philpem@18 91 state.rom[i+1] = romdat2[i/2];
philpem@18 92 }
philpem@18 93
philpem@18 94 // TODO: if ROM buffer not filled, repeat the ROM data we read until it is (wraparound emulation)
philpem@18 95
philpem@18 96 // free the data arrays and close the files
philpem@18 97 free(romdat1);
philpem@18 98 free(romdat2);
philpem@18 99 fclose(r14c);
philpem@18 100 fclose(r15c);
philpem@18 101
philpem@52 102 // Initialise the disc controller
philpem@52 103 wd2797_init(&state.fdc_ctx);
philpem@80 104 // Initialise the keyboard controller
philpem@80 105 keyboard_init(&state.kbd);
philpem@52 106
philpem@18 107 return 0;
philpem@18 108 }
philpem@18 109
philpem@18 110 void state_done()
philpem@18 111 {
philpem@60 112 if (state.base_ram != NULL) {
philpem@60 113 free(state.base_ram);
philpem@60 114 state.base_ram = NULL;
philpem@18 115 }
philpem@62 116
philpem@62 117 if (state.exp_ram != NULL) {
philpem@62 118 free(state.exp_ram);
philpem@62 119 state.exp_ram = NULL;
philpem@62 120 }
philpem@62 121
philpem@52 122 // Deinitialise the disc controller
philpem@52 123 wd2797_done(&state.fdc_ctx);
philpem@112 124 wd2010_done(&state.hdc_ctx);
philpem@18 125 }
philpem@18 126
philpem@18 127