Fri, 12 Apr 2013 16:26:25 +0100
Don't set PS1 if there is a level-7 interrupt or bus error
PS1 should only be set if the page was originally present (PS1 or PS0 set). If
PS0 and PS1 are clear (page not present) then do NOT set PS1.
Once again the TRM is blatantly and spectacularly wrong...
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@18 | 79 | fread(romdat1, 1, romlen, r15c); |
philpem@18 | 80 | fread(romdat2, 1, romlen2, r14c); |
philpem@18 | 81 | |
philpem@18 | 82 | // convert the ROM data |
philpem@18 | 83 | for (size_t i=0; i<(romlen + romlen2); i+=2) { |
philpem@18 | 84 | state.rom[i+0] = romdat1[i/2]; |
philpem@18 | 85 | state.rom[i+1] = romdat2[i/2]; |
philpem@18 | 86 | } |
philpem@18 | 87 | |
philpem@18 | 88 | // TODO: if ROM buffer not filled, repeat the ROM data we read until it is (wraparound emulation) |
philpem@18 | 89 | |
philpem@18 | 90 | // free the data arrays and close the files |
philpem@18 | 91 | free(romdat1); |
philpem@18 | 92 | free(romdat2); |
philpem@18 | 93 | fclose(r14c); |
philpem@18 | 94 | fclose(r15c); |
philpem@18 | 95 | |
philpem@52 | 96 | // Initialise the disc controller |
philpem@52 | 97 | wd2797_init(&state.fdc_ctx); |
philpem@80 | 98 | // Initialise the keyboard controller |
philpem@80 | 99 | keyboard_init(&state.kbd); |
philpem@52 | 100 | |
philpem@18 | 101 | return 0; |
philpem@18 | 102 | } |
philpem@18 | 103 | |
philpem@18 | 104 | void state_done() |
philpem@18 | 105 | { |
philpem@60 | 106 | if (state.base_ram != NULL) { |
philpem@60 | 107 | free(state.base_ram); |
philpem@60 | 108 | state.base_ram = NULL; |
philpem@18 | 109 | } |
philpem@62 | 110 | |
philpem@62 | 111 | if (state.exp_ram != NULL) { |
philpem@62 | 112 | free(state.exp_ram); |
philpem@62 | 113 | state.exp_ram = NULL; |
philpem@62 | 114 | } |
philpem@62 | 115 | |
philpem@52 | 116 | // Deinitialise the disc controller |
philpem@52 | 117 | wd2797_done(&state.fdc_ctx); |
philpem@112 | 118 | wd2010_done(&state.hdc_ctx); |
philpem@18 | 119 | } |
philpem@18 | 120 | |
philpem@18 | 121 |