mirror of
https://github.com/rzzzwilson/pymlac.git
synced 2025-06-10 09:32:41 +00:00
Combining PTR and PTP device
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
DEVFILES = cpu.o dcpu.o ptr.o ptp.o memory.o kb.o ttyin.o ttyout.o trace.o error.o log.o plist.o
|
||||
DEVFILES = cpu.o dcpu.o ptrptp.o memory.o kb.o ttyin.o ttyout.o trace.o error.o log.o plist.o
|
||||
OFILES = vimlac.o $(DEVFILES)
|
||||
|
||||
#CFLAGS=-fPIC -O2 -Wall -ansi -pedantic -std=c99 -g
|
||||
|
||||
250
vimlac/ptrptp.c
Executable file
250
vimlac/ptrptp.c
Executable file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Implementation for the vimlac PTR/PTP (papertape reader/punch).
|
||||
*/
|
||||
|
||||
#include "vimlac.h"
|
||||
#include "ptrptp.h"
|
||||
|
||||
|
||||
/*****
|
||||
* constants for the PTR device
|
||||
*
|
||||
* The device reads at 300 chars/second, so we work out how many
|
||||
* machine cycles data is ready/notready at a 30%/70% ready cycle.
|
||||
******/
|
||||
|
||||
#define PTR_CHARS_PER_SECOND 300
|
||||
#define PTR_CYCLES_PER_CHAR (CPU_HERZ / PTR_CHARS_PER_SECOND)
|
||||
#define PTR_READY_CYCLES (int)((3 * PTR_CYCLES_PER_CHAR) / 10)
|
||||
#define PTR_NOT_PTR_READY_CYCLES (int)((7 * PTR_CYCLES_PER_CHAR) / 10)
|
||||
|
||||
#define PTR_EOF 0377
|
||||
|
||||
/*****
|
||||
* constants for the PTP device
|
||||
*
|
||||
* The device punches at 30 chars/second, so we work out how many
|
||||
* machine cycles device is not ready after punch starts.
|
||||
******/
|
||||
|
||||
#define PTP_CHARS_PER_SECOND 30
|
||||
#define PTP_NOT_READY_CYCLES (int) (CPU_HERZ / PTP_CHARS_PER_SECOND)
|
||||
|
||||
// define some use values
|
||||
#define InUsePTR "PTR"
|
||||
#define InUsePTP "PTP"
|
||||
|
||||
#define STREQ(a, b) (strcmp((a), (b)) == 0)
|
||||
|
||||
|
||||
/*****
|
||||
* State variables for the general device
|
||||
******/
|
||||
|
||||
static char *device_use = NULL; // NULL, InUsePTR or InUsePTP
|
||||
static bool device_motor_on = false;
|
||||
static FILE *device_open_file = NULL;
|
||||
static char *device_filename = NULL;
|
||||
static long device_cycle_count = 0;
|
||||
static bool device_ready = false;
|
||||
|
||||
/*****
|
||||
* Specific state variables for the PTR device
|
||||
******/
|
||||
|
||||
static bool ptr_at_eof = true;
|
||||
static BYTE ptr_value = PTR_EOF;
|
||||
|
||||
|
||||
int ptr_mount(char *fname)
|
||||
{
|
||||
if (device_use && STREQ(device_use, InUsePTP))
|
||||
verror("ptr_mount: Can't mount PTR file, being used as PTP");
|
||||
;
|
||||
device_filename = fname;
|
||||
device_open_file = fopen(fname, "rb");
|
||||
if (device_open_file == NULL)
|
||||
{
|
||||
ptr_dismount();
|
||||
return errno;
|
||||
}
|
||||
device_motor_on = false;
|
||||
device_ready = false;
|
||||
ptr_at_eof = false;
|
||||
ptr_value = PTR_EOF;
|
||||
device_cycle_count = PTR_NOT_PTR_READY_CYCLES;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ptr_dismount(void)
|
||||
{
|
||||
if (device_use && STREQ(device_use, InUsePTP))
|
||||
verror("ptr_mount: Can't dismount PTR file, being used as PTP");
|
||||
|
||||
if (device_open_file)
|
||||
fclose(device_open_file);
|
||||
device_filename = NULL;
|
||||
device_open_file = NULL;
|
||||
device_motor_on = false;
|
||||
device_ready = true;
|
||||
ptr_at_eof = true;
|
||||
ptr_value = PTR_EOF;
|
||||
}
|
||||
|
||||
|
||||
void ptr_start(void)
|
||||
{
|
||||
if (device_use && STREQ(device_use, InUsePTP))
|
||||
verror("ptrptp_start: Can't start PTR motor, being used as PTP");
|
||||
|
||||
device_motor_on = true;
|
||||
device_ready = false;
|
||||
device_cycle_count = PTR_NOT_PTR_READY_CYCLES;
|
||||
}
|
||||
|
||||
|
||||
void ptr_stop(void)
|
||||
{
|
||||
if (device_use && STREQ(device_use, InUsePTP))
|
||||
verror("ptr_stop: Can't stop PTR motor, being used as PTP");
|
||||
|
||||
device_motor_on = false;
|
||||
device_cycle_count = PTR_NOT_PTR_READY_CYCLES;
|
||||
}
|
||||
|
||||
|
||||
int ptr_read(void)
|
||||
{
|
||||
if (device_use && STREQ(device_use, InUsePTP))
|
||||
verror("ptr_read: Can't read PTR, device being used as PTP");
|
||||
|
||||
return ptr_value;
|
||||
}
|
||||
|
||||
|
||||
bool ptr_ready(void)
|
||||
{
|
||||
return device_ready;
|
||||
}
|
||||
|
||||
|
||||
void ptr_tick(long cycles)
|
||||
{
|
||||
// if not being used as PTR, do nothing
|
||||
if (device_use && !STREQ(device_use, InUsePTR))
|
||||
return;
|
||||
|
||||
/* if no state change */
|
||||
if (!device_motor_on || ptr_at_eof || device_open_file == NULL)
|
||||
return;
|
||||
|
||||
/* tape in, motor on */
|
||||
device_cycle_count -= cycles;
|
||||
if (device_cycle_count <= 0L)
|
||||
{
|
||||
if (device_ready)
|
||||
{
|
||||
device_ready = false;
|
||||
device_cycle_count += PTR_NOT_PTR_READY_CYCLES;
|
||||
ptr_value = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
device_ready = true;
|
||||
device_cycle_count += PTR_READY_CYCLES;
|
||||
if (fread(&ptr_value, sizeof(BYTE), 1, device_open_file) != 1)
|
||||
{ /* assume EOF on file, dismount tape */
|
||||
fclose(device_open_file);
|
||||
device_open_file = NULL;
|
||||
ptr_at_eof = true;
|
||||
ptr_value = PTR_EOF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MID
|
||||
|
||||
int ptp_mount(char *fname)
|
||||
{
|
||||
if (device_use && STREQ(device_use, InUsePTR))
|
||||
verror("ptp_mount: Can't mount PTP, device being used as PTR");
|
||||
|
||||
device_use = InUsePTP;
|
||||
device_filename = fname;
|
||||
device_open_file = fopen(fname, "wb");
|
||||
if (device_open_file == NULL)
|
||||
{
|
||||
ptp_dismount();
|
||||
return errno;
|
||||
}
|
||||
device_motor_on = false;
|
||||
device_ready = false;
|
||||
device_cycle_count = PTP_NOT_READY_CYCLES;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ptp_dismount(void)
|
||||
{
|
||||
if (device_use && STREQ(device_use, InUsePTR))
|
||||
verror("ptp_dismount: Can't dismount PTP, device being used as PTR");
|
||||
|
||||
if (device_open_file)
|
||||
if (fclose(device_open_file) != 0)
|
||||
device_filename = NULL;
|
||||
device_open_file = NULL;
|
||||
device_motor_on = false;
|
||||
device_ready = true;
|
||||
}
|
||||
|
||||
|
||||
void ptp_start(void)
|
||||
{
|
||||
device_motor_on = true;
|
||||
device_ready = false;
|
||||
device_cycle_count = PTP_NOT_READY_CYCLES;
|
||||
}
|
||||
|
||||
|
||||
void ptp_stop(void)
|
||||
{
|
||||
device_motor_on = false;
|
||||
device_cycle_count = PTP_NOT_READY_CYCLES;
|
||||
}
|
||||
|
||||
|
||||
void ptp_punch(BYTE value)
|
||||
{
|
||||
if (device_motor_on && device_open_file != NULL)
|
||||
{
|
||||
putc(value, device_open_file);
|
||||
device_cycle_count = PTP_NOT_READY_CYCLES;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ptp_ready(void)
|
||||
{
|
||||
return device_ready;
|
||||
}
|
||||
|
||||
|
||||
void ptp_tick(long cycles)
|
||||
{
|
||||
/* if no state change */
|
||||
if (!device_motor_on || device_open_file == NULL)
|
||||
return;
|
||||
|
||||
/* tape in, motor on */
|
||||
device_cycle_count -= cycles;
|
||||
if (device_cycle_count <= 0L)
|
||||
{
|
||||
if (!device_ready)
|
||||
device_ready = true;
|
||||
device_cycle_count = 0;
|
||||
}
|
||||
}
|
||||
24
vimlac/ptrptp.h
Executable file
24
vimlac/ptrptp.h
Executable file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Interface for the vimlac PTR/PTP (papertape reader/punch).
|
||||
*/
|
||||
|
||||
#ifndef PTRPTP_H
|
||||
#define PTRPTP_H
|
||||
|
||||
int ptr_mount(char *fname);
|
||||
void ptr_dismount(void);
|
||||
void ptr_start(void);
|
||||
void ptr_stop(void);
|
||||
int ptr_read(void);
|
||||
void ptr_tick(long cycles);
|
||||
bool ptr_ready(void);
|
||||
|
||||
int ptp_mount(char *fname);
|
||||
void ptp_dismount(void);
|
||||
void ptp_start(void);
|
||||
void ptp_stop(void);
|
||||
void ptp_punch(BYTE byte);
|
||||
void ptp_tick(long cycles);
|
||||
bool ptp_ready(void);
|
||||
|
||||
#endif
|
||||
@@ -60,6 +60,7 @@
|
||||
#include "cpu.h"
|
||||
#include "dcpu.h"
|
||||
#include "memory.h"
|
||||
#include "ptrptp.h"
|
||||
#include "error.h"
|
||||
#include "log.h"
|
||||
#include "plist.h"
|
||||
@@ -469,22 +470,60 @@ allmem(char *value, char *var2)
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Description : Run one instruction on the CPU.
|
||||
Parameters : addr - address of memory cell (string, may be NULL)
|
||||
Description : Run one or more instructions on the CPU.
|
||||
Parameters : num - address of memory cell (string, may be NULL)
|
||||
: fld2 - unused
|
||||
Returns : The number of errors encountered (0 or 1).
|
||||
Comments :
|
||||
******************************************************************************/
|
||||
int
|
||||
run_one(char *addr, char *fld2)
|
||||
run_one(char *num, char *fld2)
|
||||
{
|
||||
int run_num = 0;
|
||||
|
||||
// if given address run from that address, else use PC contents
|
||||
if (addr)
|
||||
cpu_set_PC(str2word(addr));
|
||||
if (!num)
|
||||
run_num = 1;
|
||||
else
|
||||
run_num = str2word(num);
|
||||
|
||||
cpu_start();
|
||||
UsedCycles = cpu_execute_one();
|
||||
while (run_num--)
|
||||
{
|
||||
int cycles = cpu_execute_one();
|
||||
|
||||
ptr_tick(cycles);
|
||||
ptp_tick(cycles);
|
||||
|
||||
UsedCycles += cycles;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Description : Run the CPU until PC is the same as 'addr'.
|
||||
Parameters : addr - PC contents to stop at
|
||||
: fld2 - unused
|
||||
Returns : The number of errors encountered (0 or 1).
|
||||
Comments :
|
||||
******************************************************************************/
|
||||
int
|
||||
rununtil(char *addr, char *fld2)
|
||||
{
|
||||
WORD stop_pc = str2word(addr);
|
||||
|
||||
cpu_start();
|
||||
do
|
||||
{
|
||||
int cycles = cpu_execute_one();
|
||||
|
||||
ptr_tick(cycles);
|
||||
ptp_tick(cycles);
|
||||
|
||||
UsedCycles += cycles;
|
||||
} while (cpu_get_PC() != stop_pc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -547,6 +586,38 @@ checkreg(char *reg, char *expected)
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Description : Check that the main CPU is in the correct state.
|
||||
Parameters : state - string holding expected display state ('on' or 'off)
|
||||
: unused - unused
|
||||
Returns : The number of errors encountered (0 or 1).
|
||||
Comments :
|
||||
******************************************************************************/
|
||||
int
|
||||
checkcpu(char *state, char *unused)
|
||||
{
|
||||
if ((STREQ(state, "on")) && !cpu_get_state())
|
||||
{
|
||||
vlog("Main CPU run state is %s, should be 'ON'",
|
||||
(DisplayOn ? "ON": "OFF"));
|
||||
return 1;
|
||||
}
|
||||
else if ((STREQ(state, "off")) && cpu_get_state())
|
||||
{
|
||||
vlog("Main CPU run state is %s, should be 'OFF'",
|
||||
(DisplayOn ? "ON": "OFF"));
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
vlog("checkcpu: state should be 'on' or 'OFF', got %s", state);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Description : Check that the display is in the correct state.
|
||||
Parameters : state - string holding expected display state ('on' or 'off)
|
||||
@@ -555,7 +626,7 @@ Description : Check that the display is in the correct state.
|
||||
Comments :
|
||||
******************************************************************************/
|
||||
int
|
||||
checkd(char *state, char *unused)
|
||||
checkdcpu(char *state, char *unused)
|
||||
{
|
||||
if ((STREQ(state, "on")) && !DisplayOn)
|
||||
{
|
||||
@@ -565,7 +636,7 @@ checkd(char *state, char *unused)
|
||||
}
|
||||
else if ((STREQ(state, "off")) && DisplayOn)
|
||||
{
|
||||
vlog("DCPU run state is %s, should be 'OFF'",
|
||||
vlog("Display CPU run state is %s, should be 'OFF'",
|
||||
(DisplayOn ? "ON": "OFF"));
|
||||
return 1;
|
||||
}
|
||||
@@ -1210,6 +1281,8 @@ run_one_test(Test *test)
|
||||
error += setmem(fld1, fld2);
|
||||
else if (STREQ(opcode, "RUN"))
|
||||
error += run_one(fld1, fld2);
|
||||
else if (STREQ(opcode, "RUNUNTIL"))
|
||||
error += rununtil(fld1, fld2);
|
||||
else if (STREQ(opcode, "CHECKCYCLES"))
|
||||
error += checkcycles(fld1, fld2);
|
||||
else if (STREQ(opcode, "CHECKREG"))
|
||||
@@ -1224,8 +1297,10 @@ run_one_test(Test *test)
|
||||
error += checkrun(fld1, fld2);
|
||||
else if (STREQ(opcode, "SETD"))
|
||||
error += setd(fld1, fld2);
|
||||
else if (STREQ(opcode, "CHECKD"))
|
||||
error += checkd(fld1, fld2);
|
||||
else if (STREQ(opcode, "CHECKDCPU"))
|
||||
error += checkdcpu(fld1, fld2);
|
||||
else if (STREQ(opcode, "CHECKCPU"))
|
||||
error += checkcpu(fld1, fld2);
|
||||
else
|
||||
{
|
||||
printf("Unrecognized operation '%s' at line %d\n",
|
||||
|
||||
Reference in New Issue
Block a user