1
0
mirror of https://github.com/rzzzwilson/pymlac.git synced 2025-06-10 09:32:41 +00:00

Readying test_cpu

This commit is contained in:
Ross Wilson
2015-10-15 19:45:29 +07:00
parent 3bad73e242
commit b211efcb06
20 changed files with 957 additions and 19 deletions

View File

@@ -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

View File

@@ -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");

View File

@@ -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.

181
vimlac/dcpu.c Executable file
View File

@@ -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 */
}

28
vimlac/dcpu.h Executable file
View File

@@ -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

30
vimlac/error.c Normal file
View File

@@ -0,0 +1,30 @@
/*
* Error routines for the imlac simulator.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
/******************************************************************************
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);
}

10
vimlac/error.h Normal file
View File

@@ -0,0 +1,10 @@
/*
* Error routines for the imlac simulation.
*/
#ifndef ERROR_H
#define ERROR_H
void error(char *fmt, ...);
#endif

58
vimlac/kbd.c Executable file
View File

@@ -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;
}

24
vimlac/kbd.h Executable file
View File

@@ -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

159
vimlac/ptp.c Normal file
View File

@@ -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;
}
}
}
}

16
vimlac/ptp.h Normal file
View File

@@ -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

View File

@@ -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 */

View File

@@ -1,5 +1,5 @@
/*
* Interface for the vimlac PTR (papertape reader).
* Interface for the imlac PTR (papertape reader).
*/
#ifndef PTR_H

23
vimlac/test_cpu.c Normal file
View File

@@ -0,0 +1,23 @@
/*
* Test the CPU implementation.
*/
#include <stdio.h>
#include <assert.h>
#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;
}

27
vimlac/trace.c Normal file
View File

@@ -0,0 +1,27 @@
/*
* Trace routines for the imlac simulator.
*/
#include <stdarg.h>
#include <stdio.h>
/******************************************************************************
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);
}

10
vimlac/trace.h Normal file
View File

@@ -0,0 +1,10 @@
/*
* Interface for the imlac TRACE routine(s).
*/
#ifndef TRACE_H
#define TRACE_H
void trace(char *fmt, ...);
#endif

149
vimlac/ttyin.c Normal file
View File

@@ -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;
}
}
}
}

15
vimlac/ttyin.h Normal file
View File

@@ -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

136
vimlac/ttyout.c Normal file
View File

@@ -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;
}
}
}

17
vimlac/ttyout.h Normal file
View File

@@ -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