diff --git a/README b/README new file mode 100644 index 0000000..fde13fe --- /dev/null +++ b/README @@ -0,0 +1,15 @@ +This is the IMLAC simulator written in Python - pymlac. +This python version is slowly being converted from the C version. + +The IMLAC: http://en.wikipedia.org/wiki/Imlac_PDS-1 + +The directories here are: + + bin - place for imlac papertape executables (*.ptp & other files) + disasm - an imlac executable disassembler + (for either papertape or tty programs) + iasm - imlac cross assembler program (ptp or tty) + idasm - an interactive disassembler (ptp or tty) + images - loadable imlac images I have found on the 'net + pymlac - the imlac emulator in python + vimlac.pics - various pictures of vimlac (C interpreter) screens diff --git a/bin/2locFltPtMathSrc.ptp b/bin/2locFltPtMathSrc.ptp new file mode 100755 index 0000000..94217d1 Binary files /dev/null and b/bin/2locFltPtMathSrc.ptp differ diff --git a/bin/40tp_blockPunch1.0.ptp b/bin/40tp_blockPunch1.0.ptp new file mode 100644 index 0000000..52ccd7f Binary files /dev/null and b/bin/40tp_blockPunch1.0.ptp differ diff --git a/bin/40tp_debugger5.0.ptp b/bin/40tp_debugger5.0.ptp new file mode 100755 index 0000000..892afeb Binary files /dev/null and b/bin/40tp_debugger5.0.ptp differ diff --git a/bin/40tp_eightLevelTest2.1AlphaGraphic.ptp b/bin/40tp_eightLevelTest2.1AlphaGraphic.ptp new file mode 100755 index 0000000..d35c9e3 Binary files /dev/null and b/bin/40tp_eightLevelTest2.1AlphaGraphic.ptp differ diff --git a/bin/40tp_lightPen1.0.ptp b/bin/40tp_lightPen1.0.ptp new file mode 100755 index 0000000..592418f Binary files /dev/null and b/bin/40tp_lightPen1.0.ptp differ diff --git a/bin/40tp_loSpeedAssm601.ptp b/bin/40tp_loSpeedAssm601.ptp new file mode 100755 index 0000000..aa0cc9f Binary files /dev/null and b/bin/40tp_loSpeedAssm601.ptp differ diff --git a/bin/40tp_longVectorTest.ptp b/bin/40tp_longVectorTest.ptp new file mode 100755 index 0000000..699902c Binary files /dev/null and b/bin/40tp_longVectorTest.ptp differ diff --git a/bin/40tp_simpleDisplay.ptp b/bin/40tp_simpleDisplay.ptp new file mode 100755 index 0000000..2431952 Binary files /dev/null and b/bin/40tp_simpleDisplay.ptp differ diff --git a/bin/40tp_spacewar2.5.ptp b/bin/40tp_spacewar2.5.ptp new file mode 100755 index 0000000..e78ffb5 Binary files /dev/null and b/bin/40tp_spacewar2.5.ptp differ diff --git a/bin/40tp_symFormII_1.2C1_8kg.ptp b/bin/40tp_symFormII_1.2C1_8kg.ptp new file mode 100755 index 0000000..154bd74 Binary files /dev/null and b/bin/40tp_symFormII_1.2C1_8kg.ptp differ diff --git a/bin/40tp_tse-4_supGrid.ptp b/bin/40tp_tse-4_supGrid.ptp new file mode 100755 index 0000000..64d8669 Binary files /dev/null and b/bin/40tp_tse-4_supGrid.ptp differ diff --git a/bin/40tp_ttyio.ptp b/bin/40tp_ttyio.ptp new file mode 100755 index 0000000..73e2d3c Binary files /dev/null and b/bin/40tp_ttyio.ptp differ diff --git a/bin/40tp_upperMemTest1.ptp b/bin/40tp_upperMemTest1.ptp new file mode 100755 index 0000000..89d31db Binary files /dev/null and b/bin/40tp_upperMemTest1.ptp differ diff --git a/bin/README b/bin/README new file mode 100644 index 0000000..eba16b6 --- /dev/null +++ b/bin/README @@ -0,0 +1,3 @@ +This holds the papertape (PTP) programs for the imlac. + +Most of these were obtained from: http://www.ubanproductions.com/imlac_sw.html diff --git a/bin/blockpunchsrc.pdf b/bin/blockpunchsrc.pdf new file mode 100644 index 0000000..9cefa76 Binary files /dev/null and b/bin/blockpunchsrc.pdf differ diff --git a/bin/checkAxprimIGSR_fortranSrc.ptp b/bin/checkAxprimIGSR_fortranSrc.ptp new file mode 100755 index 0000000..1713a49 Binary files /dev/null and b/bin/checkAxprimIGSR_fortranSrc.ptp differ diff --git a/bin/fortranARDSsrc.ptp b/bin/fortranARDSsrc.ptp new file mode 100755 index 0000000..cae2862 Binary files /dev/null and b/bin/fortranARDSsrc.ptp differ diff --git a/bin/integerMath.ptp b/bin/integerMath.ptp new file mode 100755 index 0000000..389e0a2 Binary files /dev/null and b/bin/integerMath.ptp differ diff --git a/bin/keybrd.ptp b/bin/keybrd.ptp new file mode 100755 index 0000000..6e4a856 Binary files /dev/null and b/bin/keybrd.ptp differ diff --git a/bin/lowerMemTest1.ptp b/bin/lowerMemTest1.ptp new file mode 100755 index 0000000..db0c8c6 Binary files /dev/null and b/bin/lowerMemTest1.ptp differ diff --git a/bin/lowspeedassembler.pdf b/bin/lowspeedassembler.pdf new file mode 100644 index 0000000..51cb7c3 Binary files /dev/null and b/bin/lowspeedassembler.pdf differ diff --git a/bin/munch b/bin/munch new file mode 100644 index 0000000..7e545c3 Binary files /dev/null and b/bin/munch differ diff --git a/bin/munch.ptp b/bin/munch.ptp new file mode 100644 index 0000000..7e545c3 Binary files /dev/null and b/bin/munch.ptp differ diff --git a/bin/unlabeled.ptp b/bin/unlabeled.ptp new file mode 100755 index 0000000..9295446 Binary files /dev/null and b/bin/unlabeled.ptp differ diff --git a/docs/PDS-1D_ProgrammingGuide.pdf b/docs/PDS-1D_ProgrammingGuide.pdf new file mode 100755 index 0000000..422fc9a Binary files /dev/null and b/docs/PDS-1D_ProgrammingGuide.pdf differ diff --git a/docs/PDS-1D_Schematics.pdf b/docs/PDS-1D_Schematics.pdf new file mode 100755 index 0000000..37c2daf Binary files /dev/null and b/docs/PDS-1D_Schematics.pdf differ diff --git a/docs/PDS-1_TechnicalMan.pdf b/docs/PDS-1_TechnicalMan.pdf new file mode 100755 index 0000000..2f0f5c7 Binary files /dev/null and b/docs/PDS-1_TechnicalMan.pdf differ diff --git a/docs/PDS-4 Programming Card 1.jpg b/docs/PDS-4 Programming Card 1.jpg new file mode 100755 index 0000000..26a1b46 Binary files /dev/null and b/docs/PDS-4 Programming Card 1.jpg differ diff --git a/docs/PDS-4 Programming Card 1c.jpg b/docs/PDS-4 Programming Card 1c.jpg new file mode 100755 index 0000000..3e30e8c Binary files /dev/null and b/docs/PDS-4 Programming Card 1c.jpg differ diff --git a/docs/PDS-4 Programming Card 2.jpg b/docs/PDS-4 Programming Card 2.jpg new file mode 100755 index 0000000..9074ddc Binary files /dev/null and b/docs/PDS-4 Programming Card 2.jpg differ diff --git a/docs/PDS-4 Programming Card 2c.jpg b/docs/PDS-4 Programming Card 2c.jpg new file mode 100755 index 0000000..d882b20 Binary files /dev/null and b/docs/PDS-4 Programming Card 2c.jpg differ diff --git a/docs/PDS-4 Programming Card 3.jpg b/docs/PDS-4 Programming Card 3.jpg new file mode 100755 index 0000000..765bf54 Binary files /dev/null and b/docs/PDS-4 Programming Card 3.jpg differ diff --git a/docs/PDS-4 Programming Card 3c.jpg b/docs/PDS-4 Programming Card 3c.jpg new file mode 100755 index 0000000..855dc27 Binary files /dev/null and b/docs/PDS-4 Programming Card 3c.jpg differ diff --git a/docs/PDS-4 Programming Card 4.jpg b/docs/PDS-4 Programming Card 4.jpg new file mode 100755 index 0000000..676aa9f Binary files /dev/null and b/docs/PDS-4 Programming Card 4.jpg differ diff --git a/docs/PDS-4 Programming Card 4c.jpg b/docs/PDS-4 Programming Card 4c.jpg new file mode 100755 index 0000000..a1f73b2 Binary files /dev/null and b/docs/PDS-4 Programming Card 4c.jpg differ diff --git a/docs/README b/docs/README new file mode 100644 index 0000000..ed8c09d --- /dev/null +++ b/docs/README @@ -0,0 +1,11 @@ +Here are various documents describing the architecture and +various programs. + +The picture SydneyUniversityPDS4Rom.png shows the output +of the ROM-60 program that checks the ROM from 040 to 077 +against what it should be in a floppy system. The rom was +turned off and the papertape boot loader was toggled in before +running the ROM-60 program, so the output shows the floppy +bootloader in the "correct" column and the papertape bootloader +in the "actual" column. This is from the PDS-4 that was at +Sydney University in 1978. diff --git a/docs/Sydney_University_PDS-4_Rom.png b/docs/Sydney_University_PDS-4_Rom.png new file mode 100644 index 0000000..c80bede Binary files /dev/null and b/docs/Sydney_University_PDS-4_Rom.png differ diff --git a/iasm/Makefile b/iasm/Makefile new file mode 100755 index 0000000..02b6294 --- /dev/null +++ b/iasm/Makefile @@ -0,0 +1,37 @@ +################################################################################ +# Makefile for the Imlac Cross Assembler (iasm). +################################################################################ +# $Revision: 1.11 $ +################################################################################ + +CCOPTS=-std=c99 -pedantic -Wall -g + + +all: iasm + +iasm: Makefile iasm.h iasm.c assemble.o + $(CC) $(CCOPTS) -o iasm iasm.c assemble.o + +assemble.o: Makefile assemble.h assemble.c + $(CC) $(CCOPTS) -c assemble.c + +clean: + rm -f *.o *~ core iasm *.tty *.core *.trace *.log *.lst # *.ptp + +install: all + cp iasm ../bin + +test: all print.asm +# iasm -l simpledisplay.lst simpledisplay.asm +# -../bin/vimlac -bptr -iptr simpledisplay.ptp -nocorein -d 0177777 -r 040 -t 0100 -r 0100 > simpledisplay.trace + iasm -l print.lst print.asm + -../bin/vimlac -bptr -iptr print.ptp -nocorein -d 0177777 -r 040 -r 0100 +# iasm -l JUMPTEST.LST JUMPTEST.ASM +# -../bin/vimlac -bptr -iptr JUMPTEST.ASM.ptp -nocorein -d 0177777 -r 040 -noclear -t 0100 -r 0100 > JUMPTEST.trace +# ../bin/vimlac -bptr -iptr 40tp_blockPunch1.0.ptp -nocorein -r 040 -otty blockpunch.tty -t 037660 -r 037660 -t 037640 -r 037640 -d 037540 -r -d 037674 -r -t 037670 -r 037670 > blockpunch.trace + +chars.ptp: chars.asm + iasm chars.asm + +reallyclean: clean + diff --git a/iasm/allopcodes.asm b/iasm/allopcodes.asm new file mode 100755 index 0000000..826a6b5 --- /dev/null +++ b/iasm/allopcodes.asm @@ -0,0 +1,132 @@ +;------------------------------- +; Assembler source containing all IMLAC opcodes. +;------------------------------- + org 0100 ; +start law 03777 ; 007777 + lwc 03777 ; 107777 + jmp 03777 ; 013777 + jmp *03777 ; 113777 + dac 03777 ; 023777 + dac *03777 ; 123777 + xam 03777 ; 027777 + xam *03777 ; 127777 + isz 03777 ; 033777 + isz *03777 ; 133777 + jms 03777 ; 037777 + jms *03777 ; 137777 + and 03777 ; 047777 + and *03777 ; 147777 + ior 03777 ; 053777 + ior *03777 ; 153777 + xor 03777 ; 057777 + xor *03777 ; 157777 + lac 03777 ; 053777 + lac *03777 ; 153777 + add 03777 ; 067777 + add *03777 ; 167777 + sub 03777 ; 073777 + sub *03777 ; 173777 + sam 03777 ; 077777 + sam *03777 ; 177777 +;------------------------------- + hlt ; 000000 + hlt 00001 ; 000001 + hlt 03777 ; 003777 + nop ; 100000 + cla ; 100001 + cma ; 100002 + sta ; 100003 + iac ; 100004 + coa ; 100005 + cia ; 100006 + cll ; 100010 + cml ; 100020 + stl ; 100030 + oda ; 100040 + lda ; 100041 + cal ; 100011 +;------------------------------- + ral 0 ; 003000 + ral 3 ; 003003 + rar 0 ; 003020 + rar 3 ; 003023 + sal 0 ; 003040 + sal 3 ; 003043 + sar 0 ; 003060 + sar 3 ; 003063 + don ; 003100 +;------------------------------- + asz ; 002001 + asn ; 102001 + asp ; 002002 + asm ; 102002 + lsz ; 002004 + lsn ; 102004 + dsf ; 002010 + dsn ; 102010 + ksf ; 002020 + ksn ; 102020 + rsf ; 002040 + rsn ; 102040 + tsf ; 002100 + tsn ; 102100 + ssf ; 002200 + ssn ; 102200 + hsf ; 002400 + hsn ; 102400 +;------------------------------- + dla ; 001003 + ctb ; 001011 + dof ; 001012 + krb ; 001021 + kcf ; 001022 + krc ; 001023 + rrb ; 001031 + rcf ; 001032 + rrc ; 001033 + tpr ; 001041 + tcf ; 001042 + tpc ; 001043 + hrb ; 001051 + hof ; 001052 + hon ; 001061 + stb ; 001062 + scf ; 001071 + ios ; 001072 +;------------------------------- + iot 0101 ; 001101 + iot 0111 ; 001111 + iot 0131 ; 001131 + iot 0132 ; 001132 + iot 0134 ; 001134 + iot 0141 ; 001141 + iof ; 001161 + ion ; 001162 + pun ; 001271 + psf ; 001274 +;------------------------------- + dlxa 07777 ; 017777 + dlya 07777 ; 027777 +; deim 07777 ; 037777 + djms 07777 ; 057777 + djmp 07777 ; 067777 +;------------------------------- + dopr 015 ; 004015 + dopr 014 ; 004014 + dhlt ; 000000 + dsts 0 ; 004004 + dsts 1 ; 004005 + dsts 2 ; 004006 + dsts 3 ; 004007 + dstb 0 ; 004010 + dstb 1 ; 004011 + drjm ; 004040 + dixm ; 005000 + diym ; 004400 + ddxm ; 004200 + ddym ; 004100 + dhvc ; 006000 + ddsp ; 004020 + dnop ; 004000 +;------------------------------- + end diff --git a/iasm/assemble.c b/iasm/assemble.c new file mode 100755 index 0000000..4756114 --- /dev/null +++ b/iasm/assemble.c @@ -0,0 +1,1403 @@ +/******************************************************************************\ + * assemble.c * + * ------------ * + * * + * The actual assembler implementation. * + * * + * The assembler is a two-pass assembler. The first pass just fills the * + * symbol table with addresses. The second pass does most of the work. * + * * +\******************************************************************************/ + +#include "iasm.h" +#include "assemble.h" + + +/****** + * Local constants, definitions, etc. + ******/ + +#define BUFFERSIZE 1024 +#define MAXNAME_LEN 7 +#define HASHTABSIZE 1023 +#define MAXBLOCKSIZE 255 +#define WORDADDRMASK 03777 +#define INDIRECTBIT (1 << 15) +#define WORDMASK 0xFFFF + +typedef int WORD; + +typedef struct sym /* one symbol */ +{ + struct sym *next; /* next symbol */ + char name[MAXNAME_LEN + 1]; /* symbol name */ + WORD address; /* symbol address */ +} SYM; + + +/****** + * File globals. + ******/ + +static char inputline[BUFFERSIZE + 1]; +static SYM *hashtab[HASHTABSIZE]; + +static long dot = -1L; +static WORD codeblockstart = 0; +static WORD codeblock[MAXBLOCKSIZE]; +static int nextcodeword = 0; + +static int LineNumber = 0; + + +typedef enum +{ + AYES, /* address MUST be supplied */ + ANO, /* address must NOT be supplied */ + AOPT /* address field is optional */ +} ADDROPT; + +typedef struct +{ + char *opcode; /* opcode string */ + WORD code; /* WORD of code for opcode */ + ADDROPT address; /* address allowed options */ + WORD addrmask; /* bitmask for address */ + BOOL indirect; /* TRUE if indirect allowed */ +} OPCODE; + +OPCODE opcodes[] = +{ + { "LAW", 0004000, AYES, 03777, FALSE }, + { "LWC", 0104000, AYES, 03777, FALSE }, + { "JMP", 0010000, AYES, 03777, TRUE }, + { "DAC", 0020000, AYES, 03777, TRUE }, + { "XAM", 0024000, AYES, 03777, TRUE }, + { "ISZ", 0030000, AYES, 03777, TRUE }, + { "JMS", 0034000, AYES, 03777, TRUE }, + { "AND", 0044000, AYES, 03777, TRUE }, + { "IOR", 0050000, AYES, 03777, TRUE }, + { "XOR", 0054000, AYES, 03777, TRUE }, + { "LAC", 0060000, AYES, 03777, TRUE }, + { "ADD", 0064000, AYES, 03777, TRUE }, + { "SUB", 0070000, AYES, 03777, TRUE }, + { "SAM", 0074000, AYES, 03777, TRUE }, + + { "HLT", 0000000, AOPT, 03777, FALSE }, + { "NOP", 0100000, ANO, 0, FALSE }, + { "CLA", 0100001, ANO, 0, FALSE }, + { "CMA", 0100002, ANO, 0, FALSE }, + { "STA", 0100003, ANO, 0, FALSE }, + { "IAC", 0100004, ANO, 0, FALSE }, + { "COA", 0100005, ANO, 0, FALSE }, + { "CIA", 0100006, ANO, 0, FALSE }, + { "CLL", 0100010, ANO, 0, FALSE }, + { "CML", 0100020, ANO, 0, FALSE }, + { "STL", 0100030, ANO, 0, FALSE }, + { "ODA", 0100040, ANO, 0, FALSE }, + { "LDA", 0100041, ANO, 0, FALSE }, + { "CAL", 0100011, ANO, 0, FALSE }, + + { "RAL", 0003000, AYES, 03, FALSE }, + { "RAR", 0003020, AYES, 03, FALSE }, + { "SAL", 0003040, AYES, 03, FALSE }, + { "SAR", 0003060, AYES, 03, FALSE }, + { "DON", 0003100, ANO, 0, FALSE }, + + { "ASZ", 0002001, ANO, 0, FALSE }, + { "ASN", 0102001, ANO, 0, FALSE }, + { "ASP", 0002002, ANO, 0, FALSE }, + { "ASM", 0102002, ANO, 0, FALSE }, + { "LSZ", 0002004, ANO, 0, FALSE }, + { "LSN", 0102004, ANO, 0, FALSE }, + { "DSF", 0002010, ANO, 0, FALSE }, + { "DSN", 0102010, ANO, 0, FALSE }, + { "KSF", 0002020, ANO, 0, FALSE }, + { "KSN", 0102020, ANO, 0, FALSE }, + { "RSF", 0002040, ANO, 0, FALSE }, + { "RSN", 0102040, ANO, 0, FALSE }, + { "TSF", 0002100, ANO, 0, FALSE }, + { "TSN", 0102100, ANO, 0, FALSE }, + { "SSF", 0002200, ANO, 0, FALSE }, + { "SSN", 0102200, ANO, 0, FALSE }, + { "HSF", 0002400, ANO, 0, FALSE }, + { "HSN", 0102400, ANO, 0, FALSE }, + + { "DLA", 0001003, ANO, 0, FALSE }, + { "CTB", 0001011, ANO, 0, FALSE }, + { "DOF", 0001012, ANO, 0, FALSE }, + { "KRB", 0001021, ANO, 0, FALSE }, + { "KCF", 0001022, ANO, 0, FALSE }, + { "KRC", 0001023, ANO, 0, FALSE }, + { "RRB", 0001031, ANO, 0, FALSE }, + { "RCF", 0001032, ANO, 0, FALSE }, + { "RRC", 0001033, ANO, 0, FALSE }, + { "TPR", 0001041, ANO, 0, FALSE }, + { "TCF", 0001042, ANO, 0, FALSE }, + { "TPC", 0001043, ANO, 0, FALSE }, + { "HRB", 0001051, ANO, 0, FALSE }, + { "HOF", 0001052, ANO, 0, FALSE }, + { "HON", 0001061, ANO, 0, FALSE }, + { "STB", 0001062, ANO, 0, FALSE }, + { "SCF", 0001071, ANO, 0, FALSE }, + { "IOS", 0001072, ANO, 0, FALSE }, + + { "IOT", 0001000, AYES, 0777, FALSE }, + { "IOF", 0001161, ANO, 0, FALSE }, + { "ION", 0001162, ANO, 0, FALSE }, + { "PUN", 0001171, ANO, 0, FALSE }, + { "PSF", 0001174, ANO, 0, FALSE }, + { "PPC", 0001271, ANO, 0, FALSE }, + + { "DLXA", 0010000, AYES, 07777, FALSE }, + { "DLYA", 0020000, AYES, 07777, FALSE }, +/* { "DEIM", 0030000, AYES, 07777, FALSE }, handled as pseudo-op */ + { "DJMS", 0050000, AYES, 07777, FALSE }, + { "DJMP", 0060000, AYES, 07777, FALSE }, + + { "DOPR", 0004000, AYES, 017, FALSE }, + { "DHLT", 0000000, ANO, 0, FALSE }, + { "DSTS", 0004004, AYES, 03, FALSE }, + { "DSTB", 0004010, AYES, 07, FALSE }, + { "DRJM", 0004040, ANO, 0, FALSE }, + { "DIXM", 0005000, ANO, 0, FALSE }, + { "DIYM", 0004400, ANO, 0, FALSE }, + { "DDXM", 0004200, ANO, 0, FALSE }, + { "DDYM", 0004100, ANO, 0, FALSE }, + { "DHVC", 0006000, ANO, 0, FALSE }, + { "DDSP", 0004020, ANO, 0, FALSE }, + { "DNOP", 0004000, ANO, 0, FALSE }, +}; + +#define NUMOPCODES (sizeof(opcodes) / sizeof(opcodes[0])) + + +/****** + * The PTR block loader, origin at 03700. + ******/ + +#define ZEROLEADERSIZE 2 + +WORD blkldr[] = +{ + /* ; Imlac Papertape Program Block Loader */ + /* ; */ + /* ; This loader is loaded by the bootstrap program at x7700, where x=0 for */ + /* ; a 4K machine, and x=1 for an 8K machine, etc. */ + /* ; */ + /* ; The load format consists of one or more contiguous blocks, with no */ + /* ; padding bytes between them. Each block has the form: */ + /* ; */ + /* ; word count (byte) */ + /* ; load address */ + /* ; data word 1 */ + /* ; data word 2 */ + /* ; ... */ + /* ; data word n */ + /* ; checksum */ + /* ; */ + /* ; All values are 16bit words, except the word count, which is an 8bit byte. */ + /* ; Words are always received high-order byte first. */ + /* ; */ + /* ; After the word count there is the load address, followed by */ + /* ; data words, which are loaded starting at "load address". */ + /* ; */ + /* ; The sum of all the data words in the block must be the same as the checksum */ + /* ; word which follows the data words. The checksum is calculated with 16bit */ + /* ; integers, incrementing the sum whenever the 16bit value overflows. */ + /* ; */ + /* ; The end of the load is signalled by a block with a negative starting address. */ + /* ; */ + /* ; Disassembled from the 40tp_simpleDisplay.ptp image file. */ + /* ; */ + /* org 003700 ; */ + /* cksum equ .-1 ;checksum stored here (before loader) */ + 0001032, /* 003700 rcf ; */ + 0013740, /* 003701 jmp patch ;go decide TTY or PTR, clear AC */ + 0023677, /* 003702 ndpatch dac cksum ;zero checksum, AC is zero (from patch) */ + 0037760, /* 003703 jms rdbyte ; */ + 0102001, /* 003704 asn ;wait here for non-zero byte */ + 0013703, /* 003705 jmp .-2 ; */ + 0100006, /* 003706 cia ; */ + 0023777, /* 003707 dac wrdcnt ;store negative word count */ + 0037750, /* 003710 jms rdword ;read load address */ + 0023776, /* 003711 dac ldaddr ; */ + 0077730, /* 003712 sam neg1 ; */ + 0013715, /* 003713 jmp rdblock ; */ + 0000000, /* 003714 hlt ;if load address is -1, halt - finished */ + 0037750, /* 003715 rdblock jms rdword ;now read block to load address */ + 0123776, /* 003716 dac *ldaddr ; */ + 0037731, /* 003717 jms dosum ; */ + 0033776, /* 003720 isz ldaddr ; */ + 0033777, /* 003721 isz wrdcnt ; */ + 0013715, /* 003722 jmp rdblock ; */ + 0037750, /* 003723 jms rdword ;get expected checksum */ + 0073677, /* 003724 sub cksum ;compare with calculated */ + 0102001, /* 003725 asn ; */ + 0013746, /* 003726 jmp newblk ;if same, get next block */ + 0000000, /* 003727 hlt ;if not same, ERROR */ + 0177777, /* 003730 neg1 data 0177777 ; */ + /* ;------------------------ */ + /* ;Compute checksum. Word to sum in AC. */ + /* ;------------------------ */ + 0017720, /* 003731 dosum bss 1 ; */ + 0100010, /* 003732 cll ; */ + 0067677, /* 003733 add cksum ; */ + 0002004, /* 003734 lsz ; */ + 0100004, /* 003735 iac ; */ + 0023677, /* 003736 dac cksum ; */ + 0113731, /* 003737 jmp *dosum ; */ + /* ;------------------------ */ + /* ;Decide what input device we are using, PTR or TTY. */ + /* ;------------------------ */ + 0001061, /* 003740 patch hon ; */ + 0063774, /* 003741 lac ttyset ; */ + 0023761, /* 003742 dac devpat ; */ + 0005032, /* 003743 law 1032 ; */ + 0177775, /* 003744 sam *adr044 ; */ + 0023761, /* 003745 dac devpat ; */ + 0100011, /* 003746 newblk cal ; */ + 0013702, /* 003747 jmp ndpatch ; */ + /* ;------------------------ */ + /* ;Read WORD from input device. */ + /* ;------------------------ */ + 0017711, /* 003750 rdword bss 1 ; */ + 0100011, /* 003751 cal ; */ + 0037760, /* 003752 jms rdbyte ; */ + 0003003, /* 003753 ral 3 ; */ + 0003003, /* 003754 ral 3 ; */ + 0003002, /* 003755 ral 2 ; */ + 0037760, /* 003756 jms rdbyte ; */ + 0113750, /* 003757 jmp *rdword ; */ + /* ;------------------------ */ + /* ;Read BYTE from input device. Read from PTR or TTY. */ + /* ;------------------------ */ + 0017757, /* 003760 rdbyte bss 1 ; */ + 0001032, /* 003761 devpat rcf ;could be patched to 'jmp rdtty' */ + 0102400, /* 003762 hsn ; */ + 0013762, /* 003763 jmp .-1 ; */ + 0002400, /* 003764 hsf ; */ + 0013764, /* 003765 jmp .-1 ; */ + 0001051, /* 003766 hrb ;read PTR byte */ + 0113760, /* 003767 jmp *rdbyte ; */ + 0002040, /* 003770 rdtty rsf ; */ + 0013770, /* 003771 jmp .-1 ; */ + 0001033, /* 003772 rrc ;read TTY byte, clear flag */ + 0113760, /* 003773 jmp *rdbyte ; */ + /* ;------------------------ */ + 0013770, /* 003774 ttyset jmp rdtty ; */ + 0000044, /* 003775 adr044 data 044 ; */ + 0000000, /* 003776 ldaddr data 0 ; */ + 0000000 /* 003777 wrdcnt data 0 ; */ + /* ;------------------------ */ + /* end ; */ +}; + +#define BLKLDR_SIZE (sizeof(blkldr)/sizeof(blkldr[0])) + + +/****** + * Forward prototypes. + ******/ + +static WORD atoo(char *str); +static SYM *deflabel(char *name, WORD address); +static void emitblock(void); +static void emitbyte(WORD word); +static void emitloader(void); +static void emitstart(); +static void emitword(WORD word); +static void emitcode(WORD code); +static WORD geninc(char *field); +static WORD genincbyte(char *field); +static void genlist(WORD code); +static WORD getaddress(char *field, BOOL indok); +static int hash(char *name); +static BOOL isdecimal(char *str); +static BOOL islabel(char *name); +static BOOL isoctal(char *str); +static SYM *lookup(char *label); +static OPCODE *lookupopcode(char *opcode); +static void newcodeblock(WORD org); +static SYM *newSYM(char *name); +static void strupper(char *str); +static void synerror(char *buff, char *fmt, ...); + + +/****************************************************************************** + Name : atoo() +Description : Get octal number from a string. + Parameters : str - string to get octal number from + Returns : The octal value of the string. + Comments : + ******************************************************************************/ +static WORD +atoo(char *str) +{ + WORD result = 0; + + for (; *str; ++str) + result = result * 8 + *str - '0'; + + return result; +} + + +/****************************************************************************** + Name : deflabel() +Description : Define a label in the symbol table. + Parameters : name - name to define + : addr - the label address + Returns : + Comments : + ******************************************************************************/ +static SYM * +deflabel(char *name, WORD addr) +{ + int hashval = hash(name); + SYM *newsym = newSYM(name); + + newsym->address = addr; + + newsym->next = hashtab[hashval]; + hashtab[hashval] = newsym; + + return newsym; +} + + +/****************************************************************************** + Name : delimfields() +Description : Delimit label, opcode and address fields of assembler line. + Parameters : buffer - address of line buffer + : label - address of label pointer (returned) + : opcode - address of opcode pointer (returned) + : field - address of address field pointer (returned) + : comment - address of comment string (returned) + Returns : + Comments : The buffer is broken into shorter strings (destroyed). + ******************************************************************************/ +static void +delimfields(char *buffer, + char **label, char **opcode, char **field, char **comment) +{ + char *chptr; + + /* point 'label', 'opcode' and 'field' to strings */ + *label = *opcode = *field = *comment = NULL; + + chptr = buffer; + if (isalpha(*chptr)) + { + *label = chptr; + while (!isspace(*chptr) && *chptr != ';' && *chptr != '\n') + ++chptr; + *chptr = '\0'; + ++chptr; + } + + while (isspace(*chptr) && *chptr != ';' && *chptr != '\n') + ++chptr; + if (*chptr != ';' && *chptr != '\n') + { + *opcode = chptr; + while (!isspace(*chptr)) + ++chptr; + *chptr = '\0'; + ++chptr; + + while (isspace(*chptr) && *chptr != ';' && *chptr != '\n') + ++chptr; + if (*chptr != ';' && *chptr != '\n') + { + *field = chptr; + while (!isspace(*chptr) && *chptr != ';' && *chptr != '\n') + ++chptr; + *chptr = '\0'; + if (strlen(*field) == 0) + *field = NULL; + } + } + + if (*chptr == ';') + *comment = chptr; + + if (*label) + strupper(*label); + if (*opcode) + strupper(*opcode); + if (*field) + strupper(*field); +} + + +/****************************************************************************** + Name : emitblock() +Description : Emit the code for the current block. + Parameters : + Returns : + Comments : + *****************************************************************************/ +static void +emitblock(void) +{ + if (nextcodeword > 0) + { + WORD checksum; + int i; + + /****** + * Emit block header stuff. + ******/ + + emitbyte(nextcodeword); + emitword(codeblockstart); + + /****** + * Calculate the checksum while we emit code. + ******/ + + checksum = 0; + + for (i = 0; i < nextcodeword; ++i) + { + checksum = checksum + codeblock[i]; + if (checksum & ~WORDMASK) + ++checksum; + checksum &= WORDMASK; + emitword(codeblock[i]); + } + + /****** + * Emit bchecksum. + ******/ + + emitword(checksum); + } +} + + +/****************************************************************************** + Name : emitbyte() +Description : Emit one BYTE to output stream. + Parameters : word - the BYTE value to emit + Returns : + Comments : + ******************************************************************************/ +static void +emitbyte(WORD word) +{ + fputc(word & 0xFF, OutFile); +} + + +/****************************************************************************** + Name : emitcode() +Description : Generate code for one word. + Parameters : code - the WORD to put into current code block + Returns : + Comments : If the block buffer is full, spill to the output file first. + ******************************************************************************/ +static void +emitcode(WORD code) +{ + if (dot == -1L) + synerror(inputline, "Expected ORG pseudo-op"); + + /* if current block is full, emit and reset */ + if (nextcodeword >= MAXBLOCKSIZE) + { + emitblock(); + + codeblockstart = dot; + nextcodeword = 0; + } + + codeblock[nextcodeword++] = code; +} + + +/****************************************************************************** + Name : emitloader() +Description : Emit papertape loader. + Parameters : fname - output filename (for error reporting) + Returns : + Comments : + ******************************************************************************/ +static void +emitloader(void) +{ + int i; + + for (i = 0; i < ZEROLEADERSIZE; ++i) + emitbyte(0); + + for (i = 0; i < BLKLDR_SIZE; ++i) + emitword(blkldr[i]); + + for (i = 0; i < ZEROLEADERSIZE; ++i) + emitbyte(0); +} + + +/****************************************************************************** + Name : emitstart() +Description : Emit papertape end-of-code start block. + Parameters : address - the program start address + Returns : + Comments : We have to emit a block size byte, just use 1 + ******************************************************************************/ +static void +emitstart(WORD address) +{ + emitbyte(1); /* one byte block */ + emitword(address); /* start address */ +} + + +/****************************************************************************** + Name : emitword() +Description : Emit one WORD to output stream. + Parameters : word - the WORD value to emit + : out - open FILE stream for output + Returns : + Comments : + ******************************************************************************/ +static void +emitword(WORD word) +{ + fputc((word >> 8) & 0xFF, OutFile); + fputc(word & 0xFF, OutFile); +} + + +/****************************************************************************** + Name : gencode() +Description : Generate code for one line. + Parameters : olabel - pointer to label token (NULL if no label) + : oopcode - pointer to opcode token (NULL if no opcode) + : ofield - pointer to field buffer (NULL if no field) + : comment - pointer to coment buffer (NULL if no field) + Returns : TRUE if assembly should continue, FALSE if END opcode found. + Comments : Called by pass 2. + ******************************************************************************/ +static BOOL +gencode(char *olabel, char *oopcode, char *ofield, char *comment) +{ + BOOL result = TRUE; + char *label = CopyStr(olabel); + char *opcode = CopyStr(oopcode); + char *field = CopyStr(ofield); + +/****** + * If there is a label, make sure it's valid. + ******/ + + if (label != NULL && !islabel(label)) + synerror(inputline, "Label '%s' is not legal", olabel); + +/****** + * If there is an opcode, handle it. + ******/ + + if (opcode != NULL) + { + if (STREQ(opcode, "ORG")) + { + if (label != NULL) + synerror(inputline, "Label not allowed on ORG statement"); + + if (field == NULL || !isoctal(field)) + synerror(inputline, "ORG statement must have octal address"); + + emitblock(); + dot = atoo(field); + newcodeblock(dot); + genlist(-1); + } + else if (STREQ(opcode, "END")) + { + if (label != NULL) + synerror(inputline, "Label not allowed on END statement"); + if (field != NULL) + synerror(inputline, "Address not allowed on END statement"); + result = FALSE; + genlist(-1); + } + else if (STREQ(opcode, "DATA")) + { + WORD code; + + if (field == NULL) + synerror(inputline, "Data field required on DATA statement"); + if (isoctal(field)) + code = atoo(field); + else if (isdecimal(field)) + code = atoi(field); + else + code = getaddress(field, FALSE); +/* synerror(inputline, "DATA field must be octal or decimal"); */ + + emitcode(code); + genlist(code); + ++dot; + } + else if (STREQ(opcode, "INC")) + { + WORD code = geninc(field); + + emitcode(code); + genlist(code); + ++dot; + } + else + { + OPCODE *optr = lookupopcode(opcode); + WORD code; + + if (optr == NULL) + synerror(inputline, "Unrecognised opcode"); + + if (optr->address == AYES && field == NULL) + synerror(inputline, "Opcode requires address field"); + + if (optr->address == ANO && field != NULL) + synerror(inputline, "Opcode must not have address field"); + + code = optr->code; + + if (field != NULL) + { + WORD address; + WORD mask = optr->addrmask; + + if (optr->indirect) + mask |= INDIRECTBIT; + + address = getaddress(field, optr->indirect); + if (address & ~mask) + synerror(inputline, "Address field overflow!"); + + code = (code & ~optr->addrmask) | address; + } + + emitcode(code); + genlist(code); + ++dot; + } + } + else /* blank line */ + genlist(-1); + +/****** + * Return line assemble result. + ******/ + + return result; +} + + +/****************************************************************************** + Name : geninc() +Description : Generate code for one word of INC code. + Parameters : field - INC field to generate code for + Returns : The code word generated. + Comments : + ******************************************************************************/ +static WORD +geninc(char *field) +{ + char *endfld; + WORD highbyte; + WORD lowbyte; + + if (field == NULL) + synerror(inputline, "Data field required on INC statement"); + + endfld = strchr(field, ','); + if (endfld == NULL) + synerror(inputline, "Bad data field on INC statement"); + *endfld = '\0'; + ++endfld; + + highbyte = genincbyte(field); + lowbyte = genincbyte(endfld); + + return (highbyte << 8) | lowbyte; +} + + +/****************************************************************************** + Name : genincbyte() +Description : Generate code for one byte of INC code. + Parameters : infile - input filename (error reporting) + : lnum - input line number (error reporting) + : field - INC byte field to generate code for + Returns : + Comments : + ******************************************************************************/ +static WORD +genincbyte(char *field) +{ + static int beam = 1; + + int x; + int y; + int xneg = 0; + int yneg = 0; + + switch (toupper(*field)) + { + case 'A': /* make byte */ + ++field; + if (isoctal(field)) + return atoo(field); + else if (isdecimal(field)) + return atoi(field); + else + synerror(inputline, "Bad INC 'A' field"); + break; + case 'B': /* beam on */ + beam = 1; + ++field; + break; + case 'D': /* beam off */ + beam = 0; + ++field; + break; + case 'E': /* enter INC mode */ +/* beam = 1; UNUSED */ + return 0060; + break; + case 'F': /* escape INC mode */ + return 0171; + break; + case 'N': + return 0111; + break; + case 'P': /* pause (filler) */ + return 0200; + break; + case 'R': + return 0151; + break; + case 'X': + return 0010; + break; + case 'Y': + return 0001; + break; + case '+': case '-': case '0': case '1': case '2': case '3': + break; + default: + synerror(inputline, "Bad INC field"); + break; + } + + if (*field == '+') + { + xneg = 0; + ++field; + } + else if (*field == '-') + { + xneg = 1; + ++field; + } + + if (strchr("0123", *field) == NULL) + synerror(inputline, "Bad INC field"); + + x = *field - '0'; + ++field; + + if (*field == '+') + { + yneg = 0; + ++field; + } + else if (*field == '-') + { + yneg = 1; + ++field; + } + + if (strchr("0123", *field) == NULL) + synerror(inputline, "Bad INC field"); + + y = *field - '0'; + ++field; + + if (strlen(field) != 0) + synerror(inputline, "Bad INC field"); + + return 0200 | (beam << 6) | (xneg << 5) | (x << 3) | (yneg << 2) | y; +} + + + +/****************************************************************************** + Name : genlist() +Description : Generate a listing line, if required. + Parameters : code - the code word generated by this instruction + Returns : + Comments : If 'code' is -1, don't show code word. + ******************************************************************************/ +static void +genlist(WORD code) +{ + if (ListFile != NULL) + { + if (code == -1) + fprintf(ListFile, " %4d:\t%s", + LineNumber, inputline); + else + fprintf(ListFile, "%6.6o %6.6o %4d:\t%s", + code, (int) dot, LineNumber, inputline); + } +} + + +/****************************************************************************** + Name : getaddress() +Description : Get an address value from the 'field' string. + Parameters : field - the field string to get the address from + : indok - TRUE if indirection allowed + Returns : The address value. + Comments : A valid address field can be: + :