diff --git a/vimlac/Makefile b/vimlac/Makefile index ecdad67..4bb3c53 100644 --- a/vimlac/Makefile +++ b/vimlac/Makefile @@ -1,4 +1,6 @@ -OFILES = vimlac.o cpu.o dcpu.o ptr.o ptp.o memory.o kb.o ttyin.o ttyout.o trace.o +OFILES=cpu.o dcpu.o ptr.o ptp.o memory.o kbd.o ttyin.o ttyout.o trace.o +CFILES=cpu.c dcpu.c ptr.c ptp.c memory.c kbd.c ttyin.c ttyout.c trace.c error.c +HFILES=cpu.h dcpu.h ptr.h ptp.h memory.h kbd.h ttyin.h ttyout.h trace.h error.h CFLAGS=-shared -fPIC -O2 -Wall -ansi -pedantic -std=c99 -g @@ -10,6 +12,9 @@ vimlac: ${OFILES} Makefile #gcc -o vimlac.so -shared -fPIC ${OFILES} gcc -o vimlac ${OFILES} +test_cpu: test_cpu.c $(CFILES) $(HFILES) Makefile + gcc -o test_cpu test_cpu.c $(CFILES) + test_ptr: test_ptr.c ptr.c ptr.h Makefile gcc -o test_ptr ptr.c test_ptr.c diff --git a/vimlac/cpu.c b/vimlac/cpu.c index d0fd949..eae29d8 100755 --- a/vimlac/cpu.c +++ b/vimlac/cpu.c @@ -6,11 +6,11 @@ * * \******************************************************************************/ -#include "vimlac.h" +#include "imlac.h" #include "cpu.h" #include "dcpu.h" #include "memory.h" -#include "kb.h" +#include "kbd.h" #include "ptr.h" #include "ptp.h" #include "ttyin.h" @@ -492,7 +492,7 @@ Description : Emulate the DSF instruction. static int i_DSF(void) { - if (dcpu_on()) + if (dcpu_running()) r_PC = (r_PC + 1) & WORD_MASK; trace("DSF\t"); @@ -529,7 +529,7 @@ Description : Emulate the DSN instruction. static int i_DSN(void) { - if (!dcpu_on()) + if (!dcpu_running()) r_PC = (r_PC + 1) & WORD_MASK; trace("DSN\t"); @@ -585,7 +585,7 @@ Description : Emulate the IMLAC KCF instruction. static int i_KCF(void) { - kb_clear_flag(); + kbd_clear_flag(); trace("KCF\t"); @@ -602,7 +602,7 @@ Description : Emulate the IMLAC KRB instruction. static int i_KRB(void) { - r_AC |= kb_get_char(); + r_AC |= kbd_get_char(); trace("KRB\t"); @@ -619,8 +619,8 @@ Description : Emulate the IMLAC KRC instruction. static int i_KRC(void) { - r_AC |= kb_get_char(); - kb_clear_flag(); + r_AC |= kbd_get_char(); + kbd_clear_flag(); trace("KRC\t"); @@ -637,7 +637,7 @@ Description : Emulate the IMLAC KSF instruction. static int i_KSF(void) { - if (kb_ready()) + if (kbd_ready()) r_PC = (r_PC + 1) & WORD_MASK; trace("KSF\t"); @@ -655,7 +655,7 @@ Description : Emulate the IMLAC KSN instruction. static int i_KSN(void) { - if (!kb_ready()) + if (!kbd_ready()) r_PC = (r_PC + 1) & WORD_MASK; trace("KSN\t"); @@ -673,7 +673,9 @@ Description : Emulate the IMLAC PUN instruction. static int i_PUN(void) { - ptp_punch(r_AC & 0xff); + char value = r_AC & 0xff; + + ptp_punch(value); trace("PUN\t"); @@ -937,7 +939,9 @@ Description : Emulate the IMLAC TPC instruction. static int i_TPC(void) { - ttyout_send(r_AC & 0xff); + BYTE value = r_AC & 0xff; + + ttyout_send(value); ttyout_clear_flag(); trace("TPC\t"); @@ -1116,7 +1120,7 @@ Description : Emulate the IMLAC DLA instruction. static int i_DLA(void) { - dcpu_set_PC(r_AC); + dcpu_set_DPC(r_AC); trace("DLA\t"); diff --git a/vimlac/cpu.h b/vimlac/cpu.h index 93b34b2..e532e06 100755 --- a/vimlac/cpu.h +++ b/vimlac/cpu.h @@ -1,12 +1,15 @@ /******************************************************************************\ * cpu.h * * ------- * + * * + * Implements all main CPU instructions. * + * * \******************************************************************************/ #ifndef CPU_H #define CPU_H -#include "vimlac.h" +#include "imlac.h" /****** * Exported functions. diff --git a/vimlac/dcpu.c b/vimlac/dcpu.c new file mode 100755 index 0000000..9ead4ed --- /dev/null +++ b/vimlac/dcpu.c @@ -0,0 +1,181 @@ +/******************************************************************************\ + * dcpu.c * + * -------- * + * * + * This file is used to decode and execute a display processor instruction. * + * * +\******************************************************************************/ + +#include "imlac.h" +#include "dcpu.h" +#include "memory.h" +#include "trace.h" + + +/****** + * Emulated registers, state, memory, etc. + ******/ + +static WORD r_DPC; +static WORD Prev_r_DPC; +static WORD DRSindex = 0; + +/* 40Hz sync stuff */ +static bool Sync40HzOn = false; + +/****** + * Environment stuff. PTR and TTY in and out files, etc + ******/ + +static bool dcpu_on; /* true if display processor is running */ +static bool dcpu_sync_on; /* true if 40HZ flag set */ + + +/****************************************************************************** +Description : Function to get the display CPU status. + Parameters : + Returns : + Comments : + ******************************************************************************/ +bool +dcpu_running(void) +{ + return dcpu_on == true; +} + + +/****************************************************************************** +Description : Function to start the display CPU. + Parameters : + Returns : + Comments : + ******************************************************************************/ +void +dcpu_start(void) +{ + dcpu_on = true; +} + + +/****************************************************************************** +Description : Function to stop the display CPU. + Parameters : + Returns : + Comments : + ******************************************************************************/ +void +dcpu_stop(void) +{ + dcpu_on = false; +} + + +/****************************************************************************** +Description : Functions to get various registers. + Parameters : + Returns : + Comments : + ******************************************************************************/ +WORD +dcpu_get_DPC(void) +{ + return r_DPC; +} + + +WORD +dcpu_get_prev_DPC(void) +{ + return Prev_r_DPC; +} + + +void +dcpu_set_DPC(WORD new_dpc) +{ + r_DPC = new_dpc; +} + +void +dcpu_set_DRSindex(WORD drsindex) +{ + DRSindex = drsindex; +} + + +/****************************************************************************** +Description : Function to handle unrecognized instruction. + Parameters : + Returns : + Comments : + ******************************************************************************/ +static void +illegal(void) +{ + WORD oldDPC = Prev_r_DPC & MEMMASK; + + error("INTERNAL ERROR: " + "unexpected display processor opcode %06.6o at address %06.6o", + mem_get(oldDPC, false), oldDPC); +} + + +/****************************************************************************** +Description : + Parameters : + Returns : + Comments : + ******************************************************************************/ +static int +i_LAW_LWC(bool indirect, WORD address) +{ + return 1; +} + + +/****************************************************************************** +Description : Function to execute one display processor instruction. + Parameters : + Returns : The number of cycles the instruction took. + Comments : + ******************************************************************************/ +int +dcpu_execute_one(void) +{ + WORD instruction; + WORD opcode; + WORD address; + bool indirect; + +/****** + * If main processor not running, return immediately. + ******/ + + if (!dcpu_on) + return 0; + +/****** + * Fetch the instruction. Split into initial opcode and address. + ******/ + + Prev_r_DPC = r_DPC; + instruction = mem_get(r_DPC++, false); + r_DPC = r_DPC & MEMMASK; + + indirect = (bool) (instruction & 0100000); /* high bit set? */ + opcode = (instruction >> 11) & 017; /* high 5 bits */ + address = instruction & 03777; /* low 11 bits */ + +/****** + * Now decode it. + ******/ + + switch (opcode) + { + default: illegal(); + } + + return 0; /* CAN'T REACH */ +} + + diff --git a/vimlac/dcpu.h b/vimlac/dcpu.h new file mode 100755 index 0000000..d602f2d --- /dev/null +++ b/vimlac/dcpu.h @@ -0,0 +1,28 @@ +/******************************************************************************\ + * dcpu.h * + * -------- * + * * + * Implements all display CPU instructions. * + * * +\******************************************************************************/ + +#ifndef DCPU_H +#define DCPU_H + +#include "imlac.h" + +/****** + * Exported functions. + ******/ + +bool dcpu_running(void); +void dcpu_start(void); +void dcpu_stop(void); +void dcpu_set_DRSindex(WORD); +int dcpu_execute_one(void); +WORD dcpu_get_AC(void); +WORD dcpu_get_DPC(void); +WORD dcpu_get_prev_DPC(void); +void dcpu_set_DPC(WORD dpc); + +#endif diff --git a/vimlac/error.c b/vimlac/error.c new file mode 100644 index 0000000..d3b0bc8 --- /dev/null +++ b/vimlac/error.c @@ -0,0 +1,30 @@ +/* + * Error routines for the imlac simulator. + */ + +#include +#include +#include + + +/****************************************************************************** +Description : printf()-style trace routine. + Parameters : like printf() + Returns : + Comments : + ******************************************************************************/ +void +error(char *fmt, ...) +{ + va_list ap; + char buff[1024]; + + va_start(ap, fmt); + vsprintf(buff, fmt, ap); + fprintf(stderr, "%s\n", buff); + va_end(ap); + + exit(10); +} + + diff --git a/vimlac/error.h b/vimlac/error.h new file mode 100644 index 0000000..36720ed --- /dev/null +++ b/vimlac/error.h @@ -0,0 +1,10 @@ +/* + * Error routines for the imlac simulation. + */ + +#ifndef ERROR_H +#define ERROR_H + +void error(char *fmt, ...); + +#endif diff --git a/vimlac/kbd.c b/vimlac/kbd.c new file mode 100755 index 0000000..a9f0304 --- /dev/null +++ b/vimlac/kbd.c @@ -0,0 +1,58 @@ +/******************************************************************************\ + * kbd.c * + * ------- * + * * + * This file is used to implement a KBD device (keyboard). * + * * +\******************************************************************************/ + +#include "imlac.h" +#include "kbd.h" +#include "trace.h" + + +/****** + * Emulated registers, state, memory, etc. + ******/ + +static WORD state_KBD; +static bool clear = false; + + +/****************************************************************************** +Description : Clear the KBD (keyboard) flag. + Parameters : + Returns : + Comments : + ******************************************************************************/ +void +kbd_clear_flag(void) +{ + clear = false; +} + +/****************************************************************************** +Description : Get the character in the keyboard buffer. + Parameters : + Returns : + Comments : + ******************************************************************************/ +WORD +kbd_get_char(void) +{ + return 'a'; +} + +/****************************************************************************** +Description : Test if the keyboard is ready with the next character. + Parameters : + Returns : + Comments : + ******************************************************************************/ +bool +kbd_ready(void) +{ + return !clear; +} + + diff --git a/vimlac/kbd.h b/vimlac/kbd.h new file mode 100755 index 0000000..fa87a3a --- /dev/null +++ b/vimlac/kbd.h @@ -0,0 +1,24 @@ +/******************************************************************************\ + * kbd.h * + * ------- * + * * + * Implements all display CPU instructions. * + * * +\******************************************************************************/ + +#ifndef KBD_H +#define KBD_H + +#include "imlac.h" + +/****** + * Exported functions. + ******/ + + +void kbd_clear_flag(void); +WORD kbd_get_char(void); +bool kbd_ready(void); + + +#endif diff --git a/vimlac/ptp.c b/vimlac/ptp.c new file mode 100644 index 0000000..503ce76 --- /dev/null +++ b/vimlac/ptp.c @@ -0,0 +1,159 @@ +/* + * Implementation for the imlac PTP (papertape punch) device. + */ + +#include "imlac.h" +#include "ptp.h" + + +/***** + * constants for the PTP device + * + * The device punches at 100 chars/second, so we work out how many imlac + * machine cycles data is ready/notready at a 30%/70% ready cycle. + ******/ + +#define CHARS_PER_SECOND 100 +#define CYCLES_PER_CHAR (CPU_HERZ / CHARS_PER_SECOND) +#define READY_CYCLES (int)((3 * CYCLES_PER_CHAR) / 10) +#define NOT_READY_CYCLES (int)((7 * CYCLES_PER_CHAR) / 10) + +/***** + * State variables for the PTP device + ******/ + +static bool motor_on = false; +static bool device_ready = false; +static FILE *open_file; +static char *filename = NULL; +static long cycle_count = 0; +static char value = 0; + + + +/****************************************************************************** +Description : Mount a papertape file on the PTP device + Parameters : fname - pathname of the file to mount + Returns : 0 if no error, else status code. + Comments : + ******************************************************************************/ +int ptp_mount(char *fname) +{ + filename = fname; + open_file = fopen(fname, "wb"); + if (open_file == NULL) + { + ptp_dismount(); + return errno; + } + motor_on = false; + device_ready = false; + cycle_count = NOT_READY_CYCLES; + + return 0; +} + + +/****************************************************************************** +Description : Dismount papertape file from device. + Parameters : + Returns : + Comments : Turns motor off. + ******************************************************************************/ +void ptp_dismount(void) +{ + if (open_file) + if (fclose(open_file) != 0) + filename = NULL; + open_file = NULL; + motor_on = false; + device_ready = false; +} + + +/****************************************************************************** +Description : Start the papertape device motor. + Parameters : + Returns : + Comments : We don't check if papertape mounted as the real imlac doesn't. + ******************************************************************************/ +void ptp_start(void) +{ + motor_on = true; + device_ready = false; + cycle_count = NOT_READY_CYCLES; +} + + +/****************************************************************************** +Description : Turn the papertape device motor off. + Parameters : + Returns : + Comments : + ******************************************************************************/ +void ptp_stop(void) +{ + motor_on = false; + device_ready = false; + cycle_count = NOT_READY_CYCLES; +} + + +/****************************************************************************** +Description : Write the current value to the papertape punch file. + Parameters : + Returns : + Comments : + ******************************************************************************/ +int ptp_punch(BYTE value) +{ + return value; +} + + +/****************************************************************************** +Description : Get the papertape device status. + Parameters : + Returns : TRUE if device ready, else FALSE. + Comments : + ******************************************************************************/ +bool ptp_ready(void) +{ + return device_ready; +} + + +/****************************************************************************** +Description : Tick the state machine along a bit. + Parameters : cycles - number of imlac cycles that have elapsed + Returns : + Comments : + ******************************************************************************/ +void ptp_tick(long cycles) +{ + /* if no state change */ + if (!motor_on || open_file == NULL) + return; + + /* tape in, motor on */ + cycle_count -= cycles; + if (cycle_count <= 0L) + { + if (device_ready) + { + device_ready = false; + cycle_count += NOT_READY_CYCLES; + value = 0; + } + else + { + device_ready = true; + cycle_count += READY_CYCLES; + if (fread(&value, sizeof(BYTE), 1, open_file) != 1) + { /* assume EOF on file, dismount tape */ + fclose(open_file); + open_file = NULL; + } + } + } +} diff --git a/vimlac/ptp.h b/vimlac/ptp.h new file mode 100644 index 0000000..3c3c944 --- /dev/null +++ b/vimlac/ptp.h @@ -0,0 +1,16 @@ +/* + * Interface for the imlac PTP (papertape punch). + */ + +#ifndef PTP_H +#define PTP_H + +int ptp_mount(char *fname); +void ptp_dismount(void); +void ptp_start(void); +void ptp_stop(void); +int ptp_punch(BYTE value); +bool ptp_ready(void); +void ptp_tick(long cycles); + +#endif diff --git a/vimlac/ptr.c b/vimlac/ptr.c index 41fb647..a7ce533 100644 --- a/vimlac/ptr.c +++ b/vimlac/ptr.c @@ -1,15 +1,15 @@ /* - * Implementation for the vimlac PTR (papertape reader). + * Implementation for the imlac PTR (papertape reader) device. */ -#include "vimlac.h" +#include "imlac.h" #include "ptr.h" /***** * constants for the PTR device * - * The device reads at 300 chars/second, so we work out how many + * The device reads at 300 chars/second, so we work out how many imlac * machine cycles data is ready/notready at a 30%/70% ready cycle. ******/ @@ -33,6 +33,13 @@ static BYTE value = PTR_EOF; static long cycle_count = 0; + +/****************************************************************************** +Description : Mount a papertape file on the PTR device + Parameters : fname - pathname of the file to mount + Returns : 0 if no error, else status code. + Comments : + ******************************************************************************/ int ptr_mount(char *fname) { filename = fname; @@ -52,6 +59,12 @@ int ptr_mount(char *fname) } +/****************************************************************************** +Description : Dismount papertape file from device. + Parameters : + Returns : + Comments : Turns motor off. + ******************************************************************************/ void ptr_dismount(void) { if (open_file) @@ -65,6 +78,12 @@ void ptr_dismount(void) } +/****************************************************************************** +Description : Start the papertape device motor. + Parameters : + Returns : + Comments : We don't check if papertape mounted as the real imlac doesn't. + ******************************************************************************/ void ptr_start(void) { motor_on = true; @@ -73,6 +92,12 @@ void ptr_start(void) } +/****************************************************************************** +Description : Turn the papertape device motor off. + Parameters : + Returns : + Comments : + ******************************************************************************/ void ptr_stop(void) { motor_on = false; @@ -80,18 +105,36 @@ void ptr_stop(void) } +/****************************************************************************** +Description : Read the current value of the papertape device. + Parameters : + Returns : + Comments : + ******************************************************************************/ int ptr_read(void) { return value; } +/****************************************************************************** +Description : Get the papertape device status. + Parameters : + Returns : TRUE if device ready, else FALSE. + Comments : + ******************************************************************************/ bool ptr_ready(void) { return device_ready; } +/****************************************************************************** +Description : Tick the state machine along a bit. + Parameters : cycles - number of imlac cycles that have elapsed + Returns : + Comments : + ******************************************************************************/ void ptr_tick(long cycles) { /* if no state change */ diff --git a/vimlac/ptr.h b/vimlac/ptr.h index d555b8b..d3612a9 100644 --- a/vimlac/ptr.h +++ b/vimlac/ptr.h @@ -1,5 +1,5 @@ /* - * Interface for the vimlac PTR (papertape reader). + * Interface for the imlac PTR (papertape reader). */ #ifndef PTR_H diff --git a/vimlac/test_cpu.c b/vimlac/test_cpu.c new file mode 100644 index 0000000..383acf9 --- /dev/null +++ b/vimlac/test_cpu.c @@ -0,0 +1,23 @@ +/* + * Test the CPU implementation. + */ + +#include +#include + +#include "imlac.h" +#include "cpu.h" +#include "memory.h" + +#define trace(args) ; + + +int +main(int argc, char *argv[]) +{ + int errors = 0; + + printf("%d errors found\n", errors); + + return 0; +} diff --git a/vimlac/trace.c b/vimlac/trace.c new file mode 100644 index 0000000..c5dd175 --- /dev/null +++ b/vimlac/trace.c @@ -0,0 +1,27 @@ +/* + * Trace routines for the imlac simulator. + */ + +#include +#include + + +/****************************************************************************** +Description : printf()-style trace routine. + Parameters : like printf() + Returns : + Comments : + ******************************************************************************/ +void +trace(char *fmt, ...) +{ + va_list ap; + char buff[1024]; + + va_start(ap, fmt); + vsprintf(buff, fmt, ap); + fprintf(stdout, "%s\n", buff); + va_end(ap); +} + + diff --git a/vimlac/trace.h b/vimlac/trace.h new file mode 100644 index 0000000..646623d --- /dev/null +++ b/vimlac/trace.h @@ -0,0 +1,10 @@ +/* + * Interface for the imlac TRACE routine(s). + */ + +#ifndef TRACE_H +#define TRACE_H + +void trace(char *fmt, ...); + +#endif diff --git a/vimlac/ttyin.c b/vimlac/ttyin.c new file mode 100644 index 0000000..0b8ebc2 --- /dev/null +++ b/vimlac/ttyin.c @@ -0,0 +1,149 @@ +/* + * Implementation for the imlac TTYIN (TTY input) device. + */ + +#include "imlac.h" +#include "ttyin.h" + + +/***** + * constants for the TTYIN device + * + * The device reads at 4800 chars/second, so we work out how many imlac + * machine cycles data is ready/notready at a 30%/70% ready cycle. + ******/ + +#define CHARS_PER_SECOND 4800 +#define CYCLES_PER_CHAR (CPU_HERZ / CHARS_PER_SECOND) +#define READY_CYCLES (int)((3 * CYCLES_PER_CHAR) / 10) +#define NOT_READY_CYCLES (int)((7 * CYCLES_PER_CHAR) / 10) + +#define TTYIN_EOF 0377 + +/***** + * State variables for the TTYIN device + ******/ + +static bool device_ready = false; +static FILE *open_file; +static char *filename = NULL; +static bool at_eof = false; +static BYTE value = TTYIN_EOF; +static long cycle_count = 0; + + + +/****************************************************************************** +Description : Mount a papertape file on the TTYIN device + Parameters : fname - pathname of the file to mount + Returns : 0 if no error, else status code. + Comments : + ******************************************************************************/ +int ttyin_mount(char *fname) +{ + filename = fname; + open_file = fopen(fname, "rb"); + if (open_file == NULL) + { + ttyin_dismount(); + return errno; + } + device_ready = false; + at_eof = false; + value = TTYIN_EOF; + cycle_count = NOT_READY_CYCLES; + + return 0; +} + + +/****************************************************************************** +Description : Dismount papertape file from device. + Parameters : + Returns : + Comments : Turns motor off. + ******************************************************************************/ +void ttyin_dismount(void) +{ + if (open_file) + if (fclose(open_file) != 0) + filename = NULL; + open_file = NULL; + device_ready = true; + at_eof = true; + value = TTYIN_EOF; +} + + +/****************************************************************************** +Description : Read the current value of the papertape device. + Parameters : + Returns : + Comments : + ******************************************************************************/ +int ttyin_get_char(void) +{ + return value; +} + + +/****************************************************************************** +Description : Get the papertape device status. + Parameters : + Returns : TRUE if device ready, else FALSE. + Comments : + ******************************************************************************/ +void ttyin_clear_flag(void) +{ + device_ready = false; +} + + +/****************************************************************************** +Description : Get the papertape device status. + Parameters : + Returns : TRUE if device ready, else FALSE. + Comments : + ******************************************************************************/ +bool ttyin_ready(void) +{ + return device_ready; +} + + +/****************************************************************************** +Description : Tick the state machine along a bit. + Parameters : cycles - number of imlac cycles that have elapsed + Returns : + Comments : + ******************************************************************************/ +void ttyin_tick(long cycles) +{ + /* if no state change */ + if (at_eof || open_file == NULL) + return; + + /* tape in, motor on */ + cycle_count -= cycles; + if (cycle_count <= 0L) + { + if (device_ready) + { + device_ready = false; + cycle_count += NOT_READY_CYCLES; + value = 0; + } + else + { + device_ready = true; + cycle_count += READY_CYCLES; + if (fread(&value, sizeof(BYTE), 1, open_file) != 1) + { /* assume EOF on file, dismount tape */ + fclose(open_file); + open_file = NULL; + at_eof = true; + value = TTYIN_EOF; + } + } + } +} diff --git a/vimlac/ttyin.h b/vimlac/ttyin.h new file mode 100644 index 0000000..c4597a9 --- /dev/null +++ b/vimlac/ttyin.h @@ -0,0 +1,15 @@ +/* + * Interface for the imlac TTYIN (TTY input). + */ + +#ifndef TTYIN_H +#define TTYIN_H + +int ttyin_mount(char *fname); +void ttyin_dismount(void); +int ttyin_get_char(void); +void ttyin_tick(long cycles); +bool ttyin_ready(void); +void ttyin_clear_flag(void); + +#endif diff --git a/vimlac/ttyout.c b/vimlac/ttyout.c new file mode 100644 index 0000000..a0f6dd7 --- /dev/null +++ b/vimlac/ttyout.c @@ -0,0 +1,136 @@ +/* + * Implementation for the imlac TTYOUT (TTY output) device. + */ + +#include "imlac.h" +#include "ttyout.h" + + +/***** + * constants for the TTYOUT device + * + * The device reads at 4800 chars/second, so we work out how many imlac + * machine cycles data is ready/notready at a 30%/70% ready cycle. + ******/ + +#define CHARS_PER_SECOND 4800 +#define CYCLES_PER_CHAR (CPU_HERZ / CHARS_PER_SECOND) +#define READY_CYCLES (int)((3 * CYCLES_PER_CHAR) / 10) +#define NOT_READY_CYCLES (int)((7 * CYCLES_PER_CHAR) / 10) + +#define TTYOUT_EOF 0377 + +/***** + * State variables for the TTYOUT device + ******/ + +static bool device_ready = false; +static FILE *open_file; +static char *filename = NULL; +static long cycle_count = 0; + + + +/****************************************************************************** +Description : Mount a papertape file on the TTYOUT device + Parameters : fname - pathname of the file to mount + Returns : 0 if no error, else status code. + Comments : + ******************************************************************************/ +int ttyout_mount(char *fname) +{ + filename = fname; + open_file = fopen(fname, "wb"); + if (open_file == NULL) + { + ttyout_dismount(); + return errno; + } + device_ready = false; + cycle_count = NOT_READY_CYCLES; + + return 0; +} + + +/****************************************************************************** +Description : Dismount papertape file from device. + Parameters : + Returns : + Comments : Turns motor off. + ******************************************************************************/ +void ttyout_dismount(void) +{ + if (open_file) + if (fclose(open_file) != 0) + filename = NULL; + open_file = NULL; + device_ready = true; +} + + +/****************************************************************************** +Description : Write a byte value to the device. + Parameters : + Returns : + Comments : + ******************************************************************************/ +void ttyout_send(BYTE value) +{ + if (device_ready) + fwrite(&value, 1, 1, open_file); +} + + +/****************************************************************************** +Description : Get the papertape device status. + Parameters : + Returns : TRUE if device ready, else FALSE. + Comments : + ******************************************************************************/ +void ttyout_clear_flag(void) +{ + device_ready = false; +} + + +/****************************************************************************** +Description : Get the papertape device status. + Parameters : + Returns : TRUE if device ready, else FALSE. + Comments : + ******************************************************************************/ +bool ttyout_ready(void) +{ + return device_ready; +} + + +/****************************************************************************** +Description : Tick the state machine along a bit. + Parameters : cycles - number of imlac cycles that have elapsed + Returns : + Comments : + ******************************************************************************/ +void ttyout_tick(long cycles) +{ + /* if not open, no state change */ + if (open_file == NULL) + return; + + /* file mounted */ + cycle_count -= cycles; + if (cycle_count <= 0L) + { + if (device_ready) + { + device_ready = false; + cycle_count += NOT_READY_CYCLES; + } + else + { + device_ready = true; + cycle_count += READY_CYCLES; + } + } +} diff --git a/vimlac/ttyout.h b/vimlac/ttyout.h new file mode 100644 index 0000000..576dd64 --- /dev/null +++ b/vimlac/ttyout.h @@ -0,0 +1,17 @@ +/* + * Interface for the imlac TTYOUT (TTY input). + */ + +#ifndef TTYOUT_H +#define TTYOUT_H + + +int ttyout_mount(char *fname); +void ttyout_dismount(void); +void ttyout_send(BYTE value); +void ttyout_clear_flag(void); +bool ttyout_ready(void); +void ttyout_tick(long cycles); + + +#endif