123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559 |
- #ifndef _HW_COM_C_
- #define _HW_COM_C_
- #ifndef STATIC_INLINE_HW_COM
- #define STATIC_INLINE_HW_COM STATIC_INLINE
- #endif
- #include "device_table.h"
- #ifdef HAVE_STRING_H
- #include <string.h>
- #else
- #ifdef HAVE_STRINGS_H
- #include <strings.h>
- #endif
- #endif
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #ifdef HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- enum {
- max_hw_com_registers = 8,
- };
- typedef struct _com_port {
- int ready;
- int delay;
- int interrupting;
- FILE *file;
- } com_port;
- typedef struct _com_modem {
- int carrier;
- int carrier_changed;
- int interrupting;
- } com_modem;
- typedef struct _hw_com_device {
- com_port input;
- com_port output;
- com_modem modem;
- char dlab[2];
- char reg[max_hw_com_registers];
- int interrupting;
- } hw_com_device;
- static void
- hw_com_device_init_data(device *me)
- {
- hw_com_device *com = (hw_com_device*)device_data(me);
-
- if (com->output.file != NULL)
- fclose(com->output.file);
- if (com->input.file != NULL)
- fclose(com->input.file);
- memset(com, 0, sizeof(hw_com_device));
-
- com->output.delay = (device_find_property(me, "output-delay") != NULL
- ? device_find_integer_property(me, "output-delay")
- : 0);
- com->input.delay = (device_find_property(me, "input-delay") != NULL
- ? device_find_integer_property(me, "input-delay")
- : 0);
-
- if (device_find_property(me, "input-file") != NULL) {
- const char *input_file = device_find_string_property(me, "input-file");
- com->input.file = fopen(input_file, "r");
- if (com->input.file == NULL)
- device_error(me, "Problem opening input file %s\n", input_file);
- if (device_find_property(me, "input-buffering") != NULL) {
- const char *buffering = device_find_string_property(me, "input-buffering");
- if (strcmp(buffering, "unbuffered") == 0)
- setbuf(com->input.file, NULL);
- }
- }
- if (device_find_property(me, "output-file") != NULL) {
- const char *output_file = device_find_string_property(me, "output-file");
- com->output.file = fopen(output_file, "w");
- if (com->output.file == NULL)
- device_error(me, "Problem opening output file %s\n", output_file);
- if (device_find_property(me, "output-buffering") != NULL) {
- const char *buffering = device_find_string_property(me, "output-buffering");
- if (strcmp(buffering, "unbuffered") == 0)
- setbuf(com->output.file, NULL);
- }
- }
-
- com->input.ready = 1;
- com->modem.carrier = 1;
- com->output.ready = 1;
- }
- static void
- update_com_interrupts(device *me,
- hw_com_device *com)
- {
- int interrupting;
- com->modem.interrupting = (com->modem.carrier_changed && (com->reg[1] & 0x80));
- com->input.interrupting = (com->input.ready && (com->reg[1] & 0x1));
- com->output.interrupting = (com->output.ready && (com->reg[1] & 0x2));
- interrupting = (com->input.interrupting
- || com->output.interrupting
- || com->modem.interrupting);
- if (interrupting) {
- if (!com->interrupting) {
- device_interrupt_event(me, 0 , 1 , NULL, 0);
- }
- }
- else {
- if (com->interrupting)
- device_interrupt_event(me, 0 , 0 , NULL, 0);
- }
- com->interrupting = interrupting;
- }
- static void
- make_read_ready(void *data)
- {
- device *me = (device*)data;
- hw_com_device *com = (hw_com_device*)device_data(me);
- com->input.ready = 1;
- update_com_interrupts(me, com);
- }
- static void
- read_com(device *me,
- hw_com_device *com,
- unsigned_word a,
- char val[1])
- {
- unsigned_word addr = a % 8;
-
- if (com->reg[3] & 0x8 && addr < 2) {
- *val = com->dlab[addr];
- return;
- }
- switch (addr) {
-
- case 0:
-
- if (!com->modem.carrier)
- *val = '\0';
- if (com->input.ready) {
-
- if (com->input.file == NULL) {
- if (sim_io_read_stdin(val, 1) < 0)
- com->modem.carrier_changed = 1;
- }
- else {
- if (fread(val, 1, 1, com->input.file) == 0)
- com->modem.carrier_changed = 1;
- }
-
- if (com->modem.carrier_changed) {
-
- com->modem.carrier = 0;
- com->input.ready = 0;
- *val = '\0';
- }
- else if (com->input.delay > 0) {
- com->input.ready = 0;
- device_event_queue_schedule(me, com->input.delay, make_read_ready, me);
- }
- }
- else {
-
-
- *val = '\0';
- }
- break;
- case 2:
-
- if (com->interrupting) {
- if (com->input.interrupting)
- *val = 0x4;
- else if (com->output.interrupting)
- *val = 0x2;
- else if (com->modem.interrupting == 0)
- *val = 0;
- else
- device_error(me, "bad elif for interrupts\n");
- }
- else
- *val = 0x1;
- break;
- case 5:
-
- *val = ((com->input.ready ? 0x1 : 0)
- | (com->output.ready ? 0x60 : 0)
- );
- break;
- case 6:
-
- *val = ((com->modem.carrier_changed ? 0x08 : 0)
- | (com->modem.carrier ? 0x80 : 0)
- );
- com->modem.carrier_changed = 0;
- break;
- default:
- *val = com->reg[addr];
- break;
- }
- update_com_interrupts(me, com);
- }
- static unsigned
- hw_com_io_read_buffer_callback(device *me,
- void *dest,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
- {
- hw_com_device *com = device_data(me);
- int i;
- for (i = 0; i < nr_bytes; i++) {
- read_com(me, com, addr + i, &((char*)dest)[i]);
- }
- return nr_bytes;
- }
- static void
- make_write_ready(void *data)
- {
- device *me = (device*)data;
- hw_com_device *com = (hw_com_device*)device_data(me);
- com->output.ready = 1;
- update_com_interrupts(me, com);
- }
- static void
- write_com(device *me,
- hw_com_device *com,
- unsigned_word a,
- char val)
- {
- unsigned_word addr = a % 8;
-
- if (com->reg[3] & 0x8 && addr < 2) {
- com->dlab[addr] = val;
- return;
- }
- switch (addr) {
-
- case 0:
-
- if (com->output.file == NULL) {
- sim_io_write_stdout(&val, 1);
- }
- else {
- fwrite(&val, 1, 1, com->output.file);
- }
-
- if (com->output.ready && com->output.delay > 0) {
- com->output.ready = 0;
- device_event_queue_schedule(me, com->output.delay, make_write_ready, me);
- }
- break;
- default:
- com->reg[addr] = val;
- break;
- }
- update_com_interrupts(me, com);
- }
- static unsigned
- hw_com_io_write_buffer_callback(device *me,
- const void *source,
- int space,
- unsigned_word addr,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
- {
- hw_com_device *com = device_data(me);
- int i;
- for (i = 0; i < nr_bytes; i++) {
- write_com(me, com, addr + i, ((char*)source)[i]);
- }
- return nr_bytes;
- }
- static void
- hw_com_instance_delete(device_instance *instance)
- {
-
- return;
- }
- static int
- hw_com_instance_read(device_instance *instance,
- void *buf,
- unsigned_word len)
- {
- device *me = device_instance_device(instance);
- hw_com_device *com = device_data(me);
- if (com->input.file == NULL)
- return sim_io_read_stdin(buf, len);
- else {
- return fread(buf, 1, len, com->input.file);
- }
- }
- static int
- hw_com_instance_write(device_instance *instance,
- const void *buf,
- unsigned_word len)
- {
- device *me = device_instance_device(instance);
- hw_com_device *com = device_data(me);
- if (com->output.file == NULL)
- return sim_io_write_stdout(buf, len);
- else {
- return fwrite(buf, 1, len, com->output.file);
- }
- }
- static const device_instance_callbacks hw_com_instance_callbacks = {
- hw_com_instance_delete,
- hw_com_instance_read,
- hw_com_instance_write,
- };
- static device_instance *
- hw_com_create_instance(device *me,
- const char *path,
- const char *args)
- {
-
- return device_create_instance_from(me, NULL,
- device_data(me),
- path, args,
- &hw_com_instance_callbacks);
- }
- static device_callbacks const hw_com_callbacks = {
- { generic_device_init_address,
- hw_com_device_init_data },
- { NULL, },
- { hw_com_io_read_buffer_callback,
- hw_com_io_write_buffer_callback, },
- { NULL, },
- { NULL, },
- { NULL, },
- hw_com_create_instance,
- };
- static void *
- hw_com_create(const char *name,
- const device_unit *unit_address,
- const char *args)
- {
-
- hw_com_device *hw_com = ZALLOC(hw_com_device);
- return hw_com;
- }
- const device_descriptor hw_com_device_descriptor[] = {
- { "com", hw_com_create, &hw_com_callbacks },
- { NULL },
- };
- #endif
|