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

Reverted to better old copy

This commit is contained in:
Ross Wilson
2015-10-16 10:25:47 +07:00
parent b211efcb06
commit c39b4644ca
25 changed files with 266 additions and 732 deletions

2
vimlac/.gitignore vendored
View File

@@ -1,2 +0,0 @@
test_memory
test_cpu

13
vimlac/Makefile Normal file → Executable file
View File

@@ -1,20 +1,15 @@
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
OFILES = vimlac.o cpu.o dcpu.o ptr.o ptp.o memory.o kb.o ttyin.o ttyout.o trace.o
CFLAGS=-shared -fPIC -O2 -Wall -ansi -pedantic -std=c99 -g
#test: vimlac.py vimlac
# #python vimlac.py -ptr test_add.ptp -r 040 -r 0100
# vimlac
test: vimlac.py vimlac
#python vimlac.py -ptr test_add.ptp -r 040 -r 0100
./vimlac
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 "imlac.h"
#include "vimlac.h"
#include "cpu.h"
#include "dcpu.h"
#include "memory.h"
#include "kbd.h"
#include "kb.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_running())
if (dcpu_on())
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_running())
if (!dcpu_on())
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)
{
kbd_clear_flag();
kb_clear_flag();
trace("KCF\t");
@@ -602,7 +602,7 @@ Description : Emulate the IMLAC KRB instruction.
static int
i_KRB(void)
{
r_AC |= kbd_get_char();
r_AC |= kb_get_char();
trace("KRB\t");
@@ -619,8 +619,8 @@ Description : Emulate the IMLAC KRC instruction.
static int
i_KRC(void)
{
r_AC |= kbd_get_char();
kbd_clear_flag();
r_AC |= kb_get_char();
kb_clear_flag();
trace("KRC\t");
@@ -637,7 +637,7 @@ Description : Emulate the IMLAC KSF instruction.
static int
i_KSF(void)
{
if (kbd_ready())
if (kb_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 (!kbd_ready())
if (!kb_ready())
r_PC = (r_PC + 1) & WORD_MASK;
trace("KSN\t");
@@ -673,9 +673,7 @@ Description : Emulate the IMLAC PUN instruction.
static int
i_PUN(void)
{
char value = r_AC & 0xff;
ptp_punch(value);
ptp_punch(r_AC & 0xff);
trace("PUN\t");
@@ -939,9 +937,7 @@ Description : Emulate the IMLAC TPC instruction.
static int
i_TPC(void)
{
BYTE value = r_AC & 0xff;
ttyout_send(value);
ttyout_send(r_AC & 0xff);
ttyout_clear_flag();
trace("TPC\t");
@@ -1120,7 +1116,7 @@ Description : Emulate the IMLAC DLA instruction.
static int
i_DLA(void)
{
dcpu_set_DPC(r_AC);
dcpu_set_PC(r_AC);
trace("DLA\t");
@@ -1489,7 +1485,7 @@ page00(WORD instruction)
/******************************************************************************
Description : Function to execute one main processor instruction.
Parameters :
Returns : The number of cycles the instruction took.
Returns :
Comments : Perform initial decode of 5 bit opcode and either call
: appropriate emulating function or call further decode function.
******************************************************************************/

View File

@@ -1,15 +1,12 @@
/******************************************************************************\
* cpu.h *
* ------- *
* *
* Implements all main CPU instructions. *
* *
\******************************************************************************/
#ifndef CPU_H
#define CPU_H
#include "imlac.h"
#include "vimlac.h"
/******
* Exported functions.

View File

@@ -1,105 +1,56 @@
/******************************************************************************\
* dcpu.c *
* -------- *
* dcpu.c *
* ------- *
* *
* This file is used to decode and execute a display processor instruction. *
* *
\******************************************************************************/
#include "imlac.h"
#include "vimlac.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;
static WORD r_PC;
static WORD Prev_r_PC;
static int r_DRSindex;
/* 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 */
static bool cpu_is_on; /* true if display processor is running */
/******************************************************************************
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.
Description : Functions to get/set various registers.
Parameters :
Returns :
Comments :
******************************************************************************/
WORD
dcpu_get_DPC(void)
dcpu_get_PC(void)
{
return r_DPC;
}
WORD
dcpu_get_prev_DPC(void)
{
return Prev_r_DPC;
return r_PC;
}
void
dcpu_set_DPC(WORD new_dpc)
dcpu_set_PC(WORD value)
{
r_DPC = new_dpc;
r_PC = value;
}
void
dcpu_set_DRSindex(WORD drsindex)
dcpu_set_DRSindex(int value)
{
DRSindex = drsindex;
r_DRSindex = value;
}
@@ -112,55 +63,44 @@ Description : Function to handle unrecognized instruction.
static void
illegal(void)
{
WORD oldDPC = Prev_r_DPC & MEMMASK;
WORD oldPC = Prev_r_PC & MEMMASK;
/* memdump(LogOut, oldPC - 8, 16); */
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;
"unexpected main processor opcode %06.6o at address %06.6o",
mem_get(oldPC, false), oldPC);
}
/******************************************************************************
Description : Function to execute one display processor instruction.
Parameters :
Returns : The number of cycles the instruction took.
Returns :
Comments :
******************************************************************************/
int
dcpu_execute_one(void)
{
WORD instruction;
WORD opcode;
WORD address;
bool indirect;
WORD instruction = 0;
bool indirect = false;
WORD opcode = 0;
WORD address = 0;
/******
* If main processor not running, return immediately.
* If processor not running, return immediately.
******/
if (!dcpu_on)
if (!cpu_is_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;
Prev_r_PC = r_PC;
instruction = mem_get(r_PC++, false);
r_PC = r_PC & MEMMASK;
indirect = (bool) (instruction & 0100000); /* high bit set? */
opcode = (instruction >> 11) & 017; /* high 5 bits */
@@ -170,12 +110,70 @@ dcpu_execute_one(void)
* Now decode it.
******/
#ifdef JUNK
switch (opcode)
{
default: illegal();
}
#endif
++instruction;
indirect = !indirect;
++opcode;
++address;
illegal();
return 0; /* CAN'T REACH */
return 0;
}
/******************************************************************************
Description : Function to get CPU state.
Parameters :
Returns :
Comments :
******************************************************************************/
bool
dcpu_on(void)
{
return cpu_is_on;
}
/******************************************************************************
Description : Function to start the CPU.
Parameters :
Returns :
Comments :
******************************************************************************/
void
dcpu_start(void)
{
cpu_is_on = true;
}
/******************************************************************************
Description : Function to stop the CPU.
Parameters :
Returns :
Comments :
******************************************************************************/
void
dcpu_stop(void)
{
cpu_is_on = false;
}
/******************************************************************************
Description : Function to stop the CPU.
Parameters :
Returns :
Comments :
******************************************************************************/
void
dcpu_set_drsindex(int index)
{
r_DRSindex = index;
}

View File

@@ -1,28 +1,24 @@
/******************************************************************************\
* dcpu.h *
* -------- *
* *
* Implements all display CPU instructions. *
* *
* dcpu.h *
* -------- *
\******************************************************************************/
#ifndef DCPU_H
#define DCPU_H
#include "imlac.h"
#include "vimlac.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);
WORD dcpu_get_PC(void);
void dcpu_set_PC(WORD value);
void dcpu_set_DRSindex(int index);
bool dcpu_on(void);
#endif

View File

@@ -1,30 +0,0 @@
/*
* 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);
}

View File

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

View File

@@ -1,29 +0,0 @@
/*
* Global definitions for the imlac simulator.
*/
#ifndef IMLAC_H
#define IMLAC_H
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
typedef unsigned int WORD;
typedef unsigned char BYTE;
#define CPU_HERZ 1800000
#define MEMMASK 0xffff
#define HIGHBITMASK 0x8000
#define WORD_MASK 0xffff
#define OVERFLOWMASK 0x10000
#define LOWBITMASK 0x1
void error(char *msg, ...);
#endif

View File

@@ -1,58 +0,0 @@
/******************************************************************************\
* 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;
}

View File

@@ -1,24 +0,0 @@
/******************************************************************************\
* 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

54
vimlac/memory.c Normal file → Executable file
View File

@@ -1,14 +1,13 @@
/*
* Implementation of memory for the imlac simulator.
* Implementation of vimlac memory.
*
* Memory size is a compile-time constant.
* The code here handles indirect memory references as well
* The code here handles indirect memory references as will
* as the 8 auto-index registers at 010-017 in every 2K block.
*/
#include <stdio.h>
#include "imlac.h"
#include "memory.h"
@@ -44,14 +43,6 @@ static WORD memory[MEM_SIZE];
#define AUTO_INDEX(a) (((a & INDEX_MASK) >= LOWER_INDEX) && ((a & INDEX_MASK) <= HIGHER_INDEX))
/******************************************************************************
Description : Get a word value from memory.
Parameters : address - the address to fetch from
: indirect - TRUE if the fetch is to be indirect
Returns : The word from memory.
Comments : If 'indirect' is TRUE 'address' is the address of a pointer to
: the word to fetch.
******************************************************************************/
WORD
mem_get(WORD address, bool indirect)
{
@@ -68,15 +59,6 @@ mem_get(WORD address, bool indirect)
return result;
}
/******************************************************************************
Description : Put a word value into memory.
Parameters : address - the address to store to
: indirect - TRUE if the store is to be indirect
: value - the word value to place into memory
Returns :
Comments : If 'indirect' is TRUE 'address' is the address of a pointer to
: the word to store into.
******************************************************************************/
void
mem_put(WORD address, bool indirect, WORD value)
{
@@ -91,17 +73,11 @@ mem_put(WORD address, bool indirect, WORD value)
memory[a & ADDR_MASK] = value;
}
/******************************************************************************
Description : Clear memory to zero words.
Parameters :
Returns :
Comments : If the ROM addresses are read-only, don't clear them.
******************************************************************************/
void
mem_clear(void)
{
if (rom_readonly)
{ /* save the ROM contents and restore after clear */
{ /* save the ROM contents */
WORD rom[ROM_SIZE];
memcpy(rom, &memory[ROM_START], sizeof(WORD)*ROM_SIZE);
@@ -112,12 +88,6 @@ mem_clear(void)
memset(memory, 0, sizeof(WORD)*MEM_SIZE);
}
/******************************************************************************
Description : Set the ROM addresses to a particular ROM setting.
Parameters : rom - pointer to ROM_SIZE words of OM values
Returns :
Comments : Sets the ROM area as read-only.
******************************************************************************/
void
mem_set_rom(WORD *rom)
{
@@ -125,24 +95,12 @@ mem_set_rom(WORD *rom)
memcpy(&memory[ROM_START], rom, sizeof(WORD)*ROM_SIZE);
}
/******************************************************************************
Description : Sets the ROM area to be protected or not.
Parameters : readonly - if TRUE the ROM area is protected
Returns :
Comments :
******************************************************************************/
void
mem_set_rom_readonly(bool readonly)
{
rom_readonly = readonly;
}
/******************************************************************************
Description : Load memory from a core save file.
Parameters : filename - pathname of file to load
Returns :
Comments :
******************************************************************************/
void
mem_load_core(char *filename)
{
@@ -164,12 +122,6 @@ mem_load_core(char *filename)
fclose(fd);
}
/******************************************************************************
Description : Save memory to a core save file.
Parameters : filename - pathname of file to save to
Returns :
Comments :
******************************************************************************/
void
mem_save_core(char *filename)
{

4
vimlac/memory.h Normal file → Executable file
View File

@@ -1,11 +1,11 @@
/*
* Interface to the imlac memory routines.
* Interface for the vimlac memory.
*/
#ifndef MEMORY_H
#define MEMORY_H
#include "imlac.h"
#include "vimlac.h"
#define MEM_SIZE 0x4000

88
vimlac/ptp.c Normal file → Executable file
View File

@@ -1,25 +1,23 @@
/*
* Implementation for the imlac PTP (papertape punch) device.
* Implementation for the vimlac PTP (papertape punch).
*/
#include "imlac.h"
#include "vimlac.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.
* The device punches at 300 chars/second, so we work out how many
* machine cycles device is not ready after punch starts.
******/
#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)
#define CHARS_PER_SECOND 300
#define NOT_READY_CYCLES (int) (CPU_HERZ / CHARS_PER_SECOND)
/*****
* State variables for the PTP device
* State variables for the PTR device
******/
static bool motor_on = false;
@@ -27,16 +25,8 @@ 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;
@@ -54,12 +44,6 @@ int ptp_mount(char *fname)
}
/******************************************************************************
Description : Dismount papertape file from device.
Parameters :
Returns :
Comments : Turns motor off.
******************************************************************************/
void ptp_dismount(void)
{
if (open_file)
@@ -67,16 +51,10 @@ void ptp_dismount(void)
filename = NULL;
open_file = NULL;
motor_on = false;
device_ready = false;
device_ready = true;
}
/******************************************************************************
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;
@@ -85,50 +63,29 @@ void ptp_start(void)
}
/******************************************************************************
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)
void ptp_punch(BYTE value)
{
return value;
if (motor_on && open_file != NULL)
{
putc(value, open_file);
cycle_count = NOT_READY_CYCLES;
}
}
/******************************************************************************
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 */
@@ -139,21 +96,8 @@ void ptp_tick(long cycles)
cycle_count -= cycles;
if (cycle_count <= 0L)
{
if (device_ready)
{
device_ready = false;
cycle_count += NOT_READY_CYCLES;
value = 0;
}
else
{
if (!device_ready)
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;
}
}
cycle_count = 0;
}
}

6
vimlac/ptp.h Normal file → Executable file
View File

@@ -1,5 +1,5 @@
/*
* Interface for the imlac PTP (papertape punch).
* Interface for the vimlac PTP (papertape punch).
*/
#ifndef PTP_H
@@ -9,8 +9,8 @@ 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_punch(BYTE byte);
void ptp_tick(long cycles);
bool ptp_ready(void);
#endif

49
vimlac/ptr.c Normal file → Executable file
View File

@@ -1,15 +1,15 @@
/*
* Implementation for the imlac PTR (papertape reader) device.
* Implementation for the vimlac PTR (papertape reader).
*/
#include "imlac.h"
#include "vimlac.h"
#include "ptr.h"
/*****
* constants for the PTR device
*
* The device reads at 300 chars/second, so we work out how many imlac
* 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.
******/
@@ -33,13 +33,6 @@ 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;
@@ -59,12 +52,6 @@ int ptr_mount(char *fname)
}
/******************************************************************************
Description : Dismount papertape file from device.
Parameters :
Returns :
Comments : Turns motor off.
******************************************************************************/
void ptr_dismount(void)
{
if (open_file)
@@ -78,12 +65,6 @@ 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;
@@ -92,12 +73,6 @@ void ptr_start(void)
}
/******************************************************************************
Description : Turn the papertape device motor off.
Parameters :
Returns :
Comments :
******************************************************************************/
void ptr_stop(void)
{
motor_on = false;
@@ -105,36 +80,18 @@ 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 */

2
vimlac/ptr.h Normal file → Executable file
View File

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

35
vimlac/test_memory.c Normal file → Executable file
View File

@@ -5,7 +5,7 @@
#include <stdio.h>
#include <assert.h>
#include "imlac.h"
#include "vimlac.h"
#include "memory.h"
@@ -15,7 +15,6 @@ main(int argc, char *argv[])
WORD addr;
WORD result;
FILE *fd;
int errors = 0;
// test the "memory clear" function
mem_clear();
@@ -31,7 +30,7 @@ main(int argc, char *argv[])
{
printf("A: mem_get(0x%04x) was 0x%04x, should be 0x%04x\n",
addr, mem_get(addr, false), addr);
errors += 1;
return 1;
}
}
@@ -45,7 +44,7 @@ main(int argc, char *argv[])
{
printf("B: mem_get(0x%04x) was 0x%04x, should be 0x%04x\n",
addr, mem_get(addr, false), addr);
errors += 1;
return 1;
}
}
@@ -58,26 +57,26 @@ main(int argc, char *argv[])
if (result != 1)
{
printf("C: auto-index at address 010 not indirectly addressing\n");
errors += 1;
return 1;
}
result = mem_get(010, false);
if (result != 1)
{
printf("D: auto-index at address 010 not incrementing\n");
errors += 1;
return 1;
}
mem_put(010, false, 0xffff);
result = mem_get(010, true);
if (result != 0)
{
printf("E: auto-index at address 010 not indirectly addressing\n");
errors += 1;
return 1;
}
result = mem_get(010, false);
if (result != 0)
{
printf("F: auto-index at address 010 not incrementing\n");
errors += 1;
return 1;
}
// check 017, make sure address wrap-around works
@@ -89,26 +88,26 @@ main(int argc, char *argv[])
if (result != 0)
{
printf("G: auto-index at address 017 not indirectly addressing\n");
errors += 1;
return 1;
}
result = mem_get(017, false);
if (result != 2)
{
printf("H: auto-index at address 017 not incrementing\n");
errors += 1;
return 1;
}
mem_put(017, false, 0x3fff);
result = mem_get(017, true);
if (result != 2)
{
printf("I: auto-index at address 017 not indirectly addressing\n");
errors += 1;
return 1;
}
result = mem_get(017, false);
if (result != 0x4000)
{
printf("J: auto-index at address 017 not incrementing\n");
errors += 1;
return 1;
}
// now save memory to a file
@@ -116,22 +115,24 @@ main(int argc, char *argv[])
mem_clear();
for (addr = 0; addr < MEM_SIZE; ++addr)
mem_put(addr, false, addr);
mem_save_core("imlac.core");
fd = fopen("imlac.core", "wb");
mem_save_core(fd);
fclose(fd);
// clear memory and read core file back in
mem_clear();
mem_load_core("imlac.core");
fd = fopen("imlac.core", "rb");
mem_load_core(fd);
fclose(fd);
for (addr = 0; addr < MEM_SIZE; ++addr)
{
if (mem_get(addr, false) != addr)
{
printf("K: mem_get(0x%04x) was 0x%04x, should be 0x%04x\n",
addr, mem_get(addr, false), addr);
errors += 1;
return 1;
}
}
printf("%d errors found\n", errors);
return 0;
}

0
vimlac/test_ptr.c Normal file → Executable file
View File

84
vimlac/trace.c Normal file → Executable file
View File

@@ -1,27 +1,89 @@
/*
* Trace routines for the imlac simulator.
* Trace routines for vimlac.
*/
#include <stdarg.h>
#include <stdio.h>
#include "vimlac.h"
#include "cpu.h"
bool TraceFlag = false;
/******************************************************************************
* Description : printf()-style output routine to RAW screen.
* Parameters : like printf()
* Returns :
* Comments :
******************************************************************************/
void
Emit(char *fmt, ...)
{
va_list ap;
char buff[512];
char *chptr;
va_start(ap, fmt);
vsprintf(buff, fmt, ap);
va_end(ap);
for (chptr = buff; *chptr != '\0'; ++chptr)
fprintf(stdout, "%c", *chptr);
fflush(stdout);
}
void
DumpRegs(char *buff)
{
sprintf(buff, "AC=0%6.6o\tL=%1.1o", cpu_get_AC(), cpu_get_L());
}
/******************************************************************************
Description : printf()-style trace routine to dump registers.
Parameters :
Returns :
Comments :
******************************************************************************/
void
traceRegs(void)
{
static char outbuff[512];
if (TraceFlag != false)
{
char emitbuff[512];
DumpRegs(outbuff);
sprintf(emitbuff, "\t;%s", outbuff);
Emit(emitbuff);
}
}
/******************************************************************************
Description : printf()-style trace routine.
Parameters : like printf()
Returns :
Comments :
Comments :
******************************************************************************/
void
trace(char *fmt, ...)
{
va_list ap;
char buff[1024];
static char outbuff[512];
va_start(ap, fmt);
vsprintf(buff, fmt, ap);
fprintf(stdout, "%s\n", buff);
va_end(ap);
if (TraceFlag != false)
{
va_list ap;
va_start(ap, fmt);
vsprintf(outbuff, fmt, ap);
va_end(ap);
Emit("0%6.6o\t%s", cpu_get_prev_PC(), outbuff);
traceRegs();
Emit("\n");
}
}

2
vimlac/trace.h Normal file → Executable file
View File

@@ -1,5 +1,5 @@
/*
* Interface for the imlac TRACE routine(s).
* Interface for the vimlac trace routines.
*/
#ifndef TRACE_H

132
vimlac/ttyin.c Normal file → Executable file
View File

@@ -1,149 +1,41 @@
/*
* Implementation for the imlac TTYIN (TTY input) device.
* Implementation for the vimlac TTY input device.
*/
#include "imlac.h"
#include "vimlac.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;
static bool flag; /* true if char ready to read */
/******************************************************************************
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)
void
ttyin_clear_flag(void)
{
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;
flag = false;
}
/******************************************************************************
Description : Dismount papertape file from device.
Parameters :
Returns :
Comments : Turns motor off.
******************************************************************************/
void ttyin_dismount(void)
BYTE
ttyin_get_char(void)
{
if (open_file)
if (fclose(open_file) != 0)
filename = NULL;
open_file = NULL;
device_ready = true;
at_eof = true;
value = TTYIN_EOF;
return ' ';
}
/******************************************************************************
Description : Read the current value of the papertape device.
Parameters :
Returns :
Comments :
******************************************************************************/
int ttyin_get_char(void)
bool
ttyin_ready(void)
{
return value;
return flag;
}
/******************************************************************************
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;
}
}
}
}

9
vimlac/ttyin.h Normal file → Executable file
View File

@@ -1,15 +1,12 @@
/*
* Interface for the imlac TTYIN (TTY input).
* Interface for the vimlac TTY input device.
*/
#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);
BYTE ttyin_get_char(void);
bool ttyin_ready(void);
#endif

119
vimlac/ttyout.c Normal file → Executable file
View File

@@ -1,136 +1,41 @@
/*
* Implementation for the imlac TTYOUT (TTY output) device.
* Implementation for the vimlac TTY output device.
*/
#include "imlac.h"
#include "vimlac.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;
static bool flag; /* true if char ready to read */
/******************************************************************************
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)
void
ttyout_clear_flag(void)
{
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;
flag = false;
}
/******************************************************************************
Description : Dismount papertape file from device.
Parameters :
Returns :
Comments : Turns motor off.
******************************************************************************/
void ttyout_dismount(void)
void
ttyout_send(BYTE ch)
{
if (open_file)
if (fclose(open_file) != 0)
filename = NULL;
open_file = NULL;
device_ready = true;
return;
}
/******************************************************************************
Description : Write a byte value to the device.
Parameters :
Returns :
Comments :
******************************************************************************/
void ttyout_send(BYTE value)
bool
ttyout_ready(void)
{
if (device_ready)
fwrite(&value, 1, 1, open_file);
return flag;
}
/******************************************************************************
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;
}
}
}

9
vimlac/ttyout.h Normal file → Executable file
View File

@@ -1,17 +1,12 @@
/*
* Interface for the imlac TTYOUT (TTY input).
* Interface for the vimlac TTY output device.
*/
#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);
void ttyout_send(BYTE);
bool ttyout_ready(void);
void ttyout_tick(long cycles);
#endif