src/state.c

Mon, 14 Jan 2013 09:22:12 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 14 Jan 2013 09:22:12 +0000
changeset 118
feee84e0b3bf
parent 112
a392eb8f9806
child 138
d744db15cdf7
permissions
-rw-r--r--

More bus error fixes for FreeBee

I have fixed two more bus error handling bugs in FreeBee. First, the CPU core was executing the instruction regardless of whether a bus error occurs when fetching the opcode (which caused it to execute a bogus instruction in such cases). The other one was related to one of my previous fixes - the jump to the bus error vector was at the beginning of the main loop, so it wouldn't be called immediately after the bus error occurred if the timeslot expired, causing the return address to be off.

With these fixes, Unix now runs enough to get into userspace and run the install script (it is also possible to break out and get a shell prompt). However, many commands segfault semi-randomly (or more specifically, it seems that some child processes forked by the shell might be segfaulting before they can exec the command program), so installing the system isn't possible yet. I am not sure exactly what the bug is, but it seems to be related to some function in the shell returning null when the code calling it is assuming that it won't. What the function is, or why it is returning null, I'm not sure (the shell is built without the shared libc and is stripped, making identifying the function harder). I suspect that the function might be in libc, but that is hard to tell.

Author: Andrew Warkentin <andreww591 gmail com>

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