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:
parent
58190f0c9b
commit
4d4fbdf79a
@ -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 *);
|
||||||
|
@ -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
|
||||||
|
12
src/apple2.c
12
src/apple2.c
@ -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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
99
src/option.c
99
src/option.c
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user