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

Putting pymlac trace into vimlac

This commit is contained in:
Ross Wilson 2018-07-28 19:56:18 +07:00
parent 13c0c39da1
commit 6d808fbefd
11 changed files with 1001 additions and 238 deletions

View File

@ -1,9 +1,9 @@
DEVFILES = cpu.o dcpu.o ptrptp.o memory.o kb.o ttyin.o ttyout.o trace.o error.o log.o plist.o bootstrap.o
CFILES = cpu.c dcpu.c ptrptp.c memory.c kb.c ttyin.c ttyout.c trace.c error.c log.c plist.c bootstrap.c
HFILES = cpu.h dcpu.h ptrptp.h memory.h kb.h ttyin.h ttyout.h trace.h error.h log.h plist.h bootstrap.h
DEVFILES = cpu.o dcpu.o ptrptp.o memory.o kb.o ttyin.o ttyout.o trace.o error.o log.o plist.o bootstrap.o display_pbm.o
CFILES = cpu.c dcpu.c ptrptp.c memory.c kb.c ttyin.c ttyout.c trace.c error.c log.c plist.c bootstrap.c display_pbm.c
HFILES = cpu.h dcpu.h ptrptp.h memory.h kb.h ttyin.h ttyout.h trace.h error.h log.h plist.h bootstrap.h display_pbm.h
OFILES = vimlac.o $(DEVFILES)
CFLAGS=-O2 -Wall -ansi -pedantic -std=c99 -g
CFLAGS=-O2 -Wall -pedantic -std=c99 -g
test: test_cpu
rm -f vimlac.log trace.out
@ -26,8 +26,9 @@ test_plist: test_plist.c $(DEVFILES) Makefile
test_memory: test_memory.c memory.c memory.h Makefile
gcc -o test_memory ${CFLAGS} memory.c test_memory.c
vimlac: $(CFILES)
gcc -o vimlac ${CFLAGS} $(DEVFILES) vimlac.c
#vimlac: $(CFILES)
# gcc -o vimlac ${CFLAGS} $(DEVFILES) vimlac.c
clean:
rm -f *.pyc *.o vimlac test_ptr test_memory *~ _#*#_.*
rm -Rf *.dSYM

View File

@ -198,18 +198,20 @@ Description : Emulate the IMLAC LAW/LWC instructions.
static int
i_LAW_LWC(bool indirect, WORD address)
{
vlog("i_LAW_LWC");
/* here 'indirect' selects between LWC and LAW */
if (indirect)
{
/* LWC */
r_AC = ~address & WORD_MASK;
trace("LWC\t %5.5o", address);
trace_cpu("LWC\t %5.5o", address);
}
else
{
/* LAW */
r_AC = address;
trace("LAW\t %5.5o", address);
trace_cpu("LAW\t %5.5o", address);
}
return 1;
@ -230,7 +232,7 @@ i_JMP(bool indirect, WORD address)
r_PC = new_address & MEMMASK;
trace("JMP\t%c%5.5o", (indirect) ? '*' : ' ', address);
trace_cpu("JMP\t%c%5.5o", (indirect) ? '*' : ' ', address);
return (indirect) ? 3 : 2;
}
@ -250,7 +252,7 @@ i_DAC(bool indirect, WORD address)
mem_put(new_address, false, r_AC);
trace("DAC\t%c%5.5o", (indirect) ? '*' : ' ', address);
trace_cpu("DAC\t%c%5.5o", (indirect) ? '*' : ' ', address);
return (indirect) ? 3 : 2;
}
@ -272,7 +274,7 @@ i_XAM(bool indirect, WORD address)
mem_put(new_address, false, r_AC);
r_AC = tmp;
trace("XAM\t%c%5.5o", (indirect) ? '*' : ' ', address);
trace_cpu("XAM\t%c%5.5o", (indirect) ? '*' : ' ', address);
return (indirect) ? 3 : 2;
}
@ -297,7 +299,7 @@ i_ISZ(bool indirect, WORD address)
if (new_value == 0)
r_PC = (r_PC + 1) & WORD_MASK;
trace("ISZ\t%c%5.5o", (indirect) ? '*' : ' ', address);
trace_cpu("ISZ\t%c%5.5o", (indirect) ? '*' : ' ', address);
return (indirect) ? 3 : 2;
}
@ -318,7 +320,7 @@ i_JMS(bool indirect, WORD address)
mem_put(new_address, false, r_PC);
r_PC = ++new_address & MEMMASK;
trace("JMS\t%c%5.5o", (indirect) ? '*' : ' ', address);
trace_cpu("JMS\t%c%5.5o", (indirect) ? '*' : ' ', address);
return (indirect) ? 3 : 2;
}
@ -338,7 +340,7 @@ i_AND(bool indirect, WORD address)
r_AC &= mem_get(new_address, false);
trace("AND\t%c%5.5o", (indirect) ? '*' : ' ', address);
trace_cpu("AND\t%c%5.5o", (indirect) ? '*' : ' ', address);
return (indirect) ? 3 : 2;
}
@ -358,7 +360,7 @@ i_IOR(bool indirect, WORD address)
r_AC |= mem_get(new_address, false);
trace("IOR\t%c%5.5o", (indirect) ? '*' : ' ', address);
trace_cpu("IOR\t%c%5.5o", (indirect) ? '*' : ' ', address);
return (indirect) ? 3 : 2;
}
@ -378,7 +380,7 @@ i_XOR(bool indirect, WORD address)
r_AC ^= mem_get(new_address, false);
trace("XOR\t%c%5.5o", (indirect) ? '*' : ' ', address);
trace_cpu("XOR\t%c%5.5o", (indirect) ? '*' : ' ', address);
return (indirect) ? 3 : 2;
}
@ -398,7 +400,7 @@ i_LAC(bool indirect, WORD address)
r_AC = mem_get(new_address, false);
trace("LAC\t%c%5.5o", (indirect) ? '*' : ' ', address);
trace_cpu("LAC\t%c%5.5o", (indirect) ? '*' : ' ', address);
return (indirect) ? 3 : 2;
}
@ -423,7 +425,7 @@ i_ADD(bool indirect, WORD address)
r_AC &= WORD_MASK;
}
trace("ADD\t%c%5.5o", (indirect) ? '*' : ' ', address);
trace_cpu("ADD\t%c%5.5o", (indirect) ? '*' : ' ', address);
return (indirect) ? 3 : 2;
}
@ -449,7 +451,7 @@ i_SUB(bool indirect, WORD address)
r_AC &= WORD_MASK;
}
trace("SUB\t%c%5.5o", (indirect) ? '*' : ' ', address);
trace_cpu("SUB\t%c%5.5o", (indirect) ? '*' : ' ', address);
return (indirect) ? 3 : 2;
}
@ -470,7 +472,7 @@ i_SAM(bool indirect, WORD address)
if (r_AC == mem_get(new_address, false))
r_PC = (r_PC + 1) & WORD_MASK;
trace("SAM\t%c%5.5o", (indirect) ? '*' : ' ', address);
trace_cpu("SAM\t%c%5.5o", (indirect) ? '*' : ' ', address);
return (indirect) ? 3 : 2;
}
@ -484,7 +486,7 @@ Description : Decode the 'microcode' instructions.
static int
microcode(WORD instruction)
{
char trace_msg[10]; /* little buffer for opcode */
char trace_cpu_msg[10]; /* little buffer for opcode */
/* T1 */
if (instruction & 001)
@ -519,37 +521,37 @@ microcode(WORD instruction)
r_L = (~r_L) & 1;
}
/* do some sort of trace */
strcpy(trace_msg, "");
/* do some sort of trace_cpu */
strcpy(trace_cpu_msg, "");
switch (instruction)
{
case 0100000: strcat(trace_msg, "NOP"); break;
case 0100001: strcat(trace_msg, "CLA"); break;
case 0100002: strcat(trace_msg, "CMA"); break;
case 0100003: strcat(trace_msg, "STA"); break;
case 0100004: strcat(trace_msg, "IAC"); break;
case 0100005: strcat(trace_msg, "COA"); break;
case 0100006: strcat(trace_msg, "CIA"); break;
case 0100010: strcat(trace_msg, "CLL"); break;
case 0100011: strcat(trace_msg, "CAL"); break;
case 0100020: strcat(trace_msg, "CML"); break;
case 0100030: strcat(trace_msg, "STL"); break;
case 0100040: strcat(trace_msg, "ODA"); break;
case 0100041: strcat(trace_msg, "LDA"); break;
case 0100000: strcat(trace_cpu_msg, "NOP"); break;
case 0100001: strcat(trace_cpu_msg, "CLA"); break;
case 0100002: strcat(trace_cpu_msg, "CMA"); break;
case 0100003: strcat(trace_cpu_msg, "STA"); break;
case 0100004: strcat(trace_cpu_msg, "IAC"); break;
case 0100005: strcat(trace_cpu_msg, "COA"); break;
case 0100006: strcat(trace_cpu_msg, "CIA"); break;
case 0100010: strcat(trace_cpu_msg, "CLL"); break;
case 0100011: strcat(trace_cpu_msg, "CAL"); break;
case 0100020: strcat(trace_cpu_msg, "CML"); break;
case 0100030: strcat(trace_cpu_msg, "STL"); break;
case 0100040: strcat(trace_cpu_msg, "ODA"); break;
case 0100041: strcat(trace_cpu_msg, "LDA"); break;
}
if ((instruction & 0100000) == 0)
{
/* bit 0 is clear, it's HLT */
cpu_on = false;
if (trace_msg[0] != 0)
strcat(trace_msg, "+HLT");
if (trace_cpu_msg[0] != 0)
strcat(trace_cpu_msg, "+HLT");
else
strcat(trace_msg, "HLT");
strcat(trace_cpu_msg, "HLT");
}
strcat(trace_msg, "\t");
trace(trace_msg);
strcat(trace_cpu_msg, "\t");
trace_cpu(trace_cpu_msg);
return 1;
}
@ -564,10 +566,10 @@ 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");
trace_cpu("DSF\t");
return 1;
}
@ -586,7 +588,7 @@ i_HRB(void)
{
r_AC |= ptr_read();
trace("HRB\t");
trace_cpu("HRB\t");
return 1;
}
@ -601,10 +603,10 @@ 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");
trace_cpu("DSN\t");
return 1;
}
@ -623,7 +625,7 @@ i_HSF(void)
if (ptr_ready())
r_PC = (r_PC + 1) & WORD_MASK;
trace("HSF\t");
trace_cpu("HSF\t");
return 1;
}
@ -642,7 +644,7 @@ i_HSN(void)
if (!ptr_ready())
r_PC = (r_PC + 1) & WORD_MASK;
trace("HSN\t");
trace_cpu("HSN\t");
return 1;
}
@ -659,7 +661,7 @@ i_KCF(void)
{
kb_clear_flag();
trace("KCF\t");
trace_cpu("KCF\t");
return 1;
}
@ -676,7 +678,7 @@ i_KRB(void)
{
r_AC |= kb_get_char();
trace("KRB\t");
trace_cpu("KRB\t");
return 1;
}
@ -694,7 +696,7 @@ i_KRC(void)
r_AC |= kb_get_char();
kb_clear_flag();
trace("KRC\t");
trace_cpu("KRC\t");
return 1;
}
@ -712,7 +714,7 @@ i_KSF(void)
if (kb_ready())
r_PC = (r_PC + 1) & WORD_MASK;
trace("KSF\t");
trace_cpu("KSF\t");
return 1;
}
@ -730,7 +732,7 @@ i_KSN(void)
if (!kb_ready())
r_PC = (r_PC + 1) & WORD_MASK;
trace("KSN\t");
trace_cpu("KSN\t");
return 1;
}
@ -747,7 +749,7 @@ i_PPC(void)
{
ptp_punch(r_AC & 0xff);
trace("PPC\t");
trace_cpu("PPC\t");
return 1;
}
@ -765,7 +767,7 @@ i_PSF(void)
if (ptp_ready())
r_PC = (r_PC + 1) & WORD_MASK;
trace("PSF\t");
trace_cpu("PSF\t");
return 1;
}
@ -788,7 +790,7 @@ i_RAL(int shift)
r_AC = ((r_AC << 1) + oldlink) & WORD_MASK;
}
trace("RAL\t %d", shift);
trace_cpu("RAL\t %d", shift);
return 1;
}
@ -811,7 +813,7 @@ i_RAR(int shift)
r_AC = ((r_AC >> 1) | (oldlink << 15)) & WORD_MASK;
}
trace("RAR\t %d", shift);
trace_cpu("RAR\t %d", shift);
return 1;
}
@ -828,7 +830,7 @@ i_RCF(void)
{
ttyin_clear_flag();
trace("RCF\t");
trace_cpu("RCF\t");
return 1;
}
@ -845,7 +847,7 @@ i_RRB(void)
{
r_AC |= ttyin_get_char();
trace("RRB\t");
trace_cpu("RRB\t");
return 1;
}
@ -863,7 +865,7 @@ i_RRC(void)
r_AC |= ttyin_get_char();
ttyin_clear_flag();
trace("RRC\t");
trace_cpu("RRC\t");
return 1;
}
@ -881,7 +883,7 @@ i_RSF(void)
if (ttyin_ready())
r_PC = (r_PC + 1) & WORD_MASK;
trace("RSF\t");
trace_cpu("RSF\t");
return 1;
}
@ -899,7 +901,7 @@ i_RSN(void)
if (!ttyin_ready())
r_PC = (r_PC + 1) & WORD_MASK;
trace("RSN\t");
trace_cpu("RSN\t");
return 1;
}
@ -919,7 +921,7 @@ i_SAL(int shift)
while (shift-- > 0)
r_AC = ((r_AC << 1) & WORD_MASK) | oldbit0;
trace("SAL\t %d", shift);
trace_cpu("SAL\t %d", shift);
return 1;
}
@ -941,7 +943,7 @@ i_SAR(int shift)
r_AC = (r_AC >> 1) | oldbit0;
}
trace("SAR\t %d", shift);
trace_cpu("SAR\t %d", shift);
return 1;
}
@ -959,7 +961,7 @@ i_SSF(void)
if (cpu_sync_on)
r_PC = (r_PC + 1) & WORD_MASK;
trace("SSF\t");
trace_cpu("SSF\t");
return 1;
}
@ -977,7 +979,7 @@ i_SSN(void)
if (!cpu_sync_on)
r_PC = (r_PC + 1) & WORD_MASK;
trace("SSN\t");
trace_cpu("SSN\t");
return 1;
}
@ -994,7 +996,7 @@ i_TCF(void)
{
ttyout_clear_flag();
trace("TCF\t");
trace_cpu("TCF\t");
return 1;
}
@ -1012,7 +1014,7 @@ i_TPC(void)
ttyout_send(r_AC & 0xff);
ttyout_clear_flag();
trace("TPC\t");
trace_cpu("TPC\t");
return 1;
}
@ -1029,7 +1031,7 @@ i_TPR(void)
{
ttyout_send(r_AC & 0xff);
trace("TPR\t");
trace_cpu("TPR\t");
return 1;
}
@ -1047,7 +1049,7 @@ i_TSF(void)
if (ttyout_ready())
r_PC = (r_PC + 1) & WORD_MASK;
trace("TSF\t");
trace_cpu("TSF\t");
return 1;
}
@ -1065,7 +1067,7 @@ i_TSN(void)
if (!ttyout_ready())
r_PC = (r_PC + 1) & WORD_MASK;
trace("TSN\t");
trace_cpu("TSN\t");
return 1;
}
@ -1083,7 +1085,7 @@ i_ASZ(void)
if (r_AC == 0)
r_PC = (r_PC + 1) & WORD_MASK;
trace("ASZ\t");
trace_cpu("ASZ\t");
return 1;
}
@ -1101,7 +1103,7 @@ i_ASN(void)
if (r_AC != 0)
r_PC = (r_PC + 1) & WORD_MASK;
trace("ASN\t");
trace_cpu("ASN\t");
return 1;
}
@ -1119,7 +1121,7 @@ i_ASP(void)
if ((r_AC & HIGHBITMASK) == 0)
r_PC = (r_PC + 1) & WORD_MASK;
trace("ASP\t");
trace_cpu("ASP\t");
return 1;
}
@ -1137,7 +1139,7 @@ i_LSZ(void)
if (r_L == 0)
r_PC = (r_PC + 1) & WORD_MASK;
trace("LSZ\t");
trace_cpu("LSZ\t");
return 1;
}
@ -1155,7 +1157,7 @@ i_LSN(void)
if (r_L != 0)
r_PC = (r_PC + 1) & WORD_MASK;
trace("LSN\t");
trace_cpu("LSN\t");
return 1;
}
@ -1173,7 +1175,7 @@ i_ASM(void)
if (r_AC & HIGHBITMASK)
r_PC = (r_PC + 1) & WORD_MASK;
trace("ASM\t");
trace_cpu("ASM\t");
return 1;
}
@ -1190,7 +1192,7 @@ i_DLA(void)
{
dcpu_set_PC(r_AC);
trace("DLA\t");
trace_cpu("DLA\t");
return 1;
}
@ -1205,7 +1207,7 @@ Description : Emulate the IMLAC CTB instruction.
static int
i_CTB(void)
{
trace("CTB\t");
trace_cpu("CTB\t");
return 1;
}
@ -1222,7 +1224,7 @@ i_DOF(void)
{
dcpu_stop();
trace("DOF\t");
trace_cpu("DOF\t");
return 1;
}
@ -1240,7 +1242,7 @@ i_DON(void)
dcpu_set_DRSindex(0);
dcpu_start();
trace("DON\t");
trace_cpu("DON\t");
return 1;
}
@ -1257,7 +1259,7 @@ i_HOF(void)
{
ptr_stop();
trace("HOF\t");
trace_cpu("HOF\t");
return 1;
}
@ -1274,7 +1276,7 @@ i_HON(void)
{
ptr_start();
trace("HON\t");
trace_cpu("HON\t");
return 1;
}
@ -1289,7 +1291,7 @@ Description : Emulate the IMLAC STB instruction.
static int
i_STB(void)
{
trace("STB\t");
trace_cpu("STB\t");
return 1;
}
@ -1306,7 +1308,7 @@ i_SCF(void)
{
Sync40HzOn = false;
trace("SCF\t");
trace_cpu("SCF\t");
return 1;
}
@ -1321,7 +1323,7 @@ Description : Emulate the IMLAC IOS instruction.
static int
i_IOS(void)
{
trace("IOS\t");
trace_cpu("IOS\t");
return 1;
}
@ -1336,7 +1338,7 @@ Description : Emulate the IMLAC IOT101 instruction.
static int
i_IOT101(void)
{
trace("IOT101\t");
trace_cpu("IOT101\t");
return 1;
}
@ -1351,7 +1353,7 @@ Description : Emulate the IMLAC IOT111 instruction.
static int
i_IOT111(void)
{
trace("IOT111\t");
trace_cpu("IOT111\t");
return 1;
}
@ -1365,7 +1367,7 @@ Description : Emulate the IMLAC i_IOT131 instruction.
static int
i_IOT131(void)
{
trace("i_IOT131\t");
trace_cpu("i_IOT131\t");
return 1;
}
@ -1380,7 +1382,7 @@ Description : Emulate the IMLAC i_IOT132 instruction.
static int
i_IOT132(void)
{
trace("i_IOT132\t");
trace_cpu("i_IOT132\t");
return 1;
}
@ -1395,7 +1397,7 @@ Description : Emulate the IMLAC IOT134 instruction.
static int
i_IOT134(void)
{
trace("IOT134\t");
trace_cpu("IOT134\t");
return 1;
}
@ -1410,7 +1412,7 @@ Description : Emulate the IMLAC IOT141 instruction.
static int
i_IOT141(void)
{
trace("IOT141\t");
trace_cpu("IOT141\t");
return 1;
}
@ -1425,7 +1427,7 @@ Description : Emulate the IMLAC IOF instruction.
static int
i_IOF(void)
{
trace("IOF\t");
trace_cpu("IOF\t");
return 1;
}
@ -1440,7 +1442,7 @@ Description : Emulate the IMLAC ION instruction.
static int
i_ION(void)
{
trace("ION\t");
trace_cpu("ION\t");
return 1;
}
@ -1629,5 +1631,3 @@ cpu_execute_one(void)
return 0; /* CAN'T REACH */
}

View File

@ -6,7 +6,7 @@
#ifndef CPU_H
#define CPU_H
#include "vimlac.h"
//#include "vimlac.h"
/******
* Exported functions.

View File

@ -9,22 +9,56 @@
#include "vimlac.h"
#include "dcpu.h"
#include "memory.h"
#include "display_pbm.h"
#include "trace.h"
/******
* Constants, etc.
******/
#define MSBBITS 6
#define LSBBITS 5
#define MSBMASK 03740
#define LSBMASK 037
// full 11 bits of display addressing
#define DMASK 03777
// AC bits that set DX or DY
#define BITS10 01777
#define DMSB 03740
#define DLSB 037
// display CPU constants - modes
#define MODE_NORMAL 0
#define MODE_DEIM 1
// full 11 bits of display addressing
#define DMASK 03777
// AC bits that set DX or DY
#define BITS10 01777
#define DMSB 03740
#define DLSB 037
/******
* Emulated registers, state, memory, etc.
******/
static WORD r_PC;
static WORD Prev_r_PC;
static int r_DRSindex;
static WORD DPC = 0; // the display PC
static WORD Prev_DPC; // the *previous* display PC
static WORD DRS[] = {0, 0, 0, 0, 0, 0, 0, 0}; // display CPU stack
static int DRSindex; //
static int DX; //
static int DY; //
static float DScale = 4; // display scale (1, 2, 4, 8)
int DIB = 0; // ????
static BYTE Mode = MODE_NORMAL; // DEIM mode
static bool Running = false; // true if display processor is running
/******
* Environment stuff. PTR and TTY in and out files, etc
******/
static bool cpu_is_on; /* true if display processor is running */
static char DEIM_result[10]; // holds DEIM_decode() result
/******************************************************************************
@ -33,24 +67,32 @@ Description : Functions to get/set various registers.
Returns :
Comments :
******************************************************************************/
WORD
dcpu_get_PC(void)
{
return r_PC;
return DPC;
}
WORD
dcpu_get_prev_PC(void)
{
return Prev_DPC;
}
void
dcpu_set_PC(WORD value)
{
r_PC = value;
DPC = value;
}
void
dcpu_set_DRSindex(int value)
{
r_DRSindex = value;
DRSindex = value;
}
@ -63,9 +105,7 @@ Description : Function to handle unrecognized instruction.
static void
illegal(void)
{
WORD oldPC = Prev_r_PC & MEMMASK;
/* memdump(LogOut, oldPC - 8, 16); */
WORD oldPC = Prev_DPC & MEMMASK;
error("INTERNAL ERROR: "
"unexpected main processor opcode %06.6o at address %06.6o",
@ -73,55 +113,477 @@ illegal(void)
}
/******************************************************************************
Description : Decode a DEIM byte into human text.
Parameters : byte - the DEIM byte to decode
Returns : A string that describes the DEIM byte
Comments : Uses the static buffer "DEIM_result".
******************************************************************************/
char *
DEIMdecode(BYTE byte)
{
// empty the result buffer
char *bptr = DEIM_result;
*bptr = '\0';
// now decode the DEIM byte
if (byte & 0x80)
{
if (byte & 0x40)
{
strcat(bptr, "B");
*++bptr = '\0';
}
else
{
strcat(bptr, "D");
*++bptr = '\0';
if (byte & 0x20)
{
strcat(bptr, "-");
*++bptr = '\0';
}
sprintf(bptr, "%d", (byte >> 3) & 0x03);
bptr = DEIM_result + strlen(DEIM_result);
if (byte & 0x04)
{
strcat(bptr, "-");
*++bptr = '\0';
}
sprintf(bptr, "%d", byte & 0x03);
bptr = DEIM_result + strlen(DEIM_result);
}
}
else
{
if (byte == 0111)
{
strcat(bptr, "N");
*++bptr = '\0';
}
else if (byte == 0151)
{
strcat(bptr, "R");
*++bptr = '\0';
}
else if (byte == 0171)
{
strcat(bptr, "F");
*++bptr = '\0';
}
else if (byte == 0200)
{
strcat(bptr, "P");
*++bptr = '\0';
}
else
{
sprintf(bptr, "A%03o", byte);
bptr = DEIM_result + strlen(DEIM_result);
}
}
return DEIM_result;
}
/******************************************************************************
Description : Execute a DEIM instruction byte.
Parameters : byte - the DEIM byte to decode
: last - 'true' if the last byte in a word
Returns : A trace string that describes the DEIM byte
Comments :
******************************************************************************/
static
char *doDEIMByte(BYTE byte, bool last)
{
char *trace = DEIMdecode(byte);
if (byte & 0x80) // increment mode
{
int dx = (byte & 0x18) >> 3; // extract X/Y deltas
int dy = (byte & 0x03);
int prevDX = DX; // save previous position
int prevDY = DY;
if (byte & 0x20) // get dx sign and move X
{
DX -= dx * DScale;
}
else
{
DX += dx * DScale;
}
if (byte & 0x04) // get dy sign and move Y
{
DY -= dy * DScale;
}
else
{
DY += dy * DScale;
}
if (byte & 0x40) // if beam on
{
display_draw(prevDX, prevDY, DX, DY);
}
}
else // control instructions
{
if (byte & 0x40) // escape DEIM mode
{
Mode = MODE_NORMAL;
}
if (byte & 0x20) // DRJM
{
if (DRSindex <= 0)
{
illegal();
}
DRSindex -= 1;
DPC = DRS[DRSindex];
}
if (byte & 0x10) // inc X MSB
{
DX += (1 << LSBBITS);
}
if (byte & 0x08) // clear X LSB
{
DX &= MSBMASK;
}
if (byte & 0x02) // inc Y MSB
{
DY += (1 << LSBBITS);
}
if (byte & 0x01) // clear Y LSB
{
DY &= MSBMASK;
}
}
return trace;
}
/******************************************************************************
Description : The emulated display CPU instructions.
Parameters :
Returns : The number of display CPU cycles executed.
Comments :
******************************************************************************/
static
int i_DDXM(void)
{
DX -= 040;
trace_dcpu("DDXM");
return 1;
}
static
int i_DDYM(void)
{
DY -= 040;
trace_dcpu("DDYM");
return 1;
}
static
int i_DEIM(WORD address)
{
Mode = MODE_DEIM;
trace_dcpu("DEIM %s", doDEIMByte(address & 0377, true));
return 1;
}
static
int i_DHLT(void)
{
Running = false;
trace_dcpu("DHLT");
return 1;
}
static
int i_DHVC(void)
{
trace_dcpu("DHVC");
// TODO: should DO SOMETHING here?
return 1;
}
static
int i_DIXM(void)
{
DX += 04000;
trace_dcpu("DIXM");
return 1;
}
static
int i_DIYM(void)
{
DY += 04000;
trace_dcpu("DIYM");
return 1;
}
static
int i_DJMP(WORD address)
{
DPC = MASK_MEM(address + (DIB << 12));
trace_dcpu("DJMP %04o", address);
return 1;
}
static
int i_DJMS(WORD address)
{
if (DRSindex >= 8)
{
illegal();
}
DRS[DRSindex] = DPC;
DRSindex += 1;
DPC = MASK_MEM(address + (DIB << 12));
trace_dcpu("DJMS %04o", address);
return 1;
}
static
int i_DLXA(WORD address)
{
DX = (address & BITS10) << 1;
trace_dcpu("DLXA %04o", address);
return 1;
}
static
int i_DLYA(WORD address)
{
DY = (address & BITS10) << 1;
trace_dcpu("DLYA %04o", address);
return 1;
}
static
int i_DLVH(WORD word1)
{
WORD word2 = mem_get(DPC, false);
DPC = MASK_MEM(DPC + 1);
WORD word3 = mem_get(DPC, false);
DPC = MASK_MEM(DPC + 1);
// WORD dotted = word2 & 040000;
// WORD beamon = word2 & 020000;
WORD negx = word3 & 040000;
WORD negy = word3 & 020000;
WORD ygtx = word3 & 010000;
WORD M = word2 & 007777;
WORD N = word3 & 007777;
int prevDX = DX;
int prevDY = DY;
if (ygtx) // M is y, N is x
{
if (negx)
DX -= N;
else
DX += N;
if (negy)
DY -= M;
else
DY += M;
}
else // M is x, N is y
{
if (negx)
DX -= M;
else
DX += M;
if (negy)
DY -= N;
else
DY += N;
//display_draw(prevDX, prevDY, DX, DY, dotted);
display_draw(prevDX, prevDY, DX, DY);
}
trace_dcpu("DLVH");
return 3;
}
static
int i_DRJM(void)
{
if (DRSindex <= 0)
{
illegal();
}
DRSindex -= 1;
DPC = DRS[DRSindex];
trace_dcpu("DRJM");
return 1; // FIXME check # cycles used
}
static
int i_DSTB(int block)
{
DIB = block;
trace_dcpu("DSTB %d", block);
return 1;
}
static
int i_DSTS(int scale)
{
if (scale == 0)
DScale = 0.5;
else if (scale == 1)
DScale = 1.0;
else if (scale == 2)
DScale = 2.0;
else if (scale == 3)
DScale = 3.0;
else
illegal();
trace_dcpu("DSTS %d", scale);
return 1; // FIXME check # cycles used
}
static
int page00(WORD instruction)
{
int cycles = 0;
if (instruction == 000000) // DHLT
cycles = i_DHLT();
else if (instruction == 004000) // DNOP
{
cycles = 1;
trace_dcpu("DNOP");
}
else if (instruction == 004004) // DSTS 0
cycles = i_DSTS(0);
else if (instruction == 004005) // DSTS 1
cycles = i_DSTS(1);
else if (instruction == 004006) // DSTS 2
cycles = i_DSTS(2);
else if (instruction == 004007) // DSTS 3
cycles = i_DSTS(3);
else if (instruction == 004010) // DSTB 0
cycles = i_DSTB(0);
else if (instruction == 004011) // DSTB 1
cycles = i_DSTB(1);
else if (instruction == 004040) // DRJM
cycles = i_DRJM();
else if (instruction == 004100) // DDYM
cycles = i_DDYM();
else if (instruction == 004200) // DDXM
cycles = i_DDXM();
else if (instruction == 004400) // DIYM
cycles = i_DIYM();
else if (instruction == 005000) // DIXM
cycles = i_DIXM();
else if (instruction == 006000) // DHVC
cycles = i_DHVC();
else
illegal();
return cycles;
}
/******************************************************************************
Description : Function to execute one display processor instruction.
Parameters :
Returns :
Returns : The number of display CPU cycles executed.
Comments :
******************************************************************************/
int
dcpu_execute_one(void)
{
WORD instruction = 0;
bool indirect = false;
WORD opcode = 0;
WORD address = 0;
/******
* If processor not running, return immediately.
******/
if (!cpu_is_on)
return 0;
/******
* Fetch the instruction. Split into initial opcode and address.
******/
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 */
address = instruction & 03777; /* low 11 bits */
/******
* Now decode it.
******/
#ifdef JUNK
switch (opcode)
if (!Running)
{
return 0;
}
#endif
++instruction;
indirect = !indirect;
++opcode;
++address;
illegal();
return 0;
//WORD dot = DPC;
WORD instruction = mem_get(DPC, false);
DPC = MASK_MEM(DPC + 1);
if (Mode == MODE_DEIM)
{
char *tracestr = doDEIMByte(instruction >> 8, false);
if (Mode == MODE_DEIM)
{
strcat(tracestr, ",");
strcat(tracestr, doDEIMByte(instruction & 0xff, true));
}
trace_dcpu("INC %s", tracestr);
return 1;
}
WORD opcode = instruction >> 12;
WORD address = instruction & 07777;
if (opcode == 000)
{
return page00(instruction);
}
else if (opcode == 001)
{
return i_DLXA(address);
}
else if (opcode == 002)
{
return i_DLYA(address);
}
else if (opcode == 003)
{
return i_DEIM(address);
}
else if (opcode == 004)
{
return i_DLVH(address);
}
else if (opcode == 005)
{
return i_DJMS(address);
}
else if (opcode == 006)
{
return i_DJMP(address);
}
else if (opcode == 007)
{
illegal();
}
else
{
illegal();
}
return 0; // to turn off "control may reach end of non-void function"
}
@ -132,9 +594,9 @@ Description : Function to get CPU state.
Comments :
******************************************************************************/
bool
dcpu_on(void)
dcpu_running(void)
{
return cpu_is_on;
return Running;
}
@ -147,7 +609,7 @@ Description : Function to start the CPU.
void
dcpu_start(void)
{
cpu_is_on = true;
Running = true;
}
@ -160,12 +622,12 @@ Description : Function to stop the CPU.
void
dcpu_stop(void)
{
cpu_is_on = false;
Running = false;
}
/******************************************************************************
Description : Function to stop the CPU.
Description : Function to set the DCPU DRS index.
Parameters :
Returns :
Comments :
@ -173,7 +635,32 @@ Description : Function to stop the CPU.
void
dcpu_set_drsindex(int index)
{
r_DRSindex = index;
DRSindex = index;
}
/******************************************************************************
Description : Function to get the display X coord.
Parameters :
Returns :
Comments :
******************************************************************************/
int
dcpu_get_x(void)
{
return DX;
}
/******************************************************************************
Description : Function to get the display Y coord.
Parameters :
Returns :
Comments :
******************************************************************************/
int
dcpu_get_y(void)
{
return DY;
}

View File

@ -6,19 +6,17 @@
#ifndef DCPU_H
#define DCPU_H
#include "vimlac.h"
//#include "vimlac.h"
/******
* Exported functions.
******/
void dcpu_start(void);
void dcpu_stop(void);
int dcpu_execute_one(void);
WORD dcpu_get_PC(void);
void dcpu_set_PC(WORD value);
void dcpu_set_DRSindex(int index);
bool dcpu_on(void);
void dcpu_set_DRSindex(int value);
int dcpu_execute_one(void);
bool dcpu_running(void);
void dcpu_start(void);
void dcpu_stop(void);
void dcpu_set_drsindex(int index);
int dcpu_get_x(void);
int dcpu_get_y(void);
#endif

164
vimlac/display_pbm.c Executable file
View File

@ -0,0 +1,164 @@
/*
* A display object that write *.PBM files.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "vimlac.h"
#include "display_pbm.h"
#include "log.h"
/*****
* constants for the display device
******/
#define PBM_EXTENSION "pbm"
#define SCALE_MAX_X 1024
#define SCALE_MAX_Y 1024
/*****
* State variables for the display
******/
static char *pbm_display; // pointer to display array of chars
static bool pbm_running = false; // true if display is ON
static int pbm_cyclecount = 0; // number of cycles for one instruction execution
static int pbm_sync40 = 0; // counter for 40Hz flag
static int pbm_file_num = 0; // number of next PBM file to write
static bool pbm_dirty = false; // 'true' if buffer unsaved
void
display_reset(void)
{
for (int i = 0; i < SCALE_MAX_X * SCALE_MAX_Y; ++i)
pbm_display[i] = 0;
// set internal state
pbm_running = 0;
pbm_cyclecount = 0;
pbm_sync40 = 1;
pbm_file_num = 0;
pbm_dirty = false;
}
void
display_init(void)
{
pbm_display = (char *) malloc(sizeof(bool) * SCALE_MAX_X * SCALE_MAX_Y);
display_reset();
}
void
display_write(void)
{
char fname[1024];
pbm_file_num += 1;
sprintf(fname, "pymlac_%06d.pbm", pbm_file_num);
printf("fname=%s", fname);
FILE *fd = fopen(fname, "w");
fprintf(fd, "P1\n");
fprintf(fd, "# created by pymlac %s\n", VIMLAC_VERSION);
fprintf(fd, "%d %d\n", SCALE_MAX_X, SCALE_MAX_Y);
for (int i = 0; i < SCALE_MAX_X * SCALE_MAX_Y; ++i)
fprintf(fd, "%d\n", pbm_display[i]);
fclose(fd);
pbm_dirty = false;
}
//*********************************************************
// Draw a line on the screen.
//
// x1, y1 start coordinates
// x2, y2 end coordinates
// dotted True if dotted line, else False (IGNORED)
//
// Algorithm from:
// http://csourcecodes.blogspot.com/2016/06/bresenhams-line-drawing-algorithm-generalized-c-program.html
//*********************************************************
//
void
//draw(int x1, int y1, int x2, int y2, dotted=False)
display_draw(int x1, int y1, int x2, int y2)
{
// convert virtual coords to physical
x1 /= 2;
y1 /= 2;
x2 /= 2;
y2 /= 2;
// invert the Y axis
y1 = SCALE_MAX_Y - y1;
y2 = SCALE_MAX_Y - y2;
// draw the line (Bresenham algorithm)
int x = x1;
int y = y1;
int dx = abs(x2 - x1);
int dy = abs(y2 - y1);
int s1, s2;
if (x2 > x1)
s1 = 1;
else
s2 = -1;
if (y2 > y1)
s2 = 1;
else
s2 = -1;
bool swap = false;
pbm_display[(y-1)*SCALE_MAX_X + x - 1] = 1;
if (dy > dx)
{
int temp = dx;
dx = dy;
dy = temp;
swap = true;
}
int p = 2*dy - dx;
for (int i = 0; i < dx; ++i)
{
pbm_display[(y-1)*SCALE_MAX_X + x - 1] = 1 ;
while (p >= 0)
{
p = p - 2*dx;
if (swap)
x += s1;
else
y += s2;
}
p = p + 2*dy;
if (swap)
y += s2;
else
x += s1;
}
pbm_dirty = true;
}
void
display_clear(void)
{
// clear display, but write display to next PBM file first
if (pbm_dirty)
display_write();
display_reset();
}
void
display_close(void)
{
if (pbm_dirty)
display_write();
free(pbm_display);
}

17
vimlac/display_pbm.h Executable file
View File

@ -0,0 +1,17 @@
/*
* Interface for the vimlac PBM display.
*/
#ifndef DISPLAY_PBM_H
#define DISPLAY_PBM_H
void display_reset(void);
void display_init(void);
void display_write(void);
void display_draw(int x1, int y1, int x2, int y2);
void display_clear(void);
void display_close(void);
#endif

View File

@ -6,11 +6,17 @@
#include "vimlac.h"
#include "cpu.h"
#include "dcpu.h"
#include "log.h"
bool TraceFlag = false;
bool TraceFlag = true;
static char *TraceFile = "trace.out";
static FILE *trace_fp = NULL;
static char CPU_trace[64];
static char DCPU_trace[64];
static char CPU_reg_trace[64];
static char DCPU_reg_trace[64];
/******************************************************************************
@ -44,91 +50,120 @@ trace_close(void)
/******************************************************************************
* Description : printf()-style output routine to RAW screen.
* Parameters : like printf()
* Description : Prepare a new trace outut.
* Parameters :
* Returns :
* Comments :
******************************************************************************/
void
Emit(char *fmt, ...)
trace_start_line(void)
{
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(trace_fp, "%c", *chptr);
fflush(trace_fp);
}
void
DumpRegs(char *buff)
{
sprintf(buff, "AC=0%6.6o\tL=%1.1o", cpu_get_AC(), cpu_get_L());
}
void
trace_delim(char *fmt, ...)
{
va_list ap;
char buff[1024];
va_start(ap, fmt);
vsprintf(buff, fmt, ap);
va_end(ap);
Emit("%s\n", buff);
// set output buffer to empty
CPU_trace[0] = 0;
DCPU_trace[0] = 0;
CPU_reg_trace[0] = 0;
DCPU_reg_trace[0] = 0;
}
/******************************************************************************
Description : printf()-style trace routine to dump registers.
* Description : Write stored data to the trace file.
* Parameters :
* Returns :
* Comments :
******************************************************************************/
void
trace_end_line(void)
{
fprintf(trace_fp, "%06o: %-20s%-20s %-s %-s\n",
cpu_get_prev_PC(), CPU_trace, DCPU_trace,
CPU_reg_trace, DCPU_reg_trace);
fflush(trace_fp);
}
/******************************************************************************
Description : printf()-style trace routine to dump main CPU registers.
Parameters :
Returns :
Comments :
******************************************************************************/
void
traceRegs(void)
trace_regs(void)
{
static char outbuff[512];
TraceFlag = true; // DEBUG
if (TraceFlag != false)
{
char emitbuff[512];
DumpRegs(outbuff);
sprintf(emitbuff, "\t;%s", outbuff);
Emit(emitbuff);
sprintf(CPU_reg_trace, "AC=%06.6o L=%1.1o", cpu_get_AC(), cpu_get_L());
vlog(CPU_reg_trace);
}
}
/******************************************************************************
Description : printf()-style trace routine.
Description : printf()-style trace routine to dump dislpay CPU registers.
Parameters :
Returns :
Comments :
******************************************************************************/
void
trace_dregs(void)
{
TraceFlag = true; // DEBUG
if (TraceFlag != false)
{
sprintf(DCPU_reg_trace, "DPC=%06o X=%04o, Y=%04o",
dcpu_get_PC(), dcpu_get_x(), dcpu_get_y());
vlog(DCPU_reg_trace);
}
}
/******************************************************************************
Description : printf()-style trace routine for the CPU.
Parameters : like printf()
Returns :
Comments :
******************************************************************************/
void
trace(char *fmt, ...)
trace_cpu(char *fmt, ...)
{
static char outbuff[512];
TraceFlag = true; // DEBUG
if (TraceFlag != false)
{
va_list ap;
va_start(ap, fmt);
vsprintf(outbuff, fmt, ap);
vsprintf(CPU_trace, fmt, ap);
va_end(ap);
Emit("0%6.6o\t%s", cpu_get_prev_PC(), outbuff);
traceRegs();
Emit("\n");
trace_regs();
}
}
/******************************************************************************
Description : printf()-style trace routine for the display CPU.
Parameters : like printf()
Returns :
Comments :
******************************************************************************/
void
trace_dcpu(char *fmt, ...)
{
TraceFlag = true; // DEBUG
if (TraceFlag != false)
{
va_list ap;
va_start(ap, fmt);
vsprintf(DCPU_trace, fmt, ap);
va_end(ap);
trace_dregs();
}
}

View File

@ -5,9 +5,16 @@
#ifndef TRACE_H
#define TRACE_H
void trace(char *fmt, ...);
extern bool TraceFlag;
void trace_open(void);
void trace_close(void);
void trace_delim(char *fmt, ...);
void trace_start_line(void);
void trace_end_line(void);
void trace_regs(void);
void trace_dregs(void);
void trace_cpu(char *fmt, ...);
void trace_dcpu(char *fmt, ...);
#endif

View File

@ -38,9 +38,18 @@
#include "memory.h"
#include "ptrptp.h"
#include "cpu.h"
#include "dcpu.h"
#include "trace.h"
#include "log.h"
//*********************************************************
// Conevrt a string to all lower case.
//
// s the string to convert (in situ)
//
// Returns the original string pointer.
//*********************************************************
char *
strtolower(char *s)
{
@ -53,11 +62,13 @@ strtolower(char *s)
}
//*********************************************************
// Convert a string to an integer value.
//
// s the string to convert
// s the string to convert
//
// The string may indicate a decimal or octal value.
//*********************************************************
int
str2int(char *s)
@ -73,21 +84,63 @@ str2int(char *s)
}
//*********************************************************
// Run the emulator until the main/display CPU have
// both stopped.
//*********************************************************
// Trace.init('pymlac.trace', cpu, dcpu)
//
// cpu.running = True
// while cpu.running:
// Trace.start()
//
// log(f'cpu.PC={cpu.PC}')
// cycles = cpu.execute_one_instruction()
// log(f'start_running: cpu.execute_one_instruction returned {cycles}')
// dcycles = dcpu.execute_one_instruction()
// log(f'start_running: dcpu.execute_one_instruction returned {dcycles}')
// ptrptp.ptr_tick(cycles)
// ptrptp.ptp_tick(cycles)
// ttyin.tick(cycles)
//
// Trace.end_line()
// Trace.flush()
//
// Trace.close()
void
run(WORD pc)
{
cpu_set_PC(pc);
cpu_start();
while (true)
trace_open();
//while (cpu_running() && dcpu_running())
while (cpu_running())
{
int cycles = cpu_execute_one();
if (cycles < 1)
break;
ptr_tick(cycles);
vlog("run: loop, PC=%06o", cpu_get_PC());
trace_start_line();
int cycles = cpu_execute_one();
int dcycles = dcpu_execute_one();
ptr_tick(cycles+dcycles);
ptp_tick(cycles+dcycles);
// ttyin_tick(cycles);
trace_end_line();
}
trace_close();
}
//*********************************************************
// Print some help for the befuddled user.
// msg a message to print
//*********************************************************
void
usage(char *msg)
{
@ -127,6 +180,10 @@ usage(char *msg)
}
//*********************************************************
// Start the emulator.
//*********************************************************
int
main(int argc, char *argv[])
{
@ -240,17 +297,21 @@ main(int argc, char *argv[])
}
address = strtolower(argv[ndx]);
ndx += 1;
WORD run_pc;
if (!STREQ(address, "pc"))
{
cpu_set_PC(str2int(address));
vlog("Running from address %s", address);
run_pc = str2int(address);
}
else
{
vlog("Running from current PC %06o", cpu_get_PC());
run_pc = cpu_get_PC();
}
// Trace.set_TraceMap(trace_map);
// start_running(imlac_cpu, imlac_dcpu, imlac_memory, imlac_ptrptp, imlac_ttyin);
run(run_pc);
}
else if (STREQ(opt, "-s"))
{
@ -366,17 +427,5 @@ main(int argc, char *argv[])
sprintf(buff, "Unrecognized option '%s'", opt);
usage(buff);
}
}
// mem_clear(0);
// mem_set_rom(PtrROMImage);
// ptr_mount("test_add.ptp");
// run(040);
// run(0100);
// mem_save_core("vimlac.core");
}

View File

@ -20,6 +20,8 @@
typedef unsigned int WORD;
typedef unsigned char BYTE;
#define MEMORY_SIZE 04000
#define CPU_HERZ 1800000
#define MEMMASK 0xffff
#define HIGHBITMASK 0x8000
@ -33,5 +35,8 @@ typedef unsigned char BYTE;
// macro to more reliably compare strings
#define STREQ(a, b) ((a) && (strcmp((a), (b)) == 0))
// macro to mask an address to the address space limits
#define MASK_MEM(addr) (addr & (MEMORY_SIZE - 1))
#endif