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

As copied from code.google.com/rzzzwilson.

This commit is contained in:
Ross Wilson
2015-05-20 19:02:17 +07:00
parent f95cf16fda
commit fa2c04ad95
343 changed files with 42429 additions and 0 deletions

20
vimlac/Makefile Normal file
View File

@@ -0,0 +1,20 @@
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
vimlac: ${OFILES} Makefile
#gcc -o vimlac.so -shared -fPIC ${OFILES}
gcc -o vimlac ${OFILES}
test_ptr: test_ptr.c ptr.c ptr.h Makefile
gcc -o test_ptr ptr.c test_ptr.c
test_memory: test_memory.c memory.c memory.h Makefile
gcc -o test_memory memory.c test_memory.c
clean:
rm -f *.pyc *.o vimlac test_ptr test_memory *~

1560
vimlac/cpu.c Executable file

File diff suppressed because it is too large Load Diff

26
vimlac/cpu.h Executable file
View File

@@ -0,0 +1,26 @@
/******************************************************************************\
* cpu.h *
* ------- *
\******************************************************************************/
#ifndef CPU_H
#define CPU_H
#include "vimlac.h"
/******
* Exported functions.
******/
void cpu_start(void);
void cpu_stop(void);
int cpu_execute_one(void);
WORD cpu_get_AC(void);
WORD cpu_get_L(void);
WORD cpu_get_PC(void);
WORD cpu_get_prev_PC(void);
void cpu_set_PC(WORD pc);
void cpu_set_DS(WORD ds);
#endif

145
vimlac/memory.c Normal file
View File

@@ -0,0 +1,145 @@
/*
* Implementation of vimlac memory.
*
* Memory size is a compile-time constant.
* 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 "memory.h"
/*****
* constants for the memory
******/
/* size of memory is 16K words */
#define ADDR_MASK 0x3fff
/* mask and limits to check if address is auto-index register */
#define INDEX_MASK 03777
#define LOWER_INDEX 010
#define HIGHER_INDEX 017
/*****
* State variables for the memory emulation
******/
#define ROM_START 040
#define ROM_END 077
#define ROM_SIZE (ROM_END - ROM_START + 1)
static bool rom_readonly = false;
/* the physical memory */
static WORD memory[MEM_SIZE];
/******
* Macro to decide if we are using an auto-index register
******/
#define AUTO_INDEX(a) (((a & INDEX_MASK) >= LOWER_INDEX) && ((a & INDEX_MASK) <= HIGHER_INDEX))
WORD
mem_get(WORD address, bool indirect)
{
WORD a = address & ADDR_MASK; /* wrap address to physical memory */
WORD result;
if (indirect && AUTO_INDEX(a)) /* if auto-index and indirect, increment */
memory[a] = (memory[a] + 1) & WORD_MASK;
result = memory[a & ADDR_MASK];
if (indirect)
result = memory[result & ADDR_MASK];
return result;
}
void
mem_put(WORD address, bool indirect, WORD value)
{
WORD a = address & ADDR_MASK; /* wrap address to physical memory */
if (indirect && AUTO_INDEX(a)) /* if auto-index and indirect, increment */
memory[a] = (memory[a] + 1) & WORD_MASK;
if (indirect)
a = memory[a & ADDR_MASK];
memory[a & ADDR_MASK] = value;
}
void
mem_clear(void)
{
if (rom_readonly)
{ /* save the ROM contents */
WORD rom[ROM_SIZE];
memcpy(rom, &memory[ROM_START], sizeof(WORD)*ROM_SIZE);
memset(memory, 0, sizeof(WORD)*MEM_SIZE);
memcpy(&memory[ROM_START], rom, sizeof(WORD)*ROM_SIZE);
}
else
memset(memory, 0, sizeof(WORD)*MEM_SIZE);
}
void
mem_set_rom(WORD *rom)
{
rom_readonly = true;
memcpy(&memory[ROM_START], rom, sizeof(WORD)*ROM_SIZE);
}
void
mem_set_rom_readonly(bool readonly)
{
rom_readonly = readonly;
}
void
mem_load_core(char *filename)
{
FILE *fd = fopen(filename, "rb");
WORD addr;
for (addr = 0; addr < MEM_SIZE; ++addr)
{
unsigned char byte1;
unsigned char byte2;
WORD value;
fread(&byte1, 1, 1, fd);
fread(&byte2, 1, 1, fd);
value = (byte1 << 8) + byte2;
memory[addr] = value;
}
fclose(fd);
}
void
mem_save_core(char *filename)
{
FILE *fd = fopen(filename, "wb");
WORD addr;
/* write memory in bytes, get around endian problems */
for (addr = 0; addr < MEM_SIZE; ++addr)
{
unsigned char byte;
WORD value;
value = memory[addr];
byte = (value >> 8) & 0xff;
fwrite(&byte, 1, 1, fd);
byte = value & 0xff;
fwrite(&byte, 1, 1, fd);
}
fclose(fd);
}

21
vimlac/memory.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* Interface for the vimlac memory.
*/
#ifndef MEMORY_H
#define MEMORY_H
#include "vimlac.h"
#define MEM_SIZE 0x4000
WORD mem_get(WORD address, bool indirect);
void mem_put(WORD address, bool indirect, WORD value);
void mem_clear(void);
void mem_set_rom(WORD *rom);
void mem_set_rom_readonly(bool readonly);
void mem_load_core(char *filename);
void mem_save_core(char *filename);
#endif

124
vimlac/ptr.c Normal file
View File

@@ -0,0 +1,124 @@
/*
* Implementation for the vimlac PTR (papertape reader).
*/
#include "vimlac.h"
#include "ptr.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 CHARS_PER_SECOND 300
#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 PTR_EOF 0377
/*****
* State variables for the PTR device
******/
static bool motor_on = false;
static bool device_ready = false;
static FILE *open_file;
static char *filename = NULL;
static bool at_eof = false;
static BYTE value = PTR_EOF;
static long cycle_count = 0;
int ptr_mount(char *fname)
{
filename = fname;
open_file = fopen(fname, "rb");
if (open_file == NULL)
{
ptr_dismount();
return errno;
}
motor_on = false;
device_ready = false;
at_eof = false;
value = PTR_EOF;
cycle_count = NOT_READY_CYCLES;
return 0;
}
void ptr_dismount(void)
{
if (open_file)
if (fclose(open_file) != 0)
filename = NULL;
open_file = NULL;
motor_on = false;
device_ready = true;
at_eof = true;
value = PTR_EOF;
}
void ptr_start(void)
{
motor_on = true;
device_ready = false;
cycle_count = NOT_READY_CYCLES;
}
void ptr_stop(void)
{
motor_on = false;
cycle_count = NOT_READY_CYCLES;
}
int ptr_read(void)
{
return value;
}
bool ptr_ready(void)
{
return device_ready;
}
void ptr_tick(long cycles)
{
/* if no state change */
if (!motor_on || 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 = PTR_EOF;
}
}
}
}

16
vimlac/ptr.h Normal file
View File

@@ -0,0 +1,16 @@
/*
* Interface for the vimlac PTR (papertape reader).
*/
#ifndef PTR_H
#define PTR_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);
#endif

138
vimlac/test_memory.c Normal file
View File

@@ -0,0 +1,138 @@
/*
* Test the MEMORY implementation.
*/
#include <stdio.h>
#include <assert.h>
#include "vimlac.h"
#include "memory.h"
int
main(int argc, char *argv[])
{
WORD addr;
WORD result;
FILE *fd;
// test the "memory clear" function
mem_clear();
for (addr = 0; addr < MEM_SIZE; ++addr)
assert(mem_get(addr, false) == 0);
// write some data to memory, check written properly
for (addr = 0; addr < MEM_SIZE; ++addr)
mem_put(addr, false, addr);
for (addr = 0; addr < MEM_SIZE; ++addr)
{
if (mem_get(addr, false) != addr)
{
printf("A: mem_get(0x%04x) was 0x%04x, should be 0x%04x\n",
addr, mem_get(addr, false), addr);
return 1;
}
}
for (addr = 0; addr < MEM_SIZE; ++addr)
{
mem_put(addr, false, (MEM_SIZE - addr));
}
for (addr = 0; addr < MEM_SIZE; ++addr)
{
if (mem_get(addr, false) != (MEM_SIZE - addr))
{
printf("B: mem_get(0x%04x) was 0x%04x, should be 0x%04x\n",
addr, mem_get(addr, false), addr);
return 1;
}
}
// now test auto-index locations
mem_put(0, false, 0);
mem_put(1, false, 1);
mem_put(2, false, 2);
mem_put(010, false, 0);
result = mem_get(010, true);
if (result != 1)
{
printf("C: auto-index at address 010 not indirectly addressing\n");
return 1;
}
result = mem_get(010, false);
if (result != 1)
{
printf("D: auto-index at address 010 not incrementing\n");
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");
return 1;
}
result = mem_get(010, false);
if (result != 0)
{
printf("F: auto-index at address 010 not incrementing\n");
return 1;
}
// check 017, make sure address wrap-around works
mem_put(0, false, 2);
mem_put(1, false, 1);
mem_put(2, false, 0);
mem_put(017, false, 1);
result = mem_get(017, true);
if (result != 0)
{
printf("G: auto-index at address 017 not indirectly addressing\n");
return 1;
}
result = mem_get(017, false);
if (result != 2)
{
printf("H: auto-index at address 017 not incrementing\n");
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");
return 1;
}
result = mem_get(017, false);
if (result != 0x4000)
{
printf("J: auto-index at address 017 not incrementing\n");
return 1;
}
// now save memory to a file
mem_set_rom_readonly(false);
mem_clear();
for (addr = 0; addr < MEM_SIZE; ++addr)
mem_put(addr, false, addr);
fd = fopen("imlac.core", "wb");
mem_save_core(fd);
fclose(fd);
// clear memory and read core file back in
mem_clear();
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);
return 1;
}
}
return 0;
}

46
vimlac/test_ptr.c Normal file
View File

@@ -0,0 +1,46 @@
/*
* Test the PTR implementation.
*/
#include "vimlac.h"
#include "ptr.h"
#define TIMEOUT 5000
int
main(int argc, char *argv[])
{
ptr_mount("test1.ptp");
ptr_start();
while (true)
{
int timeout;
unsigned char ch;
timeout = TIMEOUT;
while (!ptr_ready())
{
ptr_tick(2);
if (--timeout < 0)
{
printf("TIMEOUT\n");
return 0;
}
}
ch = ptr_read();
printf("byte is %4.4o (0x%02x)\n", ch, ch);
timeout = TIMEOUT;
while (ptr_ready())
{
ptr_tick(2);
if (--timeout < 0)
{
printf("TIMEOUT\n");
return 0;
}
}
}
}

28
vimlac/vimlac.h Normal file
View File

@@ -0,0 +1,28 @@
/*
* Interface for the vimlac emulator.
*/
#ifndef VIMLAC_H
#define VIMLAC_H
#include <stddef.h>
#include <stdio.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