1
0
mirror of https://github.com/pevans/erc-c.git synced 2024-11-23 23:32:45 +00:00

Switch to vm_di for option variable storage

Things like disk1, disk2, width/height, etc.
This commit is contained in:
Peter Evans 2018-03-07 20:25:39 -06:00
parent 58190f0c9b
commit 4d4fbdf79a
7 changed files with 76 additions and 153 deletions

View File

@ -17,10 +17,8 @@ enum option_flags {
extern bool option_flag(int); extern bool option_flag(int);
extern FILE *option_get_input(int); extern FILE *option_get_input(int);
extern const char *option_get_error(); extern const char *option_get_error();
extern int option_get_height();
extern int option_get_width();
extern int option_parse(int, char **); extern int option_parse(int, char **);
extern int option_read_file(int, const char *); extern int option_read_file(FILE **, const char *);
extern int option_set_size(const char *); extern int option_set_size(const char *);
extern void option_print_help(); extern void option_print_help();
extern void option_set_error(const char *); extern void option_set_error(const char *);

View File

@ -7,6 +7,18 @@ enum vm_di_entry {
VM_REFLECT, VM_REFLECT,
VM_OUTPUT, VM_OUTPUT,
// These are the physical width and height of the emulator window
VM_WIDTH,
VM_HEIGHT,
// These are file streams that correspond to disk inputs; e.g., in
// an apple context, these would be from disk drives 1 and 2
VM_DISK1,
VM_DISK2,
// The log file to which we will output our disassembly
VM_DISASM_LOG,
// This value is the size of the DI container we will construct. As // This value is the size of the DI container we will construct. As
// you can see, it's quite a bit higher than what would be implied // you can see, it's quite a bit higher than what would be implied
// by the number of enum values currently defined--and it is so we // by the number of enum values currently defined--and it is so we

View File

@ -235,7 +235,7 @@ apple2_boot(apple2 *mach)
int err; int err;
// Do we have any disks? // Do we have any disks?
stream = option_get_input(1); stream = (FILE *)vm_di_get(VM_DISK1);
if (stream) { if (stream) {
err = apple2_dd_insert(mach->drive1, stream, DD_DOS33); err = apple2_dd_insert(mach->drive1, stream, DD_DOS33);
if (err != OK) { if (err != OK) {
@ -244,7 +244,7 @@ apple2_boot(apple2 *mach)
} }
} }
stream = option_get_input(2); stream = (FILE *)vm_di_get(VM_DISK2);
if (stream) { if (stream) {
err = apple2_dd_insert(mach->drive2, stream, DD_DOS33); err = apple2_dd_insert(mach->drive2, stream, DD_DOS33);
if (err != OK) { if (err != OK) {
@ -341,13 +341,13 @@ apple2_free(apple2 *mach)
void void
apple2_run_loop(apple2 *mach) apple2_run_loop(apple2 *mach)
{ {
FILE *out; FILE *dlog;
if (option_flag(OPTION_DISASSEMBLE)) { if (option_flag(OPTION_DISASSEMBLE)) {
return; return;
} }
out = (FILE *)vm_di_get(VM_OUTPUT); dlog = (FILE *)vm_di_get(VM_DISASM_LOG);
while (vm_screen_active(mach->screen)) { while (vm_screen_active(mach->screen)) {
if (vm_debug_broke(mach->cpu->PC)) { if (vm_debug_broke(mach->cpu->PC)) {
@ -360,7 +360,7 @@ apple2_run_loop(apple2 *mach)
mach->selected_drive->locked = true; mach->selected_drive->locked = true;
} }
mos6502_dis_opcode(mach->cpu, out, mach->cpu->PC); mos6502_dis_opcode(mach->cpu, dlog, mach->cpu->PC);
if (mach->selected_drive) { if (mach->selected_drive) {
mach->selected_drive->locked = false; mach->selected_drive->locked = false;
@ -381,7 +381,7 @@ apple2_run_loop(apple2 *mach)
mach->selected_drive->locked = true; mach->selected_drive->locked = true;
} }
mos6502_dis_opcode(mach->cpu, out, mach->cpu->PC); mos6502_dis_opcode(mach->cpu, dlog, mach->cpu->PC);
if (mach->selected_drive) { if (mach->selected_drive) {
mach->selected_drive->locked = false; mach->selected_drive->locked = false;

View File

@ -95,10 +95,12 @@ main(int argc, char **argv)
// successfully or if we run `exit()` from elsewhere in the program. // successfully or if we run `exit()` from elsewhere in the program.
atexit(finish); atexit(finish);
int *width = (int *)vm_di_get(VM_WIDTH);
int *height = (int *)vm_di_get(VM_HEIGHT);
// Let's build the basic machine, using the width and height // Let's build the basic machine, using the width and height
// indicated by the user. // indicated by the user.
mach = apple2_create(option_get_width(), mach = apple2_create(*width, *height);
option_get_height());
vm_di_set(VM_MACHINE, mach); vm_di_set(VM_MACHINE, mach);

View File

@ -13,6 +13,7 @@
#include "option.h" #include "option.h"
#include "log.h" #include "log.h"
#include "vm_di.h"
/* /*
* These are the file inputs we may have to the system. What their * These are the file inputs we may have to the system. What their
@ -22,6 +23,8 @@
static FILE *input1 = NULL; static FILE *input1 = NULL;
static FILE *input2 = NULL; static FILE *input2 = NULL;
static FILE *disasm_log = NULL;
/* /*
* The size of our error buffer for anything we want to record while our * The size of our error buffer for anything we want to record while our
* option parsing goes on. * option parsing goes on.
@ -61,7 +64,7 @@ enum options {
* Here are the options we support for program execution. * Here are the options we support for program execution.
*/ */
static struct option long_options[] = { static struct option long_options[] = {
{ "disassemble", 0, NULL, DISASSEMBLE }, { "disassemble", 1, NULL, DISASSEMBLE },
{ "disk1", 1, NULL, DISK1 }, { "disk1", 1, NULL, DISK1 },
{ "disk2", 1, NULL, DISK2 }, { "disk2", 1, NULL, DISK2 },
{ "flash", 0, NULL, FLASH }, { "flash", 0, NULL, FLASH },
@ -112,21 +115,32 @@ option_parse(int argc, char **argv)
error_buffer[0] = '\0'; error_buffer[0] = '\0';
do { do {
int input_source = 0;
opt = getopt_long_only(argc, argv, "", long_options, &index); opt = getopt_long_only(argc, argv, "", long_options, &index);
switch (opt) { switch (opt) {
case DISASSEMBLE: case DISASSEMBLE:
flags |= OPTION_DISASSEMBLE; flags |= OPTION_DISASSEMBLE;
if (!option_read_file(&disasm_log, optarg)) {
return 0;
}
vm_di_set(VM_DISASM_LOG, disasm_log);
break; break;
case DISK1: case DISK1:
input_source = 1; if (!option_read_file(&input1, optarg)) {
return 0;
}
vm_di_set(VM_DISK1, input1);
break; break;
case DISK2: case DISK2:
input_source = 2; if (!option_read_file(&input2, optarg)) {
return 0;
}
vm_di_set(VM_DISK2, input2);
break; break;
case FLASH: case FLASH:
@ -145,13 +159,6 @@ option_parse(int argc, char **argv)
} }
break; break;
} }
// We seem to have a request to load a file, so let's do so.
if (input_source) {
if (!option_read_file(input_source, optarg)) {
return 0;
}
}
} while (opt != -1); } while (opt != -1);
return 1; return 1;
@ -164,62 +171,27 @@ option_parse(int argc, char **argv)
* 0 if not. * 0 if not.
*/ */
int int
option_read_file(int source, const char *file) option_read_file(FILE **stream, const char *file)
{ {
FILE *stream;
if (!file) { if (!file) {
snprintf(error_buffer, snprintf(error_buffer,
ERRBUF_SIZE, ERRBUF_SIZE,
"No file given for --disk%d\n", "No file given for --diskN\n");
source);
return 0; return 0;
} }
stream = fopen(file, "r+"); *stream = fopen(file, "r+");
if (stream == NULL) { if (*stream == NULL) {
snprintf(error_buffer, snprintf(error_buffer,
ERRBUF_SIZE, ERRBUF_SIZE,
"--disk%d: %s", "--diskN: %s",
source,
strerror(errno)); strerror(errno));
return 0; return 0;
} }
option_set_input(source, stream);
return 1; return 1;
} }
/*
* Return the FILE stream for a given input, or NULL if none can be
* found. NULL may also be returned if the input has not previously been
* assigned.
*/
FILE *
option_get_input(int source)
{
switch (source) {
case 1: return input1;
case 2: return input2;
}
return NULL;
}
/*
* Set the given input source to a given FILE stream. If the input
* source is invalid, then nothing is done.
*/
void
option_set_input(int source, FILE *stream)
{
switch (source) {
case 1: input1 = stream;
case 2: input2 = stream;
}
}
/* /*
* Print out a help message. You'll note this is not automatically * Print out a help message. You'll note this is not automatically
* generated; it must be manually updated as we add other options. * generated; it must be manually updated as we add other options.
@ -230,7 +202,7 @@ option_print_help()
fprintf(stderr, "Usage: erc [options...]\n"); fprintf(stderr, "Usage: erc [options...]\n");
fprintf(stderr, "Options:\n"); fprintf(stderr, "Options:\n");
fprintf(stderr, "\ fprintf(stderr, "\
--disassemble Print assembly notation from CPU memory\n\ --disassemble=FILE Write assembly notation into FILE\n\
--disk1=FILE Load FILE into disk drive 1\n\ --disk1=FILE Load FILE into disk drive 1\n\
--disk2=FILE Load FILE into disk drive 2\n\ --disk2=FILE Load FILE into disk drive 2\n\
--flash Flash CPU memory with contents of drive 1\n\ --flash Flash CPU memory with contents of drive 1\n\
@ -255,6 +227,9 @@ option_set_size(const char *size)
} else if (strcmp(size, "875x600") == 0) { } else if (strcmp(size, "875x600") == 0) {
width = 875; width = 875;
height = 600; height = 600;
vm_di_set(VM_WIDTH, &width);
vm_di_set(VM_HEIGHT, &height);
return OK; return OK;
} }
@ -262,24 +237,6 @@ option_set_size(const char *size)
return ERR_BADOPT; return ERR_BADOPT;
} }
/*
* Return the window width we've been configured to use.
*/
int
option_get_width()
{
return width;
}
/*
* Return the window height we want.
*/
int
option_get_height()
{
return height;
}
/* /*
* Return true if the given option flag is set. * Return true if the given option flag is set.
*/ */

View File

@ -3,6 +3,7 @@
#include "apple2.h" #include "apple2.h"
#include "mos6502.enums.h" #include "mos6502.enums.h"
#include "option.h" #include "option.h"
#include "vm_di.h"
static apple2 *mach; static apple2 *mach;
@ -47,12 +48,23 @@ Test(apple2, boot)
// ][e" at the bottom. // ][e" at the bottom.
cr_assert_eq(apple2_boot(mach), OK); cr_assert_eq(apple2_boot(mach), OK);
FILE *stream1, *stream2;
// And, as you may guess, it's ok to reboot the machine. // And, as you may guess, it's ok to reboot the machine.
option_read_file(1, "../data/zero.img"); option_read_file(&stream1, "../data/zero.img");
vm_di_set(VM_DISK1, stream1);
cr_assert_eq(apple2_boot(mach), OK); cr_assert_eq(apple2_boot(mach), OK);
option_read_file(2, "../data/bad.img"); option_read_file(&stream2, "../data/bad.img");
vm_di_set(VM_DISK2, stream2);
cr_assert_neq(apple2_boot(mach), OK); cr_assert_neq(apple2_boot(mach), OK);
fclose(stream1);
fclose(stream2);
vm_di_set(VM_DISK1, NULL);
vm_di_set(VM_DISK2, NULL);
} }
Test(apple2, set_color) Test(apple2, set_color)

View File

@ -7,26 +7,11 @@ static void
setup() setup()
{ {
option_set_error(""); option_set_error("");
option_set_input(1, NULL);
option_set_input(2, NULL);
} }
static void static void
teardown() teardown()
{ {
FILE *stream;
for (int i = 1; i <= OPTION_MAX_DISKS; i++) {
stream = option_get_input(i);
if (stream
&& stream != stdout
&& stream != stderr
&& stream != stdin
) {
fclose(stream);
}
}
} }
TestSuite(options, .init = setup, .fini = teardown); TestSuite(options, .init = setup, .fini = teardown);
@ -46,44 +31,30 @@ Test(option, error)
cr_assert_str_eq(option_get_error(), str); cr_assert_str_eq(option_get_error(), str);
} }
/* Test(option, get_input) */
/* Test(option, set_input) */
Test(option, input)
{
cr_assert_eq(option_get_input(1), NULL);
cr_assert_eq(option_get_input(2), NULL);
option_set_input(2, stdout);
cr_assert_eq(option_get_input(2), stdout);
option_set_input(3, stderr);
cr_assert_eq(option_get_input(3), NULL);
}
Test(option, read_file) Test(option, read_file)
{ {
char *str = "so much FUN"; char *str = "so much FUN";
char *bad_file = "/tmp/BLEH"; char *bad_file = "/tmp/BLEH";
char *file = "/tmp/erc-test.txt"; char *file = "/tmp/erc-test.txt";
char buf[256]; char buf[256];
FILE *stream_a;
cr_assert_eq(option_get_input(1), NULL); FILE *stream_b;
// Maybe we should use sterror(ENOENT)? // Maybe we should use sterror(ENOENT)?
cr_assert_eq(option_read_file(1, bad_file), 0); cr_assert_eq(option_read_file(&stream_a, bad_file), 0);
cr_assert_str_eq(option_get_error(), "--disk1: No such file or directory"); cr_assert_str_eq(option_get_error(), "--diskN: No such file or directory");
option_set_error(""); option_set_error("");
FILE *stream; stream_a = fopen(file, "w");
stream = fopen(file, "w"); cr_assert_neq(stream_a, NULL);
cr_assert_neq(stream, NULL); fwrite(str, sizeof(char), strlen(str), stream_a);
fwrite(str, sizeof(char), strlen(str), stream); fclose(stream_a);
fclose(stream);
option_read_file(1, file); option_read_file(&stream_b, file);
fread(buf, sizeof(char), 255, option_get_input(1)); fread(buf, sizeof(char), 255, stream_b);
cr_assert_str_eq(buf, str); cr_assert_str_eq(buf, str);
fclose(stream_b);
unlink(file); unlink(file);
} }
@ -105,35 +76,6 @@ Test(option, parse)
cr_assert_eq(option_parse(argc, argv), 0); cr_assert_eq(option_parse(argc, argv), 0);
} }
/*
* The get_width and get_height tests also implicitly test the
* option_set_size() function (which is called by option_parse()).
* Test(option, set_size)
*/
Test(option, get_width)
{
int argc = 2;
char *argv[] = {
"prog_name",
"--size=875x600",
};
cr_assert_eq(option_parse(argc, argv), 1);
cr_assert_eq(option_get_width(), 875);
}
Test(option, get_height)
{
int argc = 2;
char *argv[] = {
"prog_name",
"--size=875x600",
};
cr_assert_eq(option_parse(argc, argv), 1);
cr_assert_eq(option_get_height(), 600);
}
Test(option, flag) Test(option, flag)
{ {
int argc = 2; int argc = 2;