├── .gitignore
├── DOSBox-PDP8.bat
├── DOSBox-PDP8.lnk
├── DOSBox.exe
├── LST-to-RIM.bat
├── Misc
├── ASCII Characters.gif
├── Another Real Machine The DEC PDP-8.URL
├── DOSBox - an x86 emulator with DOS.URL
├── Doug Jones's PDP-8 manual.URL
├── Graphics Programming Black Book - Graphics Programming and Theory - Articles - Articles - GameDev.net.URL
├── Notes on the History of the DEC PDP-8.URL
├── PDP-8 - Wikipedia, the free encyclopedia.URL
├── PDP-8E Front Panel.URL
├── PDP8 Wiki PDP8 Emulator.URL
├── PDP8 Wiki PDP8 Introduction.URL
├── PDP8 Wiki PDP8 Software.URL
├── Papertapes - Retrocomputing at 45 Baud.URL
├── Professor Mark Csele Digital PDP-8 Computers.URL
└── algorithm - Optimizing Conway's 'Game of Life' - Stack Overflow.URL
├── PDP-8-LST-to-RIM
├── .classpath
├── .project
├── .settings
│ └── org.eclipse.jdt.core.prefs
├── out
│ └── ListToRimEncoder.jar
└── src
│ └── com
│ └── live
│ └── rrutt
│ └── pdp8
│ └── tools
│ └── LstToRimEncoder.java
├── PDP8.jar
├── PDP8Main
├── Brian Shelburne's PDP-8 Home Page.URL
├── PDP8MAIN.EXE
└── readme.txt
├── README.md
├── SDL.dll
├── SDL_net.dll
├── SW
├── CONWAY.LST
├── CONWAY.OBJ
├── CONWAY.RIM
├── Conway.pal
├── HELLO.LST
├── Hello.OBJ
├── Hello.RIM
├── Hello.pal
├── KEYECHO.LST
├── KEYECHO.OBJ
├── KEYECHO.RIM
├── KeyEcho.pal
├── VT100.LST
├── VT100.OBJ
├── VT100.RIM
└── VT100.pal
├── dosbox-0.74-PDP-8.conf
└── dosbox-0.74.conf
/.gitignore:
--------------------------------------------------------------------------------
1 | PDP8Main/*.ico
2 | PDP8Main/*.pdf
3 | PDP-8-LST-to-RIM/bin/
4 | stderr.txt
5 | stdout.txt
6 |
--------------------------------------------------------------------------------
/DOSBox-PDP8.bat:
--------------------------------------------------------------------------------
1 | DOSBox.exe -conf .\dosbox-0.74.conf -conf .\dosbox-0.74-PDP-8.conf
2 |
3 |
--------------------------------------------------------------------------------
/DOSBox-PDP8.lnk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrutt/PDP8/2e6754233c7c765fcd5dc73a65ff75efb5b5ec38/DOSBox-PDP8.lnk
--------------------------------------------------------------------------------
/DOSBox.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrutt/PDP8/2e6754233c7c765fcd5dc73a65ff75efb5b5ec38/DOSBox.exe
--------------------------------------------------------------------------------
/LST-to-RIM.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | set /P PALNAME=Enter LST name (no extension):
3 | java -jar .\PDP-8-LST-to-RIM\out\ListToRimEncoder.jar SW\%PALNAME%.lst
4 | pause
5 |
--------------------------------------------------------------------------------
/Misc/ASCII Characters.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrutt/PDP8/2e6754233c7c765fcd5dc73a65ff75efb5b5ec38/Misc/ASCII Characters.gif
--------------------------------------------------------------------------------
/Misc/Another Real Machine The DEC PDP-8.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://www.quadibloc.com/comp/cp0306.htm
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\3+0LvOtdGyINFUXr1h3JGg==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/Misc/DOSBox - an x86 emulator with DOS.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://www.dosbox.com/download.php?main=1
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\huwCQ6fac0W6X0pLt4RHWw==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/Misc/Doug Jones's PDP-8 manual.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://homepage.cs.uiowa.edu/~jones/pdp8/man/index.html
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\HUjtroyFAE1fM7qxZxySOg==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/Misc/Graphics Programming Black Book - Graphics Programming and Theory - Articles - Articles - GameDev.net.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/graphics-programming-black-book-r1698
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\TF7U+5OtxuU9VTkU8iZcKw==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/Misc/Notes on the History of the DEC PDP-8.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://homepage.cs.uiowa.edu/~jones/pdp8/history.html
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\uH_9jxjp+UxYjF1dOPZAaw==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/Misc/PDP-8 - Wikipedia, the free encyclopedia.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://en.wikipedia.org/wiki/PDP-8
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\MHdpeuvojVOooGR3GAPr9g==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/Misc/PDP-8E Front Panel.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://www.pdp8.net/interface/pdp8e/front_panel.shtml
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\05FHRsz9QDo2XyQlvZlSPA==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/Misc/PDP8 Wiki PDP8 Emulator.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://www.vandermark.ch/pdp8/index.php?n=PDP8.Emulator
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\vRNRK2fk9fqG98O55AX2jw==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/Misc/PDP8 Wiki PDP8 Introduction.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://www.vandermark.ch/pdp8/index.php?n=PDP8.Introduction?from=PDP8.PDP8
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\2_9snVA8z4oDcWMRjQA6pQ==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/Misc/PDP8 Wiki PDP8 Software.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://www.vandermark.ch/pdp8/index.php?n=PDP8.Software
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\2IpbIb9Y0RY_MV8wop9u8A==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/Misc/Papertapes - Retrocomputing at 45 Baud.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://45baud.net/Papertapes
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\5x_19+EhKw35Uh0Wu6hL4w==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/Misc/Professor Mark Csele Digital PDP-8 Computers.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://technology.niagarac.on.ca/staff/mcsele/pdp8.htm
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\oUHeV2GIhTci34Xbm3aXVA==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/Misc/algorithm - Optimizing Conway's 'Game of Life' - Stack Overflow.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://stackoverflow.com/questions/40485/optimizing-conways-game-of-life
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\Richard Rutt\AppData\Local\Mozilla\Firefox\Profiles\bnlauob0.default\shortcutCache\1pOcQLDdAGQFCVddwHTIzw==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/PDP-8-LST-to-RIM/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/PDP-8-LST-to-RIM/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | PDP-8-LST-to-RIM
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/PDP-8-LST-to-RIM/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.6
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.6
12 |
--------------------------------------------------------------------------------
/PDP-8-LST-to-RIM/out/ListToRimEncoder.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrutt/PDP8/2e6754233c7c765fcd5dc73a65ff75efb5b5ec38/PDP-8-LST-to-RIM/out/ListToRimEncoder.jar
--------------------------------------------------------------------------------
/PDP-8-LST-to-RIM/src/com/live/rrutt/pdp8/tools/LstToRimEncoder.java:
--------------------------------------------------------------------------------
1 | package com.live.rrutt.pdp8.tools;
2 |
3 | import java.io.BufferedOutputStream;
4 | import java.io.BufferedReader;
5 | import java.io.File;
6 | import java.io.FileOutputStream;
7 | import java.io.FileReader;
8 | import java.io.FileWriter;
9 | import java.io.IOException;
10 | import java.io.OutputStream;
11 | import java.io.PrintWriter;
12 |
13 | /**
14 | * @author Richard Rutt
15 | *
16 | */
17 | public class LstToRimEncoder {
18 |
19 | private static final String objExtension = ".OBJ";
20 | private static final String rimExtension = ".RIM";
21 | // private static final byte ASCII_CR = 13;
22 | // private static final byte ASCII_LF = 10;
23 | private static final int ASCII_RUBOUT = 0377; // Octal
24 | private static final int leaderByteCount = 2;
25 | private static final int maskHi = 07700; // Octal
26 | private static final int maskLo = 077; // Octal
27 | private static final int track7 = 0100; // Octal
28 |
29 | /**
30 | * Encode a PDP-8 Emulator PAL assembler listing *.LST file into a binary
31 | * RIM loader *.RIM file.
32 | *
33 | * @param args
34 | * command-line arguments.
35 | * @throws IOException
36 | */
37 | public static void main(String[] args) throws IOException {
38 | if ((args == null) || (args.length == 0)) {
39 | showUsage();
40 | } else {
41 | String listingFilename = args[0];
42 | processListingFile(listingFilename);
43 | }
44 | }
45 |
46 | private static void showUsage() {
47 | System.out.print("\n" + "Usage:\n"
48 | + " java LstToRimEncoder .LST\n"
49 | + "Produces .RIM\n" + "\n");
50 | }
51 |
52 | private static void processListingFile(String listingFilename)
53 | throws IOException {
54 | File listingFile = new File(listingFilename);
55 | String listingPath = listingFile.getCanonicalPath();
56 |
57 | String objPath = removeExtension(listingPath) + objExtension;
58 | String rimPath = removeExtension(listingPath) + rimExtension;
59 |
60 | File objFile = new File(objPath);
61 | File rimFile = new File(rimPath);
62 |
63 | System.out.println(String.format("Processing [%s] listing to [%s] ...",
64 | listingPath, objPath));
65 | encodeListingAsObj(listingFile, objFile);
66 |
67 | System.out.println(String.format("Processing [%s] listing to [%s] ...",
68 | listingPath, rimPath));
69 | encodeListingAsRim(listingFile, rimFile);
70 |
71 | System.out.println("Done.");
72 | }
73 |
74 | private static void encodeListingAsObj(File listingFile, File objFile)
75 | throws IOException {
76 |
77 | int inLineCount = 0;
78 | int outLineCount = 0;
79 |
80 | BufferedReader br = null;
81 | PrintWriter pw = null;
82 |
83 | try {
84 | br = new BufferedReader(new FileReader(listingFile));
85 | pw = new PrintWriter(new FileWriter(objFile));
86 |
87 | String line;
88 | while ((line = br.readLine()) != null) {
89 | inLineCount++;
90 | if (isStartAddressLine(line)) {
91 | break; // out of while loop.
92 | } else if (isDataLine(line)) {
93 | String addressString = getAddress(line);
94 | String dataString = getData(line);
95 | pw.println(String.format("%s/%s", addressString, dataString));
96 | outLineCount++;
97 | }
98 | }
99 | } finally {
100 | if (br != null) {
101 | br.close();
102 | }
103 | if (pw != null) {
104 | pw.close();
105 | }
106 | }
107 |
108 | System.out.println(String.format("Processed %d lines into %d lines.",
109 | inLineCount, outLineCount));
110 | }
111 |
112 | private static void encodeListingAsRim(File listingFile, File rimFile)
113 | throws IOException {
114 |
115 | int inLineCount = 0;
116 | int outByteCount = 0;
117 |
118 | BufferedReader br = null;
119 | BufferedOutputStream bos = null;
120 |
121 | try {
122 | br = new BufferedReader(new FileReader(listingFile));
123 | bos = new BufferedOutputStream(new FileOutputStream(rimFile));
124 |
125 | outByteCount += writeLeader(bos);
126 |
127 | String line;
128 | while ((line = br.readLine()) != null) {
129 | inLineCount++;
130 | if (isStartAddressLine(line)) {
131 | break; // out of while loop.
132 | } else if (isDataLine(line)) {
133 | String addressString = getAddress(line);
134 | outByteCount += writeAddress(addressString, bos);
135 | String dataString = getData(line);
136 | outByteCount += writeData(dataString, bos);
137 | }
138 | }
139 |
140 | outByteCount += writeLeader(bos);
141 | } finally {
142 | if (br != null) {
143 | br.close();
144 | }
145 | if (bos != null) {
146 | bos.close();
147 | }
148 | }
149 |
150 | System.out.println(String.format("Processed %d lines into %d bytes.",
151 | inLineCount, outByteCount));
152 | }
153 |
154 | private static boolean isStartAddressLine(String line) {
155 | boolean isStartAddress = false;
156 |
157 | if (line.length() > 0) {
158 | char firstChar = line.charAt(0);
159 | isStartAddress = (firstChar == '$');
160 | }
161 |
162 | return isStartAddress;
163 | }
164 |
165 | private static boolean isDataLine(String line) {
166 | boolean isData = false;
167 |
168 | if (line.length() >= 9) {
169 | char slash = line.charAt(4);
170 | isData = (slash == '/');
171 | }
172 |
173 | return isData;
174 | }
175 |
176 | private static String getAddress(String line) {
177 | return line.substring(0, 4);
178 | }
179 |
180 | private static String getData(String line) {
181 | return line.substring(5, 9);
182 | }
183 |
184 | private static int writeLeader(OutputStream os) throws IOException {
185 | for (int i = 0; i < leaderByteCount; i++) {
186 | os.write(ASCII_RUBOUT);
187 | }
188 | return leaderByteCount;
189 | }
190 |
191 | private static int writeAddress(String value, OutputStream os) throws IOException {
192 | int address = Integer.decode("0" + value); // Interpret as octal;
193 |
194 | int hiAddress = (address & maskHi) >>> 6;
195 | int loAddress = (address & maskLo);
196 |
197 | os.write(hiAddress | track7);
198 | os.write(loAddress);
199 |
200 | return 2;
201 | }
202 |
203 | private static int writeData(String value, OutputStream os) throws IOException {
204 | int data = Integer.decode("0" + value); // Interpret as octal;
205 |
206 | int hiData = (data & maskHi) >>> 6;
207 | int loData = (data & maskLo);
208 |
209 | os.write(hiData);
210 | os.write(loData);
211 |
212 | return 2;
213 | }
214 |
215 | // Reference:
216 | // http://stackoverflow.com/questions/941272/how-do-i-trim-a-file-extension-from-a-string-in-java
217 | private static String removeExtension(String s) {
218 | String separator = System.getProperty("file.separator");
219 | String folder;
220 | String filename;
221 |
222 | // Remove the path up to the filename.
223 | int lastSeparatorIndex = s.lastIndexOf(separator);
224 | if (lastSeparatorIndex < 0) {
225 | folder = "";
226 | filename = s;
227 | } else {
228 | folder = s.substring(0, lastSeparatorIndex + 1);
229 | filename = s.substring(lastSeparatorIndex + 1);
230 | }
231 |
232 | // Remove the extension.
233 | int extensionIndex = filename.lastIndexOf(".");
234 | if (extensionIndex >= 0) {
235 | filename = filename.substring(0, extensionIndex);
236 | }
237 |
238 | return folder + filename;
239 | }
240 | }
241 |
--------------------------------------------------------------------------------
/PDP8.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrutt/PDP8/2e6754233c7c765fcd5dc73a65ff75efb5b5ec38/PDP8.jar
--------------------------------------------------------------------------------
/PDP8Main/Brian Shelburne's PDP-8 Home Page.URL:
--------------------------------------------------------------------------------
1 | [InternetShortcut]
2 | URL=http://www4.wittenberg.edu/academics/mathcomp/bjsdir/PDP8HomePage.htm
3 | IDList=
4 | HotKey=0
5 | IconFile=C:\Users\ruttr\AppData\Local\Mozilla\Firefox\Profiles\32asdpow.default\shortcutCache\JSiqs1GTLgtrBjIAO0oxWg==.ico
6 | IconIndex=0
7 |
--------------------------------------------------------------------------------
/PDP8Main/PDP8MAIN.EXE:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrutt/PDP8/2e6754233c7c765fcd5dc73a65ff75efb5b5ec38/PDP8Main/PDP8MAIN.EXE
--------------------------------------------------------------------------------
/PDP8Main/readme.txt:
--------------------------------------------------------------------------------
1 | The PDP-8 Emulator Program
2 | A Brief Overview
3 |
4 |
5 | 1. Introduction
6 | -----------------
7 |
8 | The PDP-8 Emulator Program (pdp8main.exe) is a program that emulates
9 | (mimics) the PDP-8 architecture on an MS-DOS computer. With it
10 | a user can write, assemble, debug, and run PDP-8 programs and
11 | thereby obtain an understanding of and appreciation for the architecture of the PDP-8.
12 |
13 | The architecture of the PDP-8 is simple and yet elegant. Simple
14 | in that there are only 8 opcodes, clean in that it has an
15 | easily understood architecture, and elegant in its ability to
16 | implement complex operations using a limited instruction set.
17 |
18 | I use the PDP-8 Emulator Program in the teaching of computer organization
19 | at Wittenberg where the simple architecture of the PDP-8 provides
20 | an easy introduction to computer organization, machine code,
21 | and assembly language programming.
22 |
23 | The PDP-8 Emulator Program is provided "as is". Any problems
24 | or suggestions should be addressed to
25 |
26 | Brian J. Shelburne
27 | Department of Math and Comp Sci
28 | Wittenberg University
29 | Springfield, Ohio 45501
30 | email: bshelburne@wittenberg.edu
31 |
32 | The following sections provide a quick introduction to PDP-8
33 | Assembler Language (PAL) programming. It is necessarily brief
34 | and does not cover all details yet kowledgeable readers should
35 | be able to learn enough to write simple programs for
36 | the PDP-8 Emulator. A more complete description of the PDP-8
37 | Emulator and the PAL langauge can be obtained from the accompanying pdf files
38 | containing "The PDP-8 Emulator Program User's Manual- Fall 2002".
39 |
40 |
41 | Table of Contents
42 | ------------------
43 |
44 | 1. Introduction
45 | 2. Quick Overview of PDP-8 Architecture
46 | 3. Effective Address Calculation
47 | 4. An Overview of the PDP-8 Emulator
48 | 5. PDP-8 Machine Code
49 | 6. PDP-8 Assembler Language (PAL) Programs
50 | 7. Calling Subroutines
51 | 8. Doing Simple I/O
52 | 9. The PDP-8 Emulator Program User's Manual
53 |
54 | 2. Quick Overview of PDP-8 Architecture
55 | -----------------------------------------
56 |
57 | Main Memory
58 | -----------
59 |
60 | Main memory of the PDP-8 consists of 4096 (2^12) twelve-bit
61 | words. Memory is partitioned into 32 pages of 128 words.
62 | Addresses in memory are given using a page:offset format.
63 |
64 | Bits within a word are numbered left to right 0 - 11
65 |
66 | msb -> <- lsb
67 | +---+---+---+---+---+---+---+---+---+---+---+---+
68 | 0 1 2 3 4 5 6 7 8 9 10 11
69 |
70 |
71 | CPU Registers
72 | -------------
73 |
74 | There is a single twelve bit accumulator (AC) with a one-bit link
75 | register (L) that captures any carry out of the accumulator.
76 |
77 | Link bit Accumulator
78 |
79 | +---+ +---+---+---+---+---+---+---+---+---+---+---+---+
80 | 0 1 2 3 4 5 6 7 8 9 10 11
81 |
82 | An additional twelve-bit multiply-quotient register (MQ) was used
83 | for multiply/divide operations in advanced models of the PDP-8
84 | (These operations are not supported by emulator program).
85 |
86 | Other registers include
87 |
88 | Console Switch Register (SR) - 12 bits
89 | Program Counter register (PC) - 12 bits
90 | Instruction Register (IR) - 3 bits
91 | Central Processor Memory Address register (CPMA) - 12 bits
92 | Memory Buffer (MB) - 12 bits
93 |
94 | Instruction Formats
95 | -------------------
96 |
97 | The PDP-8 has eight op-codes and three instruction formats.
98 | Opcodes 0 - 5 reference memory (memory reference instructions or
99 | MRI). The MRI format is given below
100 |
101 | Memory Reference Instruction Format
102 |
103 | +---+---+---+---+---+---+---+---+---+---+---+---+
104 | | op-code |IA |MP | Offset Address |
105 | +---+---+---+---+---+---+---+---+---+---+---+---+
106 | 0 1 2 3 4 5 6 7 8 9 10 11
107 |
108 | Bits 0 - 2 : operation code
109 | Bit 3 : Indirect Addressing Bit (0:direct/1:indirect)
110 | Bit 4 : Memory Page (0:Zero Page/1:Current Page)
111 | Bits 5 -11 : Offset Address
112 |
113 |
114 | MRI op-codes
115 |
116 | 0 - Boolean AND memory with accumulator (AND)
117 | 1 - Two's complement Add memory to accumulator (TAD).
118 | and complement Link on overflow
119 | 2 - Increment memory and Skip if Zero (ISZ)
120 | 3 - Deposit accumulator to memory and Clear Accumulator (DCA)
121 | 4 - Jump to Subroutine (JMS)
122 | 5 - Jump always (JMP)
123 |
124 |
125 | Opcode 6 is an I/O operation, more exactly a family of I/O
126 | instructions
127 |
128 | Opcode 6 Format
129 |
130 | +---+---+---+---+---+---+---+---+---+---+---+---+
131 | | 1 1 0 | device number | function |
132 | +---+---+---+---+---+---+---+---+---+---+---+---+
133 | 0 1 2 3 4 5 6 7 8 9 10 11
134 |
135 | Bits 0 - 2 : opcode 6
136 | Bits 3 - 8 : Device Number
137 | Bits 9 - 11 : extended function (operation specification)
138 |
139 |
140 |
141 | Opcode 7 is a family of "micro-instructions" divided into three
142 | groups which include instructions to test, increment,
143 | complement, and rotate the accumulator and/or link bit. Generally
144 | each bit in the extended op-code field (bits 3 - 11)
145 | independently controls a different function. Functions can be
146 | combined creating a class of fairly powerful instructions.
147 |
148 | Opcode 7 Group One Microinstructions
149 |
150 | +---+---+---+---+---+---+---+---+---+---+---+---+
151 | | 1 1 1 | 0 cla cll cma cml rar ral 0/1 iac|
152 | +---+---+---+---+---+---+---+---+---+---+---+---+
153 | 0 1 2 3 4 5 6 7 8 9 10 11
154 |
155 | Opcode 7 Group Two Microinstructions
156 |
157 | +---+---+---+---+---+---+---+---+---+---+---+---+
158 | | 1 1 1 | 1 cla sma sza snl 0/1 osr hlt 0 |
159 | +---+---+---+---+---+---+---+---+---+---+---+---+
160 | 0 1 2 3 4 5 6 7 8 9 10 11
161 |
162 | Opcode 7 Group Three Microinstructions
163 |
164 | +---+---+---+---+---+---+---+---+---+---+---+---+
165 | | 1 1 1 | 1 cla mqa mql 1 |
166 | +---+---+---+---+---+---+---+---+---+---+---+---+
167 | 0 1 2 3 4 5 6 7 8 9 10 11
168 |
169 |
170 | Bits 0 - 2 : opcode 7
171 | Bit 3 : 0: Group 1
172 | Bit 3, 11 : 10 : Group 2/ 11: Group 3
173 | Bits 4 - 11 : extended opcodes - see below
174 |
175 | Group One
176 | cla - clear accumulator
177 | cll - clear link
178 | cma - complement accumulator
179 | cml - complement link
180 | rar - rotate accumulator+link right
181 | ral - rotate accumulator+link left
182 | iac - increment accumulator
183 | bit 10 : 0:rotate once/1:rotate twice
184 |
185 | Group Two
186 | sma - skip on minus accumulator
187 | sza - skip in zero accumulator
188 | snl - skip in non-zero link
189 | osr - or switch register with accumulator
190 | hlt - halt
191 | bit 8 : if 1 then reverse "sense" of bits 5 - 7
192 | not sma -> skip on positive accumulator or spa
193 | not sza -> skip on non-zero accumulator or sna
194 | not snl -> skip on zero link or szl
195 |
196 | Group Three
197 | mqa - or accumulator with MQ register
198 | mql - load MQ register from accumulator and clear
199 |
200 |
201 | 3. Effective Address Calculation
202 | -----------------------------------
203 |
204 | The PDP-8 supports Zero and Current Page Direct Addressing,
205 | Indirect Addressing, and Auto Increment Addressing
206 |
207 | Zero/Current Page Direct Addressing
208 | -----------------------------------
209 |
210 | The format of a Memory Reference Instruction contains only the
211 | seven-bit offset for a memory reference, The five-bit page number
212 | was obtained by using either Zero page addressing (page number =
213 | 00000) or Current page addressing (the five-bit page number of
214 | the address of the instruction was used).
215 |
216 | Example (zero page); If address 6224o contained the instruction
217 | 1167o (written 6224/1167), since bit 4 of the instruction is
218 | zero, the effective address of this TAD instruction would be
219 | obtained by concatenating five zeros to the seven-bit offset
220 | address
221 |
222 | 1 1 6 7 op I M offset
223 | 001 001 110 111 -> 001|0|0|1 110 111
224 | 0 1 6 7
225 | effective address -> 00000 + 1 110 111 = 000 001 110 111
226 |
227 | for an effective address of 0167.
228 |
229 |
230 | Example (current page) ; On the other hand if we have 6224/1367,
231 | since bit 4 is one, the effective address of this TAD instruction
232 | would be obtained by concatenating the leading five bits of the
233 | address of the instruction (110 01 from 6224) to the seven-bit
234 | offset address
235 |
236 | 6 2 2 4 1 1 6 7
237 | 110 010 010 100 <- address/contents -> 001 001 110 111
238 | 110 01 <- page number 1 110 111 <- offset
239 |
240 | Effective address -> 110 01 1 110 111 = 6337
241 |
242 |
243 | Page Zero is accessible from any address in memory. "Global"
244 | variables should be stored on page Zero. "Local" variables should
245 | be stored on the Current page.
246 |
247 |
248 | Indirect Addressing
249 | -------------------
250 |
251 | Zero/Current Page Direct addressing can only address two pages
252 | out of 32. To access the other 30 pages, the PDP-8 supports
253 | indirect addressing (bit three equals 1) where the Zero/Current
254 | Page addressing calculation given above is used to calculate the
255 | address of the effective address.
256 |
257 | Auto Increment Addressing
258 | -------------------------
259 |
260 | Memory locations 010 - 017 (on page zero) function as auto-
261 | increment registers. That is, whenever these addresses are
262 | addressed using indirection, their contents are FIRST incremented
263 | then used as the address of the effective address.
264 |
265 | Example (auto-increment addressing) : Suppose address 0010
266 | contains the value 3407. Instruction 1410 obtains the effective
267 | address as follows:
268 |
269 | 1 4 1 0 op I M offset
270 | 001 100 001 000 -> 001|1|0|0 01 000
271 |
272 | Since indirection is used through address 0010, the contents at
273 | 0010 (3407) first incremented (3410) and this is the effective
274 | address.
275 |
276 |
277 | 4 An Overview of the PDP-8 Emulator Program
278 | ---------------------------------------------------
279 |
280 | The PDP-8 Emulator Program was written in Turbo Pascal v6.0 for DOS.
281 | It has Debug Screen, an Editor/Assembler, Help, and a Run PDP-8 Pgm
282 | screens.
283 |
284 | Debug Screen : Displays contents of registers and one page of
285 | memory (in octal). PgUp and PgDn keys can be used to display any
286 | one of the 32 memory pages. A command line interface allows the
287 | user to directly enter, edit, debug, and execute machine code or
288 | PDP-8 assembler language programs
289 |
290 | Editor/Assembler : A small no-frills text editor allows the user
291 | to create and edit PDP-8 Assembler Language (PAL) programs.
292 | Programs can be assembled and loaded into the memory of the PDP-8
293 | Emulator for execution. A list file showing PAL versus machine
294 | code can be generated.
295 |
296 | Run PDP-8 Pgm : Allows PDP-8 programs to be executed. Includes
297 | displays for some of the registers found on the console of a real
298 | PDP-8. User written PDP-8 I/O subroutines are required to display
299 | results to this screen.
300 |
301 | Help: There on-line help for the Debug, Editor/Assembler,and Run
302 | PDP-8 Pgm screens as well as on-line help for the PDP-8 Assembler
303 | Language.
304 |
305 | Note that all numbers are displayed in OCTAL
306 |
307 |
308 | 5. PDP-8 Machine Code
309 | -----------------------
310 |
311 | Machine code program can be entered directly into the PDP-8
312 | memory from the Debug Screen. The address/contents convention
313 | "nnnn/mmmm" means address "nnnn" contains contents "mmmm".
314 |
315 | Four MRI instructions and seven Opcode 7 instructions are
316 | sufficient to execute a number of simple PDP-8 programs
317 |
318 | Machine Code Assembler Effect
319 | 1xxx TAD Two's Complement Add
320 | 2xxx ISZ Increment and Skip on Zero
321 | 3xxx DCA Deposit and Clear Accumulator
322 | 5xxx JMP Jump Always
323 | 7041 CIA Complement & Increment Accumulator
324 | (same as negate Accumulator)
325 | 7300 CLA CLL Clear Accumulator and Link
326 | 7402 HLT Halt
327 | 7500 SMA Skip on Minus Accumulator
328 | 7440 SZA Skip on Zero Accumulator
329 | 7510 SPA Skip on Positive Accumulator
330 | 7450 SNA Skip on Non-zero Accumulator .
331 |
332 | Example : The following program computes the absolute difference
333 | of A - B (i.e. |A - B|) storing the value at C. A, B, and C are
334 | stored at addresses 0070 - 0072 respectively. nnnn/mmmm denotes
335 | stored mmmm at address nnnn (0050/7300 denotes store 7300 at
336 | address 0050). Before running be sure to set the PC equal to
337 | 0050.
338 |
339 | 0050/7300 clear accumulator and link
340 | 0051/1071 load B (from address 0071)
341 | 0052/7041 negate (complement and add 1)
342 | 0053/1070 add A
343 | 0054/7500 skip if negative
344 | 0055/5057 jump to address 0057
345 | 0056/7041 negate A - B to make positive
346 | 0057/3072 deposit |A - B| to C
347 | 0060/7402 halt
348 |
349 | 0070/0015 A
350 | 0071/0025 B
351 | 0072/0000 C
352 |
353 | Note that a Load instruction is done by adding to cleared
354 | accumulator. Subtraction is done by adding the negative.
355 | Conditional branching is done using Skip on condition coupled
356 | with Jump Always.
357 |
358 | Example ; The following loop program sums the values 1 through 10
359 | (octal). A loop counter (Count) is set up at address 0251 to be
360 | used by the ISZ (Increment and Skip on Zero instruction)
361 |
362 | 0200/7300 clear accumulator and link
363 | 0201/1250 load N (from address 0250)
364 | 0202/7041 negate
365 | 0203/3251 deposit it to Count (address 0251)
366 | 0204/3252 deposit 0 to Index (address 0252)
367 | 0205/3253 deposit 0 to Sum (address 0253)
368 | 0206/2252 increment Index to 1
369 | 0207/1253 load Sum (AC is zero)
370 | 0210/1252 add in Index
371 | 0211/3253 deposit result in Sum (AC is cleared)
372 | 0212/2251 increment Count and Skip if Zero
373 | 0213/5206 otherwise loop - jump to 0206
374 | 0214/7402 halt
375 |
376 | 0250/0012 N
377 | 0251/0000 Count
378 | 0252/0000 Index
379 | 0253/0000 Sum
380 |
381 | Note that Increment and Skip on Zero (opcode 2) is used to
382 | control a counting loop at address 0212 and to increment Index at
383 | address 0206
384 |
385 |
386 | 6. PDP-8 Assembler Language (PAL) Programs
387 | --------------------------------------------
388 |
389 | The format of a PDP-8 Assemble Language instruction has up to
390 | five fields
391 |
392 | symbolic address, opcode(s) i offset /comment
393 |
394 | Commas terminate a symbolic address label, a "/" indicates a
395 | comment. "i" denotes indirection. All field are optional except for
396 | opcodes.
397 |
398 |
399 | Two assembler directive that are useful are
400 |
401 | *nnnn modify value of location counter; assemble code
402 | starting at this address
403 |
404 | $starting_address end of program; set entry point
405 |
406 | The code below sums the integers from 1 to N storing the result
407 | in Sum. By convention most PAL programs begin on page one at
408 | location 0200.
409 |
410 | /
411 | / Code Section
412 | /
413 | *0200
414 | Main, cla cll / clear AC and Link
415 | tad N / load N
416 | cia / negate it
417 | dca Count / deposit it to Count and clear AC
418 | dca Index / zero out Index
419 | dca Sum / zero out sum
420 | Loop, isz Index / add 1 to Index
421 | tad Sum / load Sum
422 | tad Index / add in Index
423 | dca Sum / store result in Sum
424 | isz Count / increment Count and skip on zero
425 | jmp Loop / otherwise loop
426 | hlt / done
427 | jmp Main / allows easy restart
428 | /
429 | / Data Section
430 | /
431 | *0250
432 | N, 10
433 | Count, 0
434 | Index, 0
435 | Sum, 0
436 | $Main / end of pgm - entry point
437 |
438 |
439 | 7. Calling Subroutines
440 | ------------------------
441 |
442 | The JMS - Jump to Subroutine (opcode 4) - instruction stores the
443 | return address at the first address of the subroutine and
444 | branches control to the second location of the subroutine. A
445 | return is made via an indirect jump.
446 |
447 | Example : The following subroutine returns the absolute value of
448 | the accumulator
449 |
450 | Abs, 0 / store return address here
451 | sma / skip in minus accumulator
452 | jmp .+2 / other jump to current location (. dot) + 2
453 | cia / negate accumulator
454 | jmp i Abs / return via indirect jump
455 |
456 | To call this subroutine use
457 |
458 | jms Abs
459 |
460 |
461 | 8. Doing Simple I/O
462 | ---------------------
463 |
464 | I/O on the PDP-8 can be done using programmed I/O transfer using
465 | explicit opcode 6 instructions to do I/O. 8-bit ASCII characters
466 | are transferred between the right-most 8 bits of the accumulator
467 | (bits 4 - 11) and the keyboard or printer. Device 3 is the
468 | keyboard, device 4 is the printer (computer screen).
469 | Synchronization between the CPU and I/O device is handled by a
470 | "flag" bit which is set if the device is ready and cleared if the
471 | device if busy. One of the opcode 6 extended functions is a "skip
472 | on flag set" which is used to put the CPU in a wait loop while
473 | waiting on the device.
474 |
475 | There are a number of Opcode 6 I/O instructions but only the
476 | following five are really needed (two for output to the printer
477 | and three for input from the keyboard). Recall that Device 3 is the
478 | keyboard and Device 4 is the printer (screen).
479 |
480 | Assembler Machine Effect
481 | Mnemonic Code
482 |
483 | TSF 6041 Skip on printer Flag set
484 |
485 | TLS 6046 Load Printer Sequence
486 | Clear printer flag to 0 and
487 | transfer accumulator to printer
488 |
489 | KSF 6031 Skip on Keyboard Flag Set
490 |
491 | KCC 6032 Clear Keyboard Flag and accumulator
492 |
493 | KRB 6036 Read Keyboard Buffer sequence
494 | Clear keyboard flag to 0 and
495 | transfer keyboard buffer to accumulator
496 |
497 | We demonstrate their use by displaying code to read a character
498 | (GetChar) and write a character (Type). Putting the code for both
499 | subroutines on page 30 and using indirect subroutine calls
500 | through page 0 allows these subroutine to called from any memory
501 | address.
502 |
503 | /
504 | / Basic I/O Routine Vectors - Page 0
505 | /
506 | *0050
507 | GetChar, XGetChar
508 | Type, XType
509 | /
510 | / Code Segment - Page 1
511 | /
512 | *0200
513 | Main, cla cll / clear AC and link
514 | kcc / reset keyboard
515 | tls / rest printer
516 | ...
517 | jms i GetChar / read a character
518 | dca Hold / store it
519 | tad Hold / get character
520 | jms i Type / echo to screen
521 | ...
522 |
523 | /
524 | / Basic I/O routines - page 30
525 | /
526 | *7400
527 | XGetChar, 0 / return address here
528 | ksf / is keyboard flag raised?
529 | jmp .-1 / no - loop
530 | krb / yes - read character to AC
531 | jmp i XGetChar / return
532 | XType, 0 / return address here
533 | tsk / is printer flag raised?
534 | jmp .-1 / no - loop
535 | tls / yes - print character
536 | cla cll / clear AC and link
537 | jmp i XType / return
538 | $Main
539 |
540 | Note: PDP-8 Emulator Program does not echo a type character.
541 | GetChar only reads a character; to echo it to the screen you
542 | have to call Type.
543 |
544 |
545 | 9. PDP-8 Emulator User's Manual
546 | ---------------------------------
547 |
548 | Bundled with the PDP-8 Emulator is a PDP-Emulator Program User's Manual
549 | which contains more information about the PDP-8 Emulator Program and the
550 | PDP-8 Assembler Language. The nine pdf files making up the manual are
551 | listed below.
552 |
553 | List of Chapters and Contents
554 | -----------------------------
555 |
556 | Pdp8covr.pdf - cover page and table of contents
557 | Pdp8ch01.pdf - An Overview of PDP-8 Architecture and the
558 | PDP-8 Emulator Program
559 | Pdp8ch02.pdf - PDP-8 Addressing Modes
560 | Pdp8ch03.pdf - PDP-8 Machine Language
561 | Pdp8ch04.pdf - The PDP-8 Assembler Language
562 | Pdp8ch05.pdf - The PDP-8 Instruction Set
563 | Pdp8ch06.pdf - Subroutines, I/O, and Running PDP-8 Programs
564 | Pdp8ch07.pdf - Advanced Programming Examples
565 | Pdp8apdx.pdf - Appendix A: PDP-8 Instructions
566 | Appendix B: PDP-8 Addressing Modes
567 | Appendix C: PDP-8 Emulator Commands
568 | Appendix D: Binary and Octal Integers
569 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PDP-8 Assembly Language Studio
2 |
3 | ## Introduction
4 |
5 | The development of digital computers has occurred within the single lifetime of people still alive today:
6 |
7 | [Wikipedia "Computer" article](http://en.wikipedia.org/wiki/Computer)
8 |
9 | Programmable digital computers execute software written in a variety of programming languages.
10 | Most software written today is written in a high-level language processed by a [compiler](http://en.wikipedia.org/wiki/Compiler) or [interpreter](http://en.wikipedia.org/wiki/Interpreted_language).
11 | The central processing units (CPUs) of computers actually process lower-level instructions produced by the compilers and interpreters.
12 | In earlier decades software programmers worked directly with the CPU instructions using _[Assembly Language](http://en.wikipedia.org/wiki/Assembly_language)_.
13 |
14 | To fully appreciate the power and convenience of high-level programming languages, and the service provided by compilers and interpreters, spend some time writing an algorithm in assembly language.
15 |
16 | This GitHub project provides a teaching environment to learn assembly language programming against the Digital Equipment Corp. PDP-8, which is considered the first successful _[mini-computer](http://en.wikipedia.org/wiki/Minicomputer)_ in the Western Hemisphere.
17 | The PDP-8 was often used for instrumentation and process control applications by small laboratories, who considered the original USD $18,000 price tag a bargain in the mid-1960's.
18 | For comparison, the modern _open source hardware_ [Arduino micro-controller](http://en.wikipedia.org/wiki/Arduino) serves the same purpose for between $25 and $100, depending on the model.
19 |
20 |
21 | ## PDP-8 Emulator
22 |
23 | Brian Shelbourne of Wittenberg University has written a PDP-8 emulator which he uses in his computer organization course.
24 | This emulator is written using Borland [Turbo Pascal](http://en.wikipedia.org/wiki/Turbo_Pascal) version 6.0 and runs in MS-DOS.
25 | The simplicity of the PDP-8 architecture, and the elegance of Turbo Pascal, allows the emulator program size to be only 85 K.
26 |
27 | [Brian Shelburne's PDP-8 Home Page](http://www4.wittenberg.edu/academics/mathcomp/bjsdir/PDP8HomePage.htm)
28 |
29 | Running the PDP-8 emulator in 64-bit versions of Windows, such as Windows 7, requires the use of the [DOSBox](http://www.dosbox.com/download.php?main=1) emulator to run the PDP-8 emulator.
30 | Versions of DOSBox also exist for non-Windows operating systems.
31 | DOSBox serves the historical computer game community but also runs other MS-DOS software.
32 |
33 |
34 | ## PDP-8 Assembly Language
35 |
36 | The original PDP-8 models were implemented using discrete diode-transistor logic, with following models using transistor-transistor logic.
37 | Digital Equipment Corp. mounted several components onto a printed circuit board dubbed a [Flip-Chip](http://en.wikipedia.org/wiki/Flip_Chip_%28trademark%29) module.
38 | This approach was soon superseded by [integrated circuit](http://en.wikipedia.org/wiki/Integrated_circuit) technology, but was a breakthrough approach in the 1960's.
39 |
40 | Here is an image of the PDP-8 chassis with its Flip-Chip module boards: [PDP-8 boards](http://www.vandermark.ch/pdp8/uploads/PDP8/PDP8.Hardware/pdp8-boards.jpg)
41 | (Note that this is a later model PDP-8 and the Flip-Chip boards in this image contain some small-scale integrated circuit chips along with discrete electronic components.)
42 |
43 | In order to keep the Flip-Chip module count to a minimum, the PDP-8 instruction set was extremely minimal even for its day.
44 | This minimalism provides an excellent teaching environment for the basics of digital software computation.
45 |
46 | Here is a primer for the PDP-8 Assembly Language, also known as PAL:
47 |
48 |
49 |
50 | **_Note:_** The PAL source code comment character is a single forward slash "/".
51 | The example PAL programs in this repository use a double-slash "//" to allow the [Notepad++](http://en.wikipedia.org/wiki/Notepad%2B%2B) editor to be configured to color-code *.pal files as if they are the C# language.
52 | This marks comments in green, and numeric values in orange, so they stand out.
53 |
54 | ## Setting up the PDP-8 Assembly Language Studio on Microsoft Windows
55 |
56 | The default scripts in this repository assume it resides on your local workstation in the folder **C:\PDP8**
57 |
58 | This can be achieved by cloning the repository with the following commands in a Command Prompt window:
59 |
60 | cd /d C:
61 | git clone PDP8
62 | cd PDP8
63 |
64 | The example PAL programs reside in the **C:\PDP8\SW** folder.
65 |
66 | ## Hello World using PAL and the PDP-8 Emulator
67 |
68 | To start the PDP-8 Emulator navigate to the **C:\PDP8** folder in Windows File Explorer and double-click on either the **DOSBox-PDP8.bat** batch script or the **DOSBox-PDP8** shortcut icon.
69 |
70 | The DOSBox program launches with the configuration files **dosbox-0.74.conf** and **dosbox-0.74-PDP-8.conf**
71 |
72 | This mounts the **C:\PDP8** Windows folder as if it were the **C:\** drive for the DOSBox, sets the **SW** folder as the current directory, and runs the PDP8Main.exe emulator as directed by the last few lines of **dosbox-0.74-PDP-8.conf**:
73 |
74 | [autoexec]
75 | mount c c:\pdp8
76 | c:
77 | cd sw
78 | ..\pdp8main\pdp8main.exe
79 |
80 | The PDP-8 Emulator main screen appears.
81 |
82 | Press the "F1" key to open the emulator help screens.
83 | Press the "Enter" key to cycle thru the help screens.
84 | Press the "Esc" key to return to the emulator.
85 |
86 | From the PDP-8 Emulator main screen, press the "E" key to enter the **Editor/Assembler** screen in the emulator.
87 |
88 | Press the "R" key to read in a PAL source file.
89 | Type "hello.pal" (without quotes) as the File Name, and then press the "Enter" key.
90 | (Remember that the DOSBox apparent **C:\SW** folder, which is mapped to the **C:\PDP8\SW** Windows folder, is the current directory.)
91 |
92 | The **Hello.pal** assembly language source code appears in the emulator's Editor/Assembler screen in text edit mode.
93 |
94 | Press the "Esc" key (or the "F10" key) to exit text edit mode and return to the Editor/Assembler menu.
95 |
96 | Press the "A" key to assemble the code into the emulator Random Access Memory (RAM).
97 |
98 | When prompted "Do want a list file (y/n) ?" type "y" followed by the "Enter" key.
99 | Enter "hello.lst" followed by the "Enter" key to save the listing file.
100 |
101 | If prompted "File Exists. Overwrite? (y/n) >" answer with "y" followed by the "Enter" key.
102 |
103 | Back in the Editor/Assembler menu, press the "Q" key (or the "Esc" key) to return to emulator main screen.
104 |
105 | Press the "R" key to enter the Run PDP-8 Screen.
106 |
107 | Press the "G" key to run the program.
108 | The phrase "Hello, World!" should appear in the text display and the program will halt, as requested by the **hlt** (halt) instruction at octal address 0204.
109 |
110 | After the **hlt** instruction, the Program Counter (PC) has the octal value 0205, which is a **jmp** (jump) to the program start address at octal 0200.
111 |
112 | Press the "G" key again to resume execution of the program, which should repeat the display of the "Hello, World!" message.
113 |
114 | Each press of the "G" key repeats another execution of the program.
115 |
116 | Return to the emulator main screen by pressing the "Q" or "Esc" key.
117 |
118 | ## Using the Emulator Debug Screen
119 |
120 | To really appreciate the simple elegance underlying all computer software, spend some time in the PDP-8 Emulator Debug Screen.
121 |
122 | Here is a sample debugging session using the "Hello World" program **hello.pal**
123 |
124 | From the PDP-8 Emulator main screen, press the "D" key to enter the Debug screen.
125 |
126 | Type "r" followed by the "Enter" key to reset the emulated PDP-8 memory and registers to all zeros.
127 |
128 | Type "l hello.lst" followed by the "Enter" key to load the assembled "Hello World" program into memory.
129 | This loader command in the emulator interprets the octal address/data pairs that appear in the left margin of the assembly language listing file and loads the appropriate values into the emulated Random Access Memory (RAM).
130 | The **$0200** line near the bottom of the listing, prior to the symbol table dump, instructs the emulator to set the Program Counter (PC) address.
131 |
132 | Type "u" followed by the enter key to un-assemble the instruction at the current address, meaning show the mnemonic symbols for that instruction.
133 |
134 | Press the space bar once to single-step execute the instruction at the current address of the Program Counter.
135 | The next instruction is automatically un-assembled after the instruction completes.
136 |
137 | Continue pressing the space bar to single-step thru the program.
138 |
139 | At any time, you may type "g" followed by the "Enter" key to proceed with automatic execution of the program from the current Program Counter address.
140 |
141 | For more advanced debugging options, press the "F1" key to open the PDP-8 Emulator help screens positioned at the Debugger command page.
142 |
143 | ## Conway's Life
144 |
145 | The example program **Conway.pal** implements [Conway's Life](http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) cellular automata algorithm.
146 |
147 | Details on this implementation are documented in this WordPress blog article:
148 | [Conway's Life Implemented in PDP-8 Assembly Language](http://rickrutt.wordpress.com/2013/10/19/conways-life-implemented-in-pdp-8-assembly-language/)
149 |
150 | Load, assemble, and run the program using the same steps described above for "Hello World", substituting the file name **conway.pal** for **hello.pal**
151 |
152 | The program can be paused after any generation by pressing any key on the keyboard.
153 | The current generation will finish displaying then the program will pause.
154 | Resume the program by pressing the "G" key.
155 |
156 | The PDP-8 Emulator also allows a running program to be paused immediately using the Control-C keyboard combination.
157 |
158 | ## Advanced PDP-8 Emulator with VT-100 Terminal
159 |
160 | The Conway's Life program execution appears best when the output is rendered on a VT-100 terminal that can interpret the [ANSI cursor addressing escape sequences](http://en.wikipedia.org/wiki/ANSI_escape_code).
161 |
162 | A Java implementation of a PDP-8 emulator includes several peripheral devices, including a VT-100 video text terminal.
163 |
164 | [A PDP-8/E Simulator in Java](http://www.vandermark.ch/pdp8/index.php?n=PDP8.Emulator)
165 |
166 | The Java emulator does not read the .LST/.OBJ) paper tape format allowed by the DOSBox compatible PDP-8 Emulator
167 | Instead we need to generate a Read-In Mode (RIM) paper tape file using a custom program provided here.
168 |
169 | In the **C:\PDP8** folder, double-click the **LST-to-RIM.bat** batch script.
170 | When prompted "Enter LST name (no extension):" enter "conway" followed by the "Enter" key.
171 | This will generate *.RIM and *.OBJ files based on the octal address/data pairs in the left margin of the assembly listing file.
172 |
173 | To run the Conway's Life program in the Java emulator, follow these steps:
174 |
175 | Navigate to the **C:\PDP8** folder in Windows file explorer.
176 |
177 | Double-click the **PDP8.jar** file to open the emulator.
178 | Several separate windows appear, representing the various peripheral devices of a high-end late model PDP-8 model E.
179 |
180 | Drag the main **PDP-8/E** console window to the right to expose other windows.
181 |
182 | Minimize the **LP02/LA180** printer window, as we do not need it.
183 | Also minimize the **TU56** DEC-Tape drive.
184 | Minimize the **SI3040-M4043** disk drive.
185 |
186 | Drag the **VT100 Terminal** window down to expose the **PC8E** reader/punch window.
187 |
188 | Right-click somewhere in the **PC8E** window and select **Reader | Open input reader hispeed** from the pop-up menu.
189 | Navigate to and open **C:\PDP8\SW\CONWAY.RIM**
190 |
191 | Click the right side of the third switch graphic to turn the "Reader On".
192 |
193 | Right-click somewhere in the **PDP-8/E** console panel window and select **Boot | RIM loader hi speed** from the pop-up menu.
194 |
195 | The paper tape graphic in the **PC8E** window should proceed to the left.
196 |
197 | Click the **Halt** toggle switch graphic in the **PDP-8/E** console panel window to halt the RIM loader program.
198 | Click the **Halt** toggle again to return it to its "up" position.
199 |
200 | Click the "4" toggle button in the **SWITCH REGISTER** section of the **PDP-8/E** console panel window to lift it up to encode an octal 0200 start address into the Switch Register.
201 |
202 | Click the "AL" toggle to Address Load the 0200 address into the Program Counter memory address.
203 |
204 | Click the "CO" (Continue) toggle in the **START** section of the console panel window to run the program.
205 | (Make sure the "HALT" toggle is in the "up" position.)
206 |
207 |
208 |
209 |
--------------------------------------------------------------------------------
/SDL.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrutt/PDP8/2e6754233c7c765fcd5dc73a65ff75efb5b5ec38/SDL.dll
--------------------------------------------------------------------------------
/SDL_net.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrutt/PDP8/2e6754233c7c765fcd5dc73a65ff75efb5b5ec38/SDL_net.dll
--------------------------------------------------------------------------------
/SW/CONWAY.LST:
--------------------------------------------------------------------------------
1 | ///
2 | //
3 | // Conway's Life for the PDP-8.
4 | //
5 | // Algorithm adapted from Chapter 17 of "Graphics Programming Black Book" By
6 | // http://www.gamedev.net/page/resources/_/technical/graphics-programming-and
7 | // (See Listing 17.5)
8 | //
9 | // If the Switch Register is all 0's on startup,
10 | // a hard-coded "glider" test pattern is loaded into the grid.
11 | // Otherwise, the Switch Register value is used as a pseudo-random seed
12 | // to generate the starting pattern.
13 | ///
14 | //
15 | // Assembly-time Constants.
16 | //
17 | // Grid Size.
18 | //
19 | // Grid dimensions for emulator "Run PDP-8 Screen".
20 | //numRows=15d
21 | //numCols=77d
22 | //numCells=1155d
23 | // Grid dimensions for use with PDP-8 emulator debug memory display.
24 | numRows=12d
25 | numCols=8d
26 | numCells=96d
27 | // Grid dimensions to maximize use of VT-100 terminal in PDP-8/E Java Emulato
28 | //numRows=22d
29 | //numCols=80d
30 | //numCells=1760d // 22 rows by 80 cols. Word per cell implies 14 pages of 128
31 | //
32 | numColP1=numCols+1
33 | numColM1=numCols-1
34 | numCellM1=numCells-1
35 | //
36 | // ASCII Character Codes.
37 | //
38 | asciiEsc=27d // Escape
39 | asciiSpace=32d // Space (Blank)
40 | asciiCR=13d // Carriage Return
41 | asciiLF=10d // Line Feed
42 | //
43 | incrNbrCount=0100 // Increment neighbor count in high half word.
44 | decrNbrCount=-incrNbrCount // Decrement neighbor count in high half word.
45 | //
46 | ///
47 | //
48 | // Page 0 is always directly-addressable.
49 | //
50 | // Auto-Index "Register" addresses.
51 | //
52 | air0=10
53 | air1=11
54 | air2=12
55 | air3=13
56 | air4=14
57 | air5=15
58 | air6=16
59 | air7=17
60 | //
61 | ///
62 | //
63 | *0020
64 | //
65 | // Bit Masks.
66 | //
67 | 0020/0017 mNbrCount, 0017 // Right 4 bits to store 0 thru 8 as Neighbor Count.
68 | 0021/0020 mCellOnLo, 0020 // Cell marked "on" in lo half (5th bit from right).
69 | 0022/2000 mCellOnHi, 2000 // Cell marked "on" in hi half.
70 | 0023/5777 mCellOffHi, 5777 // Clear "on" bit in hi half.
71 | 0024/0077 mLoHalf, 0077 // Right 6 bits.
72 | 0025/7700 mHiHalf, 7700 // Left 6 bits.
73 | 0026/0017 mRandBits, 0017 // Right 4 bits for random # (0 to 15).
74 | 0027/0007 mLoOctalDigit, 0007 // Right-most octal digit.
75 | //
76 | // Memory Constants.
77 | //
78 | 0030/7777 cMinusOne, -1
79 | 0031/7776 cMinusTwo, -2
80 | 0032/7775 cMinusThree, -3
81 | 0033/0010 cNumCols, numCols
82 | 0034/0140 cNumCells, numCells
83 | //
84 | // String and Character Constants.
85 | //
86 | 0035/0035 szClrScreen, . // VT-100 Clear Screen.
87 | 0036/0033 asciiEsc;'[2J'
88 | 0037/0133
89 | 0040/0062
90 | 0041/0112
91 | 0042/0000 0
92 | 0043/0043 szCrsrHome, . // VT-100 Cursor Home.
93 | 0044/0033 asciiEsc;'[0;0H'
94 | 0045/0133
95 | 0046/0060
96 | 0047/0073
97 | 0050/0060
98 | 0051/0110
99 | 0052/0000 0
100 | 0053/0053 szSeed, . // Random seed display message.
101 | 0054/0040 ' Seed: '
102 | 0055/0040
103 | 0056/0123
104 | 0057/0145
105 | 0060/0145
106 | 0061/0144
107 | 0062/0072
108 | 0063/0040
109 | 0064/0000 0
110 | 0065/0065 szGeneration, . // Generation display message.
111 | 0066/0040 ' Generation: '
112 | 0067/0040
113 | 0070/0107
114 | 0071/0145
115 | 0072/0156
116 | 0073/0145
117 | 0074/0162
118 | 0075/0141
119 | 0076/0164
120 | 0077/0151
121 | 0100/0157
122 | 0101/0156
123 | 0102/0072
124 | 0103/0040
125 | 0104/0000 0
126 | 0105/0105 szNewLine, . // Carriage-Return/Line-Feed combination.
127 | 0106/0015 asciiCR;asciiLF
128 | 0107/0012
129 | 0110/0000 0
130 | 0111/0040 charSpace, asciiSpace
131 | 0112/0060 charZero, '0'
132 | 0113/0052 charStar, '*'
133 | //
134 | // Neighbor Cell Offsets.
135 | //
136 | 0114/0114 cellOffsets, . // Base address to load into auto-index register.
137 | 0115/7767 coNW, -numColP1
138 | 0116/7770 coN, -numCols
139 | 0117/7771 coNE, -numColM1
140 | 0120/0001 coE, +1
141 | 0121/0011 coSE, numColP1
142 | 0122/0010 coS, numCols
143 | 0123/0007 coSW, numColM1
144 | 0124/7777 coW, -1
145 | 0125/0000 coSelf, 0 // Terminate loop.
146 | //
147 | // Array Pointers.
148 | //
149 | 0126/2007 pNWWrapCell, NWWrapCell // Extra "northwest" wrap cell.
150 | 0127/2007 pTopWrapRow, CellBuffer-1 // Preceding address for auto-indexing to top wrap
151 | 0130/2017 pGridCells, CellBuffer+numColM1 // Preceding address for actual cell grid (af
152 | 0131/2157 pBotWrapRow, CellBuffer+numCols+numCellM1 // Preceding address for bottom wra
153 | 0132/2170 pSEWrapCell, CellBuffer+numCols+numCells+numCols // Extra "southeast" wrap ce
154 | //
155 | 0133/2147 pNWPairCell, NWWrapCell+numCells // Pair for "northwest" wrap cell (just befo
156 | 0134/2147 pTopPairRow, CellBuffer+numCellM1 // Preceding address for pair for top wrap
157 | 0135/2017 pBotPairRow, CellBuffer+numColM1 // Preceding address for pair for bottom wra
158 | 0136/2030 pSEPairCell, CellBuffer+numCols+numCols // Pair for "southwest" wrap cell (ju
159 | //
160 | // Subroutine Pointers.
161 | //
162 | 0137/1200 SkipIfChar, srSkipIfChar
163 | 0140/1206 GetChar, srGetChar
164 | 0141/1213 PutChar, srPutChar
165 | 0142/1221 PutString, srPutString
166 | 0143/1230 PutNewLine, srPutNewLine
167 | 0144/1235 PutOctal, srPutOctal
168 | 0145/1302 SetRand, srSetRand
169 | 0146/1305 GetRand, srGetRand
170 | 0147/1320 EmuMUY, srEmuMUY
171 | 0150/0405 ClrGeneration, srClrGeneration
172 | 0151/0400 LoadSeed, srLoadSeed
173 | 0152/0413 ShowSeedAndGeneration, srShowSeedAndGeneration
174 | 0153/0433 ClrWrap, srClrWrap
175 | 0154/0454 ClrGrid, srClrGrid
176 | 0155/0535 RandomizeGrid, srRandomizeGrid
177 | 0156/0467 InitGrid, srInitGrid
178 | 0157/0600 ShowGrid, srShowGrid
179 | 0160/0644 ProcessGeneration, srProcessGeneration
180 | 0161/1045 CloneGrid, srCloneGrid
181 | 0162/1066 CloneCell, srCloneCell
182 | 0163/0723 CellBorn, srCellBorn
183 | 0164/0737 CellDied, srCellDied
184 | 0165/0751 CellNeighbors, srCellNeighbors
185 | 0166/1000 ProcWrap, srProcWrap
186 | //
187 | // Global Variables.
188 | //
189 | 0167/0000 gGeneration, 0
190 | 0170/0000 gSeed, 0
191 | //
192 | ///
193 | //
194 | // Main Code Page.
195 | //
196 | *0200
197 | 0200/7300 Main, cla cll // Clear AC and Link.
198 | 0201/6046 tls / Wake Up Printer (terminal display)
199 | 0202/4551 jms i LoadSeed
200 | 0203/4550 jms i ClrGeneration
201 | 0204/4552 jms i ShowSeedAndGeneration
202 | 0205/4553 jms i ClrWrap
203 | 0206/4554 jms i ClrGrid
204 | 0207/4556 jms i InitGrid
205 | 0210/4561 jms i CloneGrid
206 | 0211/4557 jms i ShowGrid
207 | 0212/4537 jms i SkipIfChar
208 | 0213/5215 jmp MainLoop
209 | 0214/5222 jmp MainPause
210 | 0215/4560 MainLoop, jms i ProcessGeneration
211 | 0216/4561 jms i CloneGrid
212 | 0217/4557 jms i ShowGrid
213 | 0220/4537 jms i SkipIfChar
214 | 0221/5215 jmp MainLoop
215 | 0222/7402 MainPause, hlt // Halt.
216 | 0223/5215 jmp MainLoop // Resume loop if user continues via front-panel.
217 | 0224/7300 End, cla cll // Clear AC and Link.
218 | 0225/7402 hlt // Halt.
219 | 0226/5200 jmp Main // Restart if user continues via front panel.
220 | //
221 | // Application Subroutines.
222 | //
223 | *0400
224 | //
225 | // Subroutine: Load Seed from Switch Register.
226 | // Parameter: Switch Register.
227 | // Updates: Global value gSeed.
228 | //
229 | 0400/0000 srLoadSeed, 0
230 | 0401/7300 cla cll // Clear AC and Link.
231 | 0402/7404 osr // Or the Switch Register bits into AC.
232 | 0403/3170 dca gSeed // Save random seed.
233 | 0404/5600 jmp i srLoadSeed // Return
234 | //
235 | // Subroutine: Clear Generation.
236 | // No parameter.
237 | // Updates: Global value gGeneration.
238 | //
239 | 0405/0000 srClrGeneration, 0
240 | 0406/7300 cla cll
241 | 0407/3167 dca gGeneration
242 | 0410/1035 tad szClrScrn
243 | 0411/4542 jms i PutString
244 | 0412/5605 jmp i srClrGeneration // Return
245 | //
246 | // Subroutine: Show Seed.
247 | // Global value: gSeed.
248 | // No parameter.
249 | //
250 | 0413/0000 srShowSeedAndGeneration, 0
251 | 0414/7300 cla cll
252 | 0415/1043 tad szCrsrHome
253 | 0416/4542 jms i PutString
254 | 0417/1053 tad szSeed
255 | 0420/4542 jms i PutString
256 | 0421/7300 cla cll
257 | 0422/1170 tad gSeed
258 | 0423/4544 jms i PutOctal
259 | 0424/1065 tad szGeneration
260 | 0425/4542 jms i PutString
261 | 0426/7300 cla cll
262 | 0427/1167 tad gGeneration
263 | 0430/4544 jms i PutOctal
264 | 0431/4543 jms i PutNewLine
265 | 0432/5613 jmp i srShowSeedAndGeneration // Return.
266 | //
267 | // Subroutine: Clear Wrap rows and cells.
268 | // No parameter.
269 | // Registers: air1 air2
270 | //
271 | 0433/0000 srClrWrap, 0
272 | 0434/7300 cla cll
273 | 0435/3526 dca i pNWWrapCell // Clear corner wrap cells.
274 | 0436/3532 dca i pSEWrapCell
275 | 0437/1033 tad cNumCols // Clear top and bottom wrap rows.
276 | 0440/7041 cia // Negate.
277 | 0441/3253 dca CWLoopCount
278 | 0442/1127 tad pTopWrapRow // Load address of top wrap row.
279 | 0443/3011 dca air1 // Set 1st index register to loop thru top wrap row.
280 | 0444/1131 tad pBotWrapRow // Load address of bottom wrap row.
281 | 0445/3012 dca air2 // Set 2nd index register to loop thru bottom wrap row.
282 | 0446/3411 CWWrapLoop, dca i air1 // Clear indirectly-indexed cells.
283 | 0447/3412 dca i air2
284 | 0450/2253 isz CWLoopCount
285 | 0451/5246 jmp CWWrapLoop // Non-zero counter, keep looping.
286 | 0452/5633 jmp i srClrWrap // Else, done looping so return.
287 | 0453/0000 CWLoopCount, 0
288 | //
289 | // Subroutine: Clear Grid cells.
290 | // No parameter.
291 | // Registers: air0
292 | //
293 | 0454/3266 srClrGrid, dca CGLoopCount
294 | 0455/1034 tad cNumCells
295 | 0456/7041 cia // Negate
296 | 0457/3266 dca CGLoopCount
297 | 0460/1130 tad pGridCells // Load address of grid cells.
298 | 0461/3010 dca air0 // Set index register to loop thru grid cell array.
299 | 0462/3410 CGGridLoop, dca i air0 // Clear next grid cell.
300 | 0463/2266 isz CGLoopCount
301 | 0464/5262 jmp CGGridLoop // Non-zero counter, keep looping.
302 | 0465/5654 jmp i srClrGrid // Else, done looping so return.
303 | 0466/0000 CGLoopCount, 0
304 | //
305 | // Subroutine: Initialize Grid cells to a predetermined pattern.
306 | // No parameter.
307 | // Register: air0
308 | //
309 | 0467/0000 srInitGrid, 0
310 | 0470/7300 cla cll
311 | 0471/1170 tad gSeed // Load random seed global value into AC.
312 | 0472/7450 sna // Skip if non-zero AC.
313 | 0473/5277 jmp IGFixedPattern // Else, zero means use fixed pattern.
314 | 0474/4545 jms i SetRand // Set the value as the pseudo-random seed.
315 | 0475/4555 jms i RandomizeGrid // Use the random pattern generator.
316 | 0476/5667 jmp i srInitGrid // And return.
317 | 0477/1321 IGFixedPattern, tad szIGPattern // Load pattern preceding address.
318 | 0500/3010 dca air0 // And save in auto-indexing register.
319 | 0501/1033 tad cNumCols // Load # columns,
320 | 0502/3310 dca IGMultiplier // And save as multiplier parameter.
321 | 0503/1410 IGLoop, tad i air0 // Get next row offset (1-based).
322 | 0504/7450 sna // Skip if non-zero.
323 | 0505/5315 jmp IGFinish // Else, finish up if AC = 0.
324 | 0506/1030 tad cMinusOne // Subtract 1 to make it 0-based.
325 | 0507/4547 jms i EmuMUY // Multiply by column count.
326 | 0510/0000 IGMultipler, 0 // Self-modified parameter value.
327 | 0511/1410 tad i air0 // Add in column offset (1-based).
328 | 0512/1130 tad pGridCells // Add in grid base preceding address.
329 | 0513/4563 jms i CellBorn // Process new cell birth.
330 | 0514/5303 jmp IGLoop // And loop to next cell pattern.
331 | 0515/4566 IGFinish, jms i ProcWrap // Process wrap row neighbor counts.
332 | 0516/4553 jms i ClrWrap // Clear wrap rows for next iteration.
333 | 0517/5667 jmp i srInitGrid // Return.
334 | 0520/0000 IGCurrAddr, 0
335 | 0521/0521 szIGPattern, . // Null-terminated row/col offset list.
336 | 0522/0001 1;2 // Glider
337 | 0523/0002
338 | 0524/0002 2;3
339 | 0525/0003
340 | 0526/0003 3;1;3;2;3;3
341 | 0527/0001
342 | 0530/0003
343 | 0531/0002
344 | 0532/0003
345 | 0533/0003
346 | 0534/0000 0 // Null-terminator.
347 | //
348 | // Subroutine: Randomize Grid cells.
349 | // No parameter.
350 | //
351 | 0535/0000 srRandomizeGrid, 0
352 | 0536/7300 cla cll
353 | 0537/1130 tad pGridCells
354 | 0540/3365 dca RGCurrCell
355 | 0541/1130 tad pGridCells
356 | 0542/1034 tad cNumCells // Compute last cell pointer for grid.
357 | 0543/3366 dca RGLastCell
358 | 0544/4546 RGLoop, jms i GetRand // Get a random integer.
359 | 0545/0026 and mRandBits // Only keep 6 bits (0 to n-1).
360 | 0546/7001 iac // Add 1 (1 to n).
361 | 0547/1365 tad RGCurrCell // Add random offset to cell pointer.
362 | 0550/3365 dca RGCurrCell
363 | 0551/1365 tad RGCurrCell // Reload and negate current cell pointer.
364 | 0552/7041 cia
365 | 0553/1366 tad RGLastCell // Subtract from last cell pointer.
366 | 0554/7510 spa // Skip if AC >= 0
367 | 0555/5362 jmp RGFinish // Else, finish up if negative.
368 | 0556/7300 cla cll
369 | 0557/1365 tad RGCurrCell // Load address of current cell into AC.
370 | 0560/4563 jms i CellBorn // Process new cell birth.
371 | 0561/5344 jmp RGLoop
372 | 0562/4566 RGFinish, jms i ProcWrap // Process wrap row neighbor counts.
373 | 0563/4553 jms i ClrWrap // Clear wrap rows for next iteration.
374 | 0564/5735 jmp i srRandomizeGrid // Return.
375 | 0565/0000 RGCurrCell, 0
376 | 0566/0000 RGLastCell, 0
377 | //
378 | *0600
379 | //
380 | // Subroutine: Show Grid cells.
381 | // No parameter.
382 | // Registers: air0
383 | //
384 | 0600/0000 srShowGrid, 0
385 | 0601/7300 cla cll
386 | 0602/1130 tad pGridCells // Load address of grid array.
387 | 0603/3010 dca air0 // Store pointer in auto-index register.
388 | 0604/1033 tad cNumCols
389 | 0605/7041 cia
390 | 0606/3242 dca SGMColCount // Store minus rows per cell count.
391 | 0607/1242 tad SGMColCount
392 | 0610/3243 dca SGColCount // Copy to actual column cell loop counter.
393 | 0611/1034 tad cNumCells
394 | 0612/7041 cia
395 | 0613/3241 dca SGLoopCount // Store negative cell count.
396 | 0614/7300 SGLoop, cla cll
397 | 0615/1410 tad i air0 // Loop thru each grid cell.
398 | 0616/0021 and mCellOnLo // Mask just "on" bit in lo half (current state).
399 | 0617/7440 sza // Skip if zero (treat as dead).
400 | 0620/5223 jmp SGLive // Else treat as live.
401 | 0621/1111 SGDead, tad charSpace
402 | 0622/5225 jmp SGPutChar
403 | 0623/7300 SGLive, cla cll
404 | 0624/1113 tad charStar
405 | 0625/4541 SGPutChar, jms i PutChar // Display space or star based on cell status.
406 | 0626/2241 isz SGLoopCount // See if we have processed all grid cells.
407 | 0627/5232 jmp SGRowCheck // If not, check if we've reached the end of a row.
408 | 0630/4543 jms i PutNewLine
409 | 0631/5600 jmp i srShowGrid // Return.
410 | 0632/2243 SGRowCheck, isz SGColCount // Increment columns-per-row counter
411 | 0633/5214 jmp SGLoop // Loop to next cell if non-zero.
412 | 0634/4543 jms i PutNewLine
413 | 0635/7300 cla cll
414 | 0636/1242 tad SGMColCount // Reset col-per-row counter.
415 | 0637/3243 dca SGColCount
416 | 0640/5214 jmp SGLoop // Then loop to next cell.
417 | 0641/0000 SGLoopCount, 0
418 | 0642/0000 SGMColCount, 0
419 | 0643/0000 SGColCount, 0
420 | //
421 | // Subroutine: Process Generation iteration.
422 | // No parameter.
423 | //
424 | 0644/0000 srProcessGeneration, 0
425 | 0645/2167 isz gGeneration // Increment generation # (Never will be zero, so will neve
426 | 0646/4552 jms i ShowSeedAndGeneration
427 | 0647/7300 cla cll
428 | 0650/1130 tad pGridCells
429 | 0651/3320 dca PGCurrAddr // Initialize current cell address.
430 | 0652/1034 tad cNumCells // Setup counter for processing each grid cell.
431 | 0653/7041 cia // Negate.
432 | 0654/3321 dca PGLoopCount
433 | 0655/2320 PGCellLoop, isz PGCurrAddr // Increment current grid cell address. (Will neve
434 | 0656/7300 cla cll
435 | 0657/1720 tad i PGCurrAddr // Load cell state into AC.
436 | 0660/7450 sna // Skip if AC non-zero.
437 | 0661/5313 jmp PGCheckLoop // Else, loop to next cell if current one is empty (also
438 | 0662/0020 and mNbrCount // Mask to check living neighbor count.
439 | 0663/3322 dca PGNbrCount // Save in local variable.
440 | 0664/1720 tad i PGCurrAddr // Re-load current cell state.
441 | 0665/0021 and mCellOnLo // Mask to check only current state "live" bit.
442 | 0666/7450 sna // Skip if AC non-zero (cell is "live").
443 | 0667/5301 jmp PGIsDead // Else process "dead" cell.
444 | 0670/7300 PGIsLive, cla cll
445 | 0671/1322 tad PGNbrCount // Get neighbor count.
446 | 0672/1031 tad cMinusTwo // Subtract 2.
447 | 0673/7510 spa // Skip if >= 0 (count >= 2).
448 | 0674/5310 jmp PGDied // Else cell just died due to under-population.
449 | 0675/1030 tad cMinusOne // Subtract 1 (Now at original count - 3).
450 | 0676/7540 sma sza // Skip if <= 0 (count <= 3).
451 | 0677/5310 jmp PGDied // Else cell just died due to overcrowding.
452 | 0700/5313 jmp PGCheckLoop // Otherwise, cell stays alive so process next cell.
453 | 0701/1322 PGIsDead, tad PGNbrCount // Get neighbor count. (AC was already zero).
454 | 0702/1032 tad cMinusThree // Subtract 3.
455 | 0703/7440 sza // Skip if = 0 (count = 3).
456 | 0704/5313 jmp PGCheckLoop // Else cell stays dead so process next cell.
457 | 0705/1320 PGBorn, tad PGCurrAddr // Load address of current cell. (AC was already zero.
458 | 0706/4563 jms i CellBorn // Create new cell.
459 | 0707/5313 jmp PGCheckLoop // Process next cell.
460 | 0710/7300 PGDied, cla cll
461 | 0711/1320 tad PGCurrAddr // Load address of current cell.
462 | 0712/4564 jms i CellDied // Kill cell, then process next cell.
463 | 0713/2321 PGCheckLoop, isz PGLoopCount
464 | 0714/5255 jmp PGCellLoop // Continue looping if non-zero.
465 | 0715/4566 PGFinish, jms i ProcWrap // Process wrapped neighbor counts.
466 | 0716/4553 jms i ClrWrap // Clear wrapped counts for next iteration.
467 | 0717/5644 jmp i srProcessGeneration // Return
468 | 0720/0000 PGCurrAddr, 0
469 | 0721/0000 PGLoopCount, 0
470 | 0722/0000 PGNbrCount, 0
471 | //
472 | // Subroutine: Cell Born.
473 | // Parameter: AC contains address of cell.
474 | //
475 | 0723/0000 srCellBorn, 0
476 | 0724/3336 dca CBCellAddr
477 | 0725/1736 tad i CBCellAddr // Load current cell state.
478 | 0726/7421 mql // Move to MQ register and clear AC.
479 | 0727/1022 tad mCellOnHi // Load mask to turn on "live" bit in hi half word.
480 | 0730/7501 mqa // "Or" in current cell state.
481 | 0731/3736 dca i CBCellAddr // And store back in cell grid position.
482 | 0732/1336 tad CBCellAddr // Reload grid cell address.
483 | 0733/4565 jms i CellNeighbors // Increment cell neighbor counts
484 | 0734/0100 incrNbrCount
485 | 0735/5723 jmp i srCellBorn // Return when done.
486 | 0736/0000 CBCellAddr, 0
487 | //
488 | // Subroutine: Cell Died.
489 | // Parameter: AC contains address of cell.
490 | //
491 | 0737/0000 srCellDied, 0
492 | 0740/3350 dca CDCellAddr
493 | 0741/1750 tad i CDCellAddr // Load current cell state.
494 | 0742/0023 and mCellOffHi // Clear "live" bit in hi half word.
495 | 0743/3750 dca i CDCellAddr // And store back in cell grid position.
496 | 0744/1350 tad CDCellAddr // Reload grid cell address.
497 | 0745/4565 jms i CellNeighbors // Increment cell neighbor counts
498 | 0746/7700 decrNbrCount
499 | 0747/5737 jmp i srCellDied // Return when done.
500 | 0750/0000 CDCellAddr, 0
501 | //
502 | // Subroutine: Cell Neighbor count update.
503 | // Parameter: AC contains address of cell, word after call contains increment
504 | // Registers: air7
505 | //
506 | 0751/0000 srCellNeighbors, 0
507 | 0752/3371 dca CNCellAddr
508 | 0753/1751 tad i srCellNeighbors // Load increment or decrement.
509 | 0754/3373 dca CNIncrDecr
510 | 0755/2351 isz srCellNeighbors // Prepare for skip-return.
511 | 0756/1114 tad cellOffsets // Load index register with address before neighbor cell of
512 | 0757/3017 dca air7
513 | 0760/1417 CNLoop, tad i air7 // Load offset to a neighbor cell.
514 | 0761/7450 sna // Skip if non-zero
515 | 0762/5751 jmp i srCellNeighbors // Else, return if offset was zero.
516 | 0763/1371 tad CNCellAddr // Load address of current cell.
517 | 0764/3372 dca CNNbrAddr // And save as neighbor cell address.
518 | 0765/1772 tad i CNNbrAddr // Load neighbor cell current state.
519 | 0766/1373 tad CNIncrDecr // And increment or decrement that cell's neighbor count (hi
520 | 0767/3772 dca i CNNbrAddr // And store back to grid cell.
521 | 0770/5360 jmp CNLoop
522 | 0771/0000 CNCellAddr, 0
523 | 0772/0000 CNNbrAddr, 0
524 | 0773/0000 CNIncrDecr, 0
525 | //
526 | *1000
527 | //
528 | // Subroutine: Process Wrap row and cell neighbor counts against intended cel
529 | // No parameter.
530 | // Registers: air1 air2
531 | //
532 | 1000/0000 srProcWrap, 0
533 | 1001/7300 cla cll
534 | 1002/1526 tad i pNWWrapCell // Load corner wrap cell.
535 | 1003/0025 and mHiHalf // Mask to only keep hi half.
536 | 1004/1533 tad i pNWPairCell // Add in grid pair cell state.
537 | 1005/3533 dca i pNWPairCell // And save back to grid.
538 | 1006/1532 tad i pSEWrapCell // Repeat for other corner wrap/pair.
539 | 1007/0025 and mHiHalf
540 | 1010/1536 tad i pSEPairCell
541 | 1011/3536 dca i pSEPairCell
542 | 1012/1127 tad pTopWrapRow // Load address of top wrap row.
543 | 1013/3011 dca air1 // Set 1st index register to loop thru top wrap row.
544 | 1014/1131 tad pBotWrapRow // Load address of bottom wrap row.
545 | 1015/3012 dca air2 // Set 2nd index register to loop thru bottom wrap row.
546 | 1016/1134 tad pTopPairRow // Load address of top pair row.
547 | 1017/3243 dca PWTopAddr // Save in local variable.
548 | 1020/1135 tad pBotPairRow // Load address of bottom pair row.
549 | 1021/3244 dca PWBotAddr // Save in local variable.
550 | 1022/1033 tad cNumCols // Setup counter for clearing top and bottom wrap rows.
551 | 1023/7041 cia // Negate.
552 | 1024/3242 dca PWLoopCount
553 | 1025/1411 PWWrapLoop, tad i air1 // Load wrapped top row neighbor count.
554 | 1026/0025 and mHiHalf // Mask to only keep hi half.
555 | 1027/2243 isz PWTopAddr // Increment top pair row cell address (will never skip).
556 | 1030/1643 tad i PWTopAddr // Add in top pair row cell state
557 | 1031/3643 dca i PWTopAddr // Store result back to grid cell.
558 | 1032/1412 tad i air2 // Load wrapped bottom row neighbor count.
559 | 1033/0025 and mHiHalf // Mask to only keep hi half.
560 | 1034/2244 isz PWBotAddr // Increment bottom pair row cell address (will never skip).
561 | 1035/1644 tad i PWBotAddr // Add in bottom pair row cell state.
562 | 1036/3644 dca i PWBotAddr // Store result back to grid cell.
563 | 1037/2242 isz PWLoopCount // Increment loop counter.
564 | 1040/5225 jmp PWWrapLoop // Non-zero counter, keep looping.
565 | 1041/5600 jmp i srProcWrap // Done looping, so return.
566 | 1042/0000 PWLoopCount, 0
567 | 1043/0000 PWTopAddr, 0
568 | 1044/0000 PWBotAddr, 0
569 | //
570 | // Subroutine: Clone Grid Cells from prior iteration state to current.
571 | // Parameters: None.
572 | // Registers: air1, air2
573 | //
574 | 1045/0000 srCloneGrid, 0
575 | 1046/7300 cla cll
576 | 1047/1130 tad pGridCells // Load address of grid array.
577 | 1050/3011 dca air1 // Store pointer in 1st auto-index register.
578 | 1051/1011 tad air1 // Copy to 2nd index register.
579 | 1052/3012 dca air2
580 | 1053/1034 tad cNumCells
581 | 1054/7041 cia
582 | 1055/3265 dca CGCLoopCount // Store negative cell count.
583 | 1056/1411 CGCLoop, tad i air1 // Loop thru each grid cell.
584 | 1057/7440 sza // Skip if zero.
585 | 1060/4562 jms i CloneCell // Copy hi half (prior state) to lo half (current state).
586 | 1061/3412 dca i air2 // Store cloned result back to grid cell.
587 | 1062/2265 isz CGCLoopCount // See if we have processed all grid cells.
588 | 1063/5256 jmp CGCLoop // If not, keep looping.
589 | 1064/5645 jmp i srCloneGrid // Return.
590 | 1065/0000 CGCLoopCount, 0
591 | //
592 | // Subroutine: Clone Cell State from prior iteration state to current.
593 | // Clone the left-half of the AC into the right-half.
594 | // Parameter: AC contains the cell contents to be cloned from the left (hi) h
595 | // Returns: Cloned result in AC.
596 | //
597 | 1066/0000 srCloneCell, 0
598 | 1067/0025 and mHiHalf // Mask to keep only left-half of AC
599 | 1070/7421 mql // Move AC to MQ and clear AC.
600 | 1071/7501 mqa // Copy MQ back to AC.
601 | 1072/7012 rtr // Rotate AC twice right.
602 | 1073/7012 rtr // 2 more bits.
603 | 1074/7012 rtr // Total of 6 bits rotation.
604 | 1075/7501 mqa // OR in original high-half.
605 | 1076/5666 jmp i srCloneCell // Return.
606 | //
607 | // Utility Subroutines.
608 | //
609 | *1200
610 | //
611 | // Subroutine: Skip If Character ready.
612 | // Check for keyboard character.
613 | // Skip-return if present, returning the character in the AC.
614 | // Else just return.
615 | //
616 | 1200/0000 srSkipIfChar, 0
617 | 1201/6031 ksf // Is Keyboard Flag Raised?
618 | 1202/5600 jmp i srSkipIfChar // No, just return.
619 | 1203/6036 krb // Yes - Read Character to AC.
620 | 1204/2200 isz srSkipIfChar // Increment return address.
621 | 1205/5600 jmp i srSkipIfChar // Return to "skip" address.
622 | //
623 | // Read a keyboard character. Wait until one appears.
624 | //
625 | 1206/0000 srGetChar, 0
626 | 1207/6031 ksf // Is Keyboard Flag Raised?
627 | 1210/5207 jmp .-1 // No - Loop! (Wait Loop)
628 | 1211/6036 krb // Yes - Read Character to AC.
629 | 1212/5606 jmp i srGetChar // Return.
630 | //
631 | // Subroutine: Put Character to display.
632 | // Parameter: AC contains character.
633 | //
634 | 1213/0000 srPutChar, 0
635 | 1214/6041 tsf // Is Printer Ready?
636 | 1215/5214 jmp .-1 // No - Loop! (Wait Loop)
637 | 1216/6046 tls // Yes - Print the character!
638 | 1217/7300 cla cll // Clear AC and Link
639 | 1220/5613 jmp i srPutChar // Return
640 | //
641 | // Subroutine: Put String to terminal.
642 | // Display a null-terminated string.
643 | // Parameter: AC contains address of word preceding null-terminated string to
644 | // Registers: air6
645 | //
646 | 1221/0000 srPutString, 0
647 | 1222/3016 dca air6 // Deposit address of string to auto-index register.
648 | 1223/1416 tad i air6 // Load character.
649 | 1224/7450 sna // Is it a null? - skip if non-zero.
650 | 1225/5621 jmp i srPutString / Yes - return if zero.
651 | 1226/4213 jms srPutChar / No - display character (subroutines on same page).
652 | 1227/5223 jmp .-4 / Get next character.
653 | //
654 | // Subroutine: Put New Line to terminal (Carriage-Return/Line-Feed combinatio
655 | // Parameters: None.
656 | //
657 | 1230/0000 srPutNewLine, 0
658 | 1231/7300 cla cll
659 | 1232/1105 tad szNewLine
660 | 1233/4542 jms i PutString
661 | 1234/5630 jmp i srPutNewLine
662 | //
663 | // Subroutine: Put Octal value to terminal.
664 | // Display a 4-digit octal value.
665 | // Parameter: AC contains the value to display.
666 | //
667 | 1235/0000 srPutOctal, 0
668 | 1236/7421 mql // Move AC to MQ and clear AC.
669 | 1237/7501 mqa // Copy MQ back to AC.
670 | 1240/0027 and mLoOctalDigit // Mask to keep only low octal digit.
671 | 1241/1112 tad charZero // Convert to display digit.
672 | 1242/3300 dca Octal0Digit
673 | 1243/7501 mqa // Copy MQ to AC.
674 | 1244/7012 rtr // Rotate right 2 bits.
675 | 1245/7010 rar // Rotate right 1 bit.
676 | 1246/7421 mql // Move AC to MQ and clear AC.
677 | 1247/7501 mqa // Copy MQ back to AC.
678 | 1250/0027 and mLoOctalDigit // Mask to keep only low octal digit.
679 | 1251/1112 tad charZero // Convert to display digit.
680 | 1252/3277 dca Octal1Digit
681 | 1253/7501 mqa // Copy MQ to AC.
682 | 1254/7012 rtr // Rotate right 2 bits.
683 | 1255/7010 rar // Rotate right 1 bit.
684 | 1256/7421 mql // Move AC to MQ and clear AC.
685 | 1257/7501 mqa // Copy MQ back to AC.
686 | 1260/0027 and mLoOctalDigit // Mask to keep only low octal digit.
687 | 1261/1112 tad charZero // Convert to display digit.
688 | 1262/3276 dca Octal2Digit
689 | 1263/7501 mqa // Copy MQ to AC.
690 | 1264/7012 rtr // Rotate right 2 bits.
691 | 1265/7010 rar // Rotate right 1 bit.
692 | 1266/0027 and mLoOctalDigit // Mask to keep only low octal digit.
693 | 1267/1112 tad charZero // Convert to display digit.
694 | 1270/3275 dca Octal3Digit
695 | 1271/1274 tad OctalDigits
696 | 1272/4542 jms i PutString
697 | 1273/5635 jmp i srPutOctal // Return.
698 | 1274/1274 OctalDigits, .
699 | 1275/0000 Octal3Digit, 0
700 | 1276/0000 Octal2Digit, 0
701 | 1277/0000 Octal1Digit, 0
702 | 1300/0000 Octal0Digit, 0
703 | 1301/0000 OctalNullTerminator, 0
704 | //
705 | //---------------------------------------------------------------------------
706 | //
707 | // The following srroutines are courtesy of:
708 | // https://www.grc.com/pdp-8/deepthought-sbc.htm
709 | //
710 | // Subroutine: Set Random number seed.
711 | // Parameter: AC contains seed value.
712 | //
713 | 1302/0000 srSetRand, 0
714 | 1303/3316 dca LastRand
715 | 1304/5702 jmp i srSetRand // Return.
716 | //
717 | // Subroutine: Get Random number.
718 | // This is the simplest way I know of to generate highly random
719 | // looking 12-bit values. It's a Linear Congruential Pseudo Random
720 | // Number Generator (LCPRNG). Each time it's called, it evaluates
721 | // the expression: NextRand = LastRand * 5545 + 541 (all octal)
722 | // No parameters.
723 | // Returns: Random number in AC.
724 | //
725 | 1305/0000 srGetRand, 0
726 | 1306/7300 CLA CLL
727 | 1307/1316 TAD LastRand // get the last PRNG value
728 | 1310/4547 JMS I EmuMUY // multiply by the following constant
729 | 1311/5545 5545 // 2917 base 10 - LCPRNG multiplicand
730 | 1312/1317 TAD cRandAdd // sum in our LCPRNG addend
731 | 1313/3316 DCA LastRand // save this for next time
732 | 1314/1360 TAD AccumHigh // return the HIGH 12-bits as our res
733 | 1315/5705 JMP I srGetRand // return the AC to the caller
734 | 1316/0000 LastRand, 0 // our previous random value
735 | 1317/0541 cRandAdd, 541 // 353 base 10
736 | //
737 | // Subroutine: Emulate Multiply instruction.
738 | // This is a full 12x12 multiply, needed because the emulated PDP-8
739 | // lacks the EAE "Extended Arithmetic Element" multiplier.
740 | // Parameters:
741 | // AC contains Multiplier.
742 | // The word after the call has Multiplicand.
743 | // Returns:
744 | // Least significant 12-bits in AC.
745 | // Most significant 12-bits in AccumHigh.
746 | //
747 | 1320/0000 srEmuMUY, 0
748 | 1321/3361 DCA Multiplier // save the multiplier for shifting
749 | 1322/1355 TAD cMinus12 // setup our -12 loop counter
750 | 1323/3356 DCA PhaseCount
751 | 1324/3357 DCA AccumLow // clear our 24-bit results accumulat
752 | 1325/3360 DCA AccumHigh
753 | 1326/1361 MultShift, TAD Multiplier // get a bit from the multiplier
754 | 1327/7104 CLL RAL // move the high-bit into LINK
755 | 1330/3361 DCA Multiplier // put the updated multiplier back
756 | 1331/7420 SNL // we do need to add-in the multiplic
757 | 1332/5340 JMP MultIterate // no multiplicand add-in
758 | 1333/1720 TAD I srEmuMUY // add the multiplicand into accumula
759 | 1334/1357 TAD AccumLow // this *may* overflow, clearing the
760 | 1335/3357 DCA AccumLow // either way, put the updated low 12
761 | 1336/7420 SNL // if LINK is still '1', no overflow
762 | 1337/2360 ISZ AccumHigh // bump the high-half if we carried o
763 | 1340/2356 MultIterate, ISZ PhaseCount // see whether we've done all 12 bits
764 | 1341/5346 JMP Shift24 // not done, so shift and iterate aga
765 | 1342/7300 CLL CLA // return the lower 12-bits in AC
766 | 1343/1357 TAD AccumLow
767 | 1344/2320 ISZ srEmuMUY // return to the instruction after mu
768 | 1345/5720 JMP I srEmuMUY
769 | 1346/1357 Shift24, TAD AccumLow // get the lower 12-bit half
770 | 1347/7104 CLL RAL // shift it left, high bit into LINK
771 | 1350/3357 DCA AccumLow // put back the new low half
772 | 1351/1360 TAD AccumHigh // get the upper 12-bit half
773 | 1352/7004 RAL // shift it left, LINK into low bit
774 | 1353/3360 DCA AccumHigh // put back the new high half
775 | 1354/5326 JMP MultShift
776 | 1355/7764 cMinus12, 7764
777 | 1356/0000 PhaseCount, 0 // our multiplier-shift counter
778 | 1357/0000 AccumLow, 0 // low 12-bits of 12x12 mult
779 | 1360/0000 AccumHigh, 0 // high 12-bits of 12x12 mult
780 | 1361/0000 Multiplier, 0 // temp used by multiplication
781 | //
782 | //---------------------------------------------------------------------------
783 | //
784 | // Cell Array Pages.
785 | //
786 | *2007 // Could be *2000, but *2007 aligns better in the PDP-8 emulator debug
787 | 2007/0000 NWWrapCell, 0 // Extra "northwest" wrap cell.
788 | 2010/0000 CellBuffer, 0 // Array of top wrap row, cell grid, bottom wrap row, and "sout
789 | //
790 | ///
791 | $Main
792 | $0200
793 |
794 | User Defined Symbol Table
795 |
796 | numRows 0014
797 | numCols 0010
798 | numCells0140
799 | numColP10011
800 | numColM10007
801 | numCellM0137
802 | asciiEsc0033
803 | asciiSpa0040
804 | asciiCR 0015
805 | asciiLF 0012
806 | incrNbrC0100
807 | decrNbrC7700
808 | air0 0010
809 | air1 0011
810 | air2 0012
811 | air3 0013
812 | air4 0014
813 | air5 0015
814 | air6 0016
815 | air7 0017
816 | mNbrCoun0020
817 | mCellOnL0021
818 | mCellOnH0022
819 | mCellOff0023
820 | mLoHalf 0024
821 | mHiHalf 0025
822 | mRandBit0026
823 | mLoOctal0027
824 | cMinusOn0030
825 | cMinusTw0031
826 | cMinusTh0032
827 | cNumCols0033
828 | cNumCell0034
829 | szClrScr0035
830 | szCrsrHo0043
831 | szSeed 0053
832 | szGenera0065
833 | szNewLin0105
834 | charSpac0111
835 | charZero0112
836 | charStar0113
837 | cellOffs0114
838 | coNW 0115
839 | coN 0116
840 | coNE 0117
841 | coE 0120
842 | coSE 0121
843 | coS 0122
844 | coSW 0123
845 | coW 0124
846 | coSelf 0125
847 | pNWWrapC0126
848 | pTopWrap0127
849 | pGridCel0130
850 | pBotWrap0131
851 | pSEWrapC0132
852 | pNWPairC0133
853 | pTopPair0134
854 | pBotPair0135
855 | pSEPairC0136
856 | SkipIfCh0137
857 | GetChar 0140
858 | PutChar 0141
859 | PutStrin0142
860 | PutNewLi0143
861 | PutOctal0144
862 | SetRand 0145
863 | GetRand 0146
864 | EmuMUY 0147
865 | ClrGener0150
866 | LoadSeed0151
867 | ShowSeed0152
868 | ClrWrap 0153
869 | ClrGrid 0154
870 | Randomiz0155
871 | InitGrid0156
872 | ShowGrid0157
873 | ProcessG0160
874 | CloneGri0161
875 | CloneCel0162
876 | CellBorn0163
877 | CellDied0164
878 | CellNeig0165
879 | ProcWrap0166
880 | gGenerat0167
881 | gSeed 0170
882 | Main 0200
883 | MainLoop0215
884 | MainPaus0222
885 | End 0224
886 | srLoadSe0400
887 | srClrGen0405
888 | srShowSe0413
889 | srClrWra0433
890 | CWWrapLo0446
891 | CWLoopCo0453
892 | srClrGri0454
893 | CGGridLo0462
894 | CGLoopCo0466
895 | srInitGr0467
896 | IGFixedP0477
897 | IGLoop 0503
898 | IGMultip0510
899 | IGFinish0515
900 | IGCurrAd0520
901 | szIGPatt0521
902 | srRandom0535
903 | RGLoop 0544
904 | RGFinish0562
905 | RGCurrCe0565
906 | RGLastCe0566
907 | srShowGr0600
908 | SGLoop 0614
909 | SGDead 0621
910 | SGLive 0623
911 | SGPutCha0625
912 | SGRowChe0632
913 | SGLoopCo0641
914 | SGMColCo0642
915 | SGColCou0643
916 | srProces0644
917 | PGCellLo0655
918 | PGIsLive0670
919 | PGIsDead0701
920 | PGBorn 0705
921 | PGDied 0710
922 | PGCheckL0713
923 | PGFinish0715
924 | PGCurrAd0720
925 | PGLoopCo0721
926 | PGNbrCou0722
927 | srCellBo0723
928 | CBCellAd0736
929 | srCellDi0737
930 | CDCellAd0750
931 | srCellNe0751
932 | CNLoop 0760
933 | CNCellAd0771
934 | CNNbrAdd0772
935 | CNIncrDe0773
936 | srProcWr1000
937 | PWWrapLo1025
938 | PWLoopCo1042
939 | PWTopAdd1043
940 | PWBotAdd1044
941 | srCloneG1045
942 | CGCLoop 1056
943 | CGCLoopC1065
944 | srCloneC1066
945 | srSkipIf1200
946 | srGetCha1206
947 | srPutCha1213
948 | srPutStr1221
949 | srPutNew1230
950 | srPutOct1235
951 | OctalDig1274
952 | Octal3Di1275
953 | Octal2Di1276
954 | Octal1Di1277
955 | Octal0Di1300
956 | OctalNul1301
957 | srSetRan1302
958 | srGetRan1305
959 | LastRand1316
960 | cRandAdd1317
961 | srEmuMUY1320
962 | MultShif1326
963 | MultIter1340
964 | Shift24 1346
965 | cMinus121355
966 | PhaseCou1356
967 | AccumLow1357
968 | AccumHig1360
969 | Multipli1361
970 | NWWrapCe2007
971 | CellBuff2010
972 |
--------------------------------------------------------------------------------
/SW/CONWAY.OBJ:
--------------------------------------------------------------------------------
1 | 0020/0017
2 | 0021/0020
3 | 0022/2000
4 | 0023/5777
5 | 0024/0077
6 | 0025/7700
7 | 0026/0017
8 | 0027/0007
9 | 0030/7777
10 | 0031/7776
11 | 0032/7775
12 | 0033/0115
13 | 0034/2203
14 | 0035/0035
15 | 0036/0033
16 | 0037/0133
17 | 0040/0062
18 | 0041/0112
19 | 0042/0000
20 | 0043/0043
21 | 0044/0033
22 | 0045/0133
23 | 0046/0060
24 | 0047/0073
25 | 0050/0060
26 | 0051/0110
27 | 0052/0000
28 | 0053/0053
29 | 0054/0123
30 | 0055/0145
31 | 0056/0145
32 | 0057/0144
33 | 0060/0072
34 | 0061/0040
35 | 0062/0000
36 | 0063/0063
37 | 0064/0040
38 | 0065/0040
39 | 0066/0107
40 | 0067/0145
41 | 0070/0156
42 | 0071/0145
43 | 0072/0162
44 | 0073/0141
45 | 0074/0164
46 | 0075/0151
47 | 0076/0157
48 | 0077/0156
49 | 0100/0072
50 | 0101/0040
51 | 0102/0000
52 | 0103/0103
53 | 0104/0015
54 | 0105/0012
55 | 0106/0000
56 | 0107/0040
57 | 0110/0060
58 | 0111/0052
59 | 0112/0112
60 | 0113/7662
61 | 0114/7663
62 | 0115/7664
63 | 0116/0001
64 | 0117/0116
65 | 0120/0115
66 | 0121/0114
67 | 0122/7777
68 | 0123/0000
69 | 0124/2007
70 | 0125/2007
71 | 0126/2124
72 | 0127/4327
73 | 0130/4445
74 | 0131/4212
75 | 0132/4212
76 | 0133/2124
77 | 0134/2242
78 | 0135/1200
79 | 0136/1206
80 | 0137/1213
81 | 0140/1221
82 | 0141/1230
83 | 0142/1235
84 | 0143/1302
85 | 0144/1305
86 | 0145/1320
87 | 0146/0405
88 | 0147/0400
89 | 0150/0413
90 | 0151/0433
91 | 0152/0454
92 | 0153/0535
93 | 0154/0467
94 | 0155/0600
95 | 0156/0644
96 | 0157/1045
97 | 0160/1066
98 | 0161/0723
99 | 0162/0737
100 | 0163/0751
101 | 0164/1000
102 | 0165/0000
103 | 0166/0000
104 | 0200/7300
105 | 0201/6046
106 | 0202/4547
107 | 0203/4546
108 | 0204/4550
109 | 0205/4551
110 | 0206/4552
111 | 0207/4554
112 | 0210/4557
113 | 0211/4555
114 | 0212/4556
115 | 0213/4557
116 | 0214/4555
117 | 0215/4535
118 | 0216/5212
119 | 0217/7402
120 | 0220/5212
121 | 0221/7300
122 | 0222/7402
123 | 0223/5200
124 | 0400/0000
125 | 0401/7300
126 | 0402/7404
127 | 0403/3166
128 | 0404/5600
129 | 0405/0000
130 | 0406/7300
131 | 0407/3165
132 | 0410/1035
133 | 0411/4540
134 | 0412/5605
135 | 0413/0000
136 | 0414/7300
137 | 0415/1043
138 | 0416/4540
139 | 0417/1053
140 | 0420/4540
141 | 0421/7300
142 | 0422/1166
143 | 0423/4542
144 | 0424/1063
145 | 0425/4540
146 | 0426/7300
147 | 0427/1165
148 | 0430/4542
149 | 0431/4541
150 | 0432/5613
151 | 0433/0000
152 | 0434/7300
153 | 0435/3524
154 | 0436/3530
155 | 0437/1033
156 | 0440/7041
157 | 0441/3253
158 | 0442/1125
159 | 0443/3011
160 | 0444/1127
161 | 0445/3012
162 | 0446/3411
163 | 0447/3412
164 | 0450/2253
165 | 0451/5246
166 | 0452/5633
167 | 0453/0000
168 | 0454/3266
169 | 0455/1034
170 | 0456/7041
171 | 0457/3266
172 | 0460/1126
173 | 0461/3010
174 | 0462/3410
175 | 0463/2266
176 | 0464/5262
177 | 0465/5654
178 | 0466/0000
179 | 0467/0000
180 | 0470/7300
181 | 0471/1166
182 | 0472/7450
183 | 0473/5277
184 | 0474/4543
185 | 0475/4553
186 | 0476/5667
187 | 0477/1321
188 | 0500/3010
189 | 0501/1033
190 | 0502/3310
191 | 0503/1410
192 | 0504/7450
193 | 0505/5315
194 | 0506/1030
195 | 0507/4545
196 | 0510/0000
197 | 0511/1410
198 | 0512/1126
199 | 0513/4561
200 | 0514/5303
201 | 0515/4564
202 | 0516/4551
203 | 0517/5667
204 | 0520/0000
205 | 0521/0521
206 | 0522/0001
207 | 0523/0002
208 | 0524/0002
209 | 0525/0003
210 | 0526/0003
211 | 0527/0001
212 | 0530/0003
213 | 0531/0002
214 | 0532/0003
215 | 0533/0003
216 | 0534/0000
217 | 0535/0000
218 | 0536/7300
219 | 0537/1126
220 | 0540/3365
221 | 0541/1126
222 | 0542/1034
223 | 0543/3366
224 | 0544/4544
225 | 0545/0026
226 | 0546/7001
227 | 0547/1365
228 | 0550/3365
229 | 0551/1365
230 | 0552/7041
231 | 0553/1366
232 | 0554/7510
233 | 0555/5362
234 | 0556/7300
235 | 0557/1365
236 | 0560/4561
237 | 0561/5344
238 | 0562/4564
239 | 0563/4551
240 | 0564/5735
241 | 0565/0000
242 | 0566/0000
243 | 0600/0000
244 | 0601/7300
245 | 0602/1126
246 | 0603/3010
247 | 0604/1033
248 | 0605/7041
249 | 0606/3242
250 | 0607/1242
251 | 0610/3243
252 | 0611/1034
253 | 0612/7041
254 | 0613/3241
255 | 0614/7300
256 | 0615/1410
257 | 0616/0021
258 | 0617/7440
259 | 0620/5223
260 | 0621/1107
261 | 0622/5225
262 | 0623/7300
263 | 0624/1111
264 | 0625/4537
265 | 0626/2241
266 | 0627/5232
267 | 0630/4541
268 | 0631/5600
269 | 0632/2243
270 | 0633/5214
271 | 0634/4541
272 | 0635/7300
273 | 0636/1242
274 | 0637/3243
275 | 0640/5214
276 | 0641/0000
277 | 0642/0000
278 | 0643/0000
279 | 0644/0000
280 | 0645/2165
281 | 0646/4550
282 | 0647/7300
283 | 0650/1126
284 | 0651/3320
285 | 0652/1034
286 | 0653/7041
287 | 0654/3321
288 | 0655/2320
289 | 0656/7300
290 | 0657/1720
291 | 0660/7450
292 | 0661/5313
293 | 0662/0020
294 | 0663/3322
295 | 0664/1720
296 | 0665/0021
297 | 0666/7450
298 | 0667/5301
299 | 0670/7300
300 | 0671/1322
301 | 0672/1031
302 | 0673/7510
303 | 0674/5310
304 | 0675/1030
305 | 0676/7540
306 | 0677/5310
307 | 0700/5313
308 | 0701/1322
309 | 0702/1032
310 | 0703/7440
311 | 0704/5313
312 | 0705/1320
313 | 0706/4561
314 | 0707/5313
315 | 0710/7300
316 | 0711/1320
317 | 0712/4562
318 | 0713/2321
319 | 0714/5255
320 | 0715/4564
321 | 0716/4551
322 | 0717/5644
323 | 0720/0000
324 | 0721/0000
325 | 0722/0000
326 | 0723/0000
327 | 0724/3336
328 | 0725/1736
329 | 0726/7421
330 | 0727/1022
331 | 0730/7501
332 | 0731/3736
333 | 0732/1336
334 | 0733/4563
335 | 0734/0100
336 | 0735/5723
337 | 0736/0000
338 | 0737/0000
339 | 0740/3350
340 | 0741/1750
341 | 0742/0023
342 | 0743/3750
343 | 0744/1350
344 | 0745/4563
345 | 0746/7700
346 | 0747/5737
347 | 0750/0000
348 | 0751/0000
349 | 0752/3371
350 | 0753/1751
351 | 0754/3373
352 | 0755/2351
353 | 0756/1112
354 | 0757/3017
355 | 0760/1417
356 | 0761/7450
357 | 0762/5751
358 | 0763/1371
359 | 0764/3372
360 | 0765/1772
361 | 0766/1373
362 | 0767/3772
363 | 0770/5360
364 | 0771/0000
365 | 0772/0000
366 | 0773/0000
367 | 1000/0000
368 | 1001/7300
369 | 1002/1524
370 | 1003/0025
371 | 1004/1531
372 | 1005/3531
373 | 1006/1530
374 | 1007/0025
375 | 1010/1534
376 | 1011/3534
377 | 1012/1125
378 | 1013/3011
379 | 1014/1127
380 | 1015/3012
381 | 1016/1132
382 | 1017/3243
383 | 1020/1133
384 | 1021/3244
385 | 1022/1033
386 | 1023/7041
387 | 1024/3242
388 | 1025/1411
389 | 1026/0025
390 | 1027/2243
391 | 1030/1643
392 | 1031/3643
393 | 1032/1412
394 | 1033/0025
395 | 1034/2244
396 | 1035/1644
397 | 1036/3644
398 | 1037/2242
399 | 1040/5225
400 | 1041/5600
401 | 1042/0000
402 | 1043/0000
403 | 1044/0000
404 | 1045/0000
405 | 1046/7300
406 | 1047/1126
407 | 1050/3011
408 | 1051/1011
409 | 1052/3012
410 | 1053/1034
411 | 1054/7041
412 | 1055/3265
413 | 1056/1411
414 | 1057/7440
415 | 1060/4560
416 | 1061/3412
417 | 1062/2265
418 | 1063/5256
419 | 1064/5645
420 | 1065/0000
421 | 1066/0000
422 | 1067/0025
423 | 1070/7421
424 | 1071/7501
425 | 1072/7012
426 | 1073/7012
427 | 1074/7012
428 | 1075/7501
429 | 1076/5666
430 | 1200/0000
431 | 1201/6031
432 | 1202/5600
433 | 1203/6036
434 | 1204/2200
435 | 1205/5600
436 | 1206/0000
437 | 1207/6031
438 | 1210/5207
439 | 1211/6036
440 | 1212/5606
441 | 1213/0000
442 | 1214/6041
443 | 1215/5214
444 | 1216/6046
445 | 1217/7300
446 | 1220/5613
447 | 1221/0000
448 | 1222/3016
449 | 1223/1416
450 | 1224/7450
451 | 1225/5621
452 | 1226/4213
453 | 1227/5223
454 | 1230/0000
455 | 1231/7300
456 | 1232/1103
457 | 1233/4540
458 | 1234/5630
459 | 1235/0000
460 | 1236/7421
461 | 1237/7501
462 | 1240/0027
463 | 1241/1110
464 | 1242/3300
465 | 1243/7501
466 | 1244/7012
467 | 1245/7010
468 | 1246/7421
469 | 1247/7501
470 | 1250/0027
471 | 1251/1110
472 | 1252/3277
473 | 1253/7501
474 | 1254/7012
475 | 1255/7010
476 | 1256/7421
477 | 1257/7501
478 | 1260/0027
479 | 1261/1110
480 | 1262/3276
481 | 1263/7501
482 | 1264/7012
483 | 1265/7010
484 | 1266/0027
485 | 1267/1110
486 | 1270/3275
487 | 1271/1274
488 | 1272/4540
489 | 1273/5635
490 | 1274/1274
491 | 1275/0000
492 | 1276/0000
493 | 1277/0000
494 | 1300/0000
495 | 1301/0000
496 | 1302/0000
497 | 1303/3316
498 | 1304/5702
499 | 1305/0000
500 | 1306/7300
501 | 1307/1316
502 | 1310/4545
503 | 1311/5545
504 | 1312/1317
505 | 1313/3316
506 | 1314/1360
507 | 1315/5705
508 | 1316/0000
509 | 1317/0541
510 | 1320/0000
511 | 1321/3361
512 | 1322/1355
513 | 1323/3356
514 | 1324/3357
515 | 1325/3360
516 | 1326/1361
517 | 1327/7104
518 | 1330/3361
519 | 1331/7420
520 | 1332/5340
521 | 1333/1720
522 | 1334/1357
523 | 1335/3357
524 | 1336/7420
525 | 1337/2360
526 | 1340/2356
527 | 1341/5346
528 | 1342/7300
529 | 1343/1357
530 | 1344/2320
531 | 1345/5720
532 | 1346/1357
533 | 1347/7104
534 | 1350/3357
535 | 1351/1360
536 | 1352/7004
537 | 1353/3360
538 | 1354/5326
539 | 1355/7764
540 | 1356/0000
541 | 1357/0000
542 | 1360/0000
543 | 1361/0000
544 | 2007/0000
545 | 2010/0000
546 |
--------------------------------------------------------------------------------
/SW/CONWAY.RIM:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrutt/PDP8/2e6754233c7c765fcd5dc73a65ff75efb5b5ec38/SW/CONWAY.RIM
--------------------------------------------------------------------------------
/SW/Conway.pal:
--------------------------------------------------------------------------------
1 | ///
2 | //
3 | // Conway's Life for the PDP-8.
4 | //
5 | // Algorithm adapted from Chapter 17 of "Graphics Programming Black Book" By Michael Abrash.
6 | // http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/graphics-programming-black-book-r1698
7 | // (See Listing 17.5)
8 | //
9 | // If the Switch Register is all 0's on startup,
10 | // a hard-coded "glider" test pattern is loaded into the grid.
11 | // Otherwise, the Switch Register value is used as a pseudo-random seed
12 | // to generate the starting pattern.
13 | ///
14 | //
15 | // Assembly-time Constants.
16 | //
17 | // Grid Size.
18 | //
19 | // Grid dimensions for emulator "Run PDP-8 Screen".
20 | //numRows=15d
21 | //numCols=77d
22 | //numCells=1155d
23 | // Grid dimensions for use with PDP-8 emulator debug memory display.
24 | numRows=12d
25 | numCols=8d
26 | numCells=96d
27 | // Grid dimensions to maximize use of VT-100 terminal in PDP-8/E Java Emulator http://www.vandermark.ch/pdp8/index.php
28 | //numRows=22d
29 | //numCols=80d
30 | //numCells=1760d // 22 rows by 80 cols. Word per cell implies 14 pages of 128 words per page.
31 | //
32 | numColP1=numCols+1
33 | numColM1=numCols-1
34 | numCellM1=numCells-1
35 | //
36 | // ASCII Character Codes.
37 | //
38 | asciiEsc=27d // Escape
39 | asciiSpace=32d // Space (Blank)
40 | asciiCR=13d // Carriage Return
41 | asciiLF=10d // Line Feed
42 | //
43 | incrNbrCount=0100 // Increment neighbor count in high half word.
44 | decrNbrCount=-incrNbrCount // Decrement neighbor count in high half word.
45 | //
46 | ///
47 | //
48 | // Page 0 is always directly-addressable.
49 | //
50 | // Auto-Index "Register" addresses.
51 | //
52 | air0=10
53 | air1=11
54 | air2=12
55 | air3=13
56 | air4=14
57 | air5=15
58 | air6=16
59 | air7=17
60 | //
61 | ///
62 | //
63 | *0020
64 | //
65 | // Bit Masks.
66 | //
67 | mNbrCount, 0017 // Right 4 bits to store 0 thru 8 as Neighbor Count.
68 | mCellOnLo, 0020 // Cell marked "on" in lo half (5th bit from right).
69 | mCellOnHi, 2000 // Cell marked "on" in hi half.
70 | mCellOffHi, 5777 // Clear "on" bit in hi half.
71 | mLoHalf, 0077 // Right 6 bits.
72 | mHiHalf, 7700 // Left 6 bits.
73 | mRandBits, 0017 // Right 4 bits for random # (0 to 15).
74 | mLoOctalDigit, 0007 // Right-most octal digit.
75 | //
76 | // Memory Constants.
77 | //
78 | cMinusOne, -1
79 | cMinusTwo, -2
80 | cMinusThree, -3
81 | cNumCols, numCols
82 | cNumCells, numCells
83 | //
84 | // String and Character Constants.
85 | //
86 | szClrScreen, . // VT-100 Clear Screen.
87 | asciiEsc;'[2J'
88 | 0
89 | szCrsrHome, . // VT-100 Cursor Home.
90 | asciiEsc;'[0;0H'
91 | 0
92 | szSeed, . // Random seed display message.
93 | ' Seed: '
94 | 0
95 | szGeneration, . // Generation display message.
96 | ' Generation: '
97 | 0
98 | szNewLine, . // Carriage-Return/Line-Feed combination.
99 | asciiCR;asciiLF
100 | 0
101 | charSpace, asciiSpace
102 | charZero, '0'
103 | charStar, '*'
104 | //
105 | // Neighbor Cell Offsets.
106 | //
107 | cellOffsets, . // Base address to load into auto-index register.
108 | coNW, -numColP1
109 | coN, -numCols
110 | coNE, -numColM1
111 | coE, +1
112 | coSE, numColP1
113 | coS, numCols
114 | coSW, numColM1
115 | coW, -1
116 | coSelf, 0 // Terminate loop.
117 | //
118 | // Array Pointers.
119 | //
120 | pNWWrapCell, NWWrapCell // Extra "northwest" wrap cell.
121 | pTopWrapRow, CellBuffer-1 // Preceding address for auto-indexing to top wrap row.
122 | pGridCells, CellBuffer+numColM1 // Preceding address for actual cell grid (after top wrap row).
123 | pBotWrapRow, CellBuffer+numCols+numCellM1 // Preceding address for bottom wrap row (after top wrap row and grid).
124 | pSEWrapCell, CellBuffer+numCols+numCells+numCols // Extra "southeast" wrap cell (after top wrap row, cell grid, and bottom wrap row.)
125 | //
126 | pNWPairCell, NWWrapCell+numCells // Pair for "northwest" wrap cell (just before top pair row).
127 | pTopPairRow, CellBuffer+numCellM1 // Preceding address for pair for top wrap row (just after NW pair).
128 | pBotPairRow, CellBuffer+numColM1 // Preceding address for pair for bottom wrap row (same as grid).
129 | pSEPairCell, CellBuffer+numCols+numCols // Pair for "southwest" wrap cell (just after bottom pair row).
130 | //
131 | // Subroutine Pointers.
132 | //
133 | SkipIfChar, srSkipIfChar
134 | GetChar, srGetChar
135 | PutChar, srPutChar
136 | PutString, srPutString
137 | PutNewLine, srPutNewLine
138 | PutOctal, srPutOctal
139 | SetRand, srSetRand
140 | GetRand, srGetRand
141 | EmuMUY, srEmuMUY
142 | ClrGeneration, srClrGeneration
143 | LoadSeed, srLoadSeed
144 | ShowSeedAndGeneration, srShowSeedAndGeneration
145 | ClrWrap, srClrWrap
146 | ClrGrid, srClrGrid
147 | RandomizeGrid, srRandomizeGrid
148 | InitGrid, srInitGrid
149 | ShowGrid, srShowGrid
150 | ProcessGeneration, srProcessGeneration
151 | CloneGrid, srCloneGrid
152 | CloneCell, srCloneCell
153 | CellBorn, srCellBorn
154 | CellDied, srCellDied
155 | CellNeighbors, srCellNeighbors
156 | ProcWrap, srProcWrap
157 | //
158 | // Global Variables.
159 | //
160 | gGeneration, 0
161 | gSeed, 0
162 | //
163 | ///
164 | //
165 | // Main Code Page.
166 | //
167 | *0200
168 | Main, cla cll // Clear AC and Link.
169 | tls / Wake Up Printer (terminal display)
170 | jms i LoadSeed
171 | jms i ClrGeneration
172 | jms i ShowSeedAndGeneration
173 | jms i ClrWrap
174 | jms i ClrGrid
175 | jms i InitGrid
176 | jms i CloneGrid
177 | jms i ShowGrid
178 | jms i SkipIfChar
179 | jmp MainLoop
180 | jmp MainPause
181 | MainLoop, jms i ProcessGeneration
182 | jms i CloneGrid
183 | jms i ShowGrid
184 | jms i SkipIfChar
185 | jmp MainLoop
186 | MainPause, hlt // Halt.
187 | jmp MainLoop // Resume loop if user continues via front-panel.
188 |
189 | End, cla cll // Clear AC and Link.
190 | hlt // Halt.
191 | jmp Main // Restart if user continues via front panel.
192 | //
193 | // Application Subroutines.
194 | //
195 | *0400
196 | //
197 | // Subroutine: Load Seed from Switch Register.
198 | // Parameter: Switch Register.
199 | // Updates: Global value gSeed.
200 | //
201 | srLoadSeed, 0
202 | cla cll // Clear AC and Link.
203 | osr // Or the Switch Register bits into AC.
204 | dca gSeed // Save random seed.
205 | jmp i srLoadSeed // Return
206 | //
207 | // Subroutine: Clear Generation.
208 | // No parameter.
209 | // Updates: Global value gGeneration.
210 | //
211 | srClrGeneration, 0
212 | cla cll
213 | dca gGeneration
214 | tad szClrScrn
215 | jms i PutString
216 | jmp i srClrGeneration // Return
217 | //
218 | // Subroutine: Show Seed.
219 | // Global value: gSeed.
220 | // No parameter.
221 | //
222 | srShowSeedAndGeneration, 0
223 | cla cll
224 | tad szCrsrHome
225 | jms i PutString
226 | tad szSeed
227 | jms i PutString
228 | cla cll
229 | tad gSeed
230 | jms i PutOctal
231 | tad szGeneration
232 | jms i PutString
233 | cla cll
234 | tad gGeneration
235 | jms i PutOctal
236 | jms i PutNewLine
237 | jmp i srShowSeedAndGeneration // Return.
238 | //
239 | // Subroutine: Clear Wrap rows and cells.
240 | // No parameter.
241 | // Registers: air1 air2
242 | //
243 | srClrWrap, 0
244 | cla cll
245 | dca i pNWWrapCell // Clear corner wrap cells.
246 | dca i pSEWrapCell
247 | tad cNumCols // Clear top and bottom wrap rows.
248 | cia // Negate.
249 | dca CWLoopCount
250 | tad pTopWrapRow // Load address of top wrap row.
251 | dca air1 // Set 1st index register to loop thru top wrap row.
252 | tad pBotWrapRow // Load address of bottom wrap row.
253 | dca air2 // Set 2nd index register to loop thru bottom wrap row.
254 | CWWrapLoop, dca i air1 // Clear indirectly-indexed cells.
255 | dca i air2
256 | isz CWLoopCount
257 | jmp CWWrapLoop // Non-zero counter, keep looping.
258 | jmp i srClrWrap // Else, done looping so return.
259 | CWLoopCount, 0
260 | //
261 | // Subroutine: Clear Grid cells.
262 | // No parameter.
263 | // Registers: air0
264 | //
265 | srClrGrid, dca CGLoopCount
266 | tad cNumCells
267 | cia // Negate
268 | dca CGLoopCount
269 | tad pGridCells // Load address of grid cells.
270 | dca air0 // Set index register to loop thru grid cell array.
271 | CGGridLoop, dca i air0 // Clear next grid cell.
272 | isz CGLoopCount
273 | jmp CGGridLoop // Non-zero counter, keep looping.
274 | jmp i srClrGrid // Else, done looping so return.
275 | CGLoopCount, 0
276 | //
277 | // Subroutine: Initialize Grid cells to a predetermined pattern.
278 | // No parameter.
279 | // Register: air0
280 | //
281 | srInitGrid, 0
282 | cla cll
283 | tad gSeed // Load random seed global value into AC.
284 | sna // Skip if non-zero AC.
285 | jmp IGFixedPattern // Else, zero means use fixed pattern.
286 | jms i SetRand // Set the value as the pseudo-random seed.
287 | jms i RandomizeGrid // Use the random pattern generator.
288 | jmp i srInitGrid // And return.
289 | IGFixedPattern, tad szIGPattern // Load pattern preceding address.
290 | dca air0 // And save in auto-indexing register.
291 | tad cNumCols // Load # columns,
292 | dca IGMultiplier // And save as multiplier parameter.
293 | IGLoop, tad i air0 // Get next row offset (1-based).
294 | sna // Skip if non-zero.
295 | jmp IGFinish // Else, finish up if AC = 0.
296 | tad cMinusOne // Subtract 1 to make it 0-based.
297 | jms i EmuMUY // Multiply by column count.
298 | IGMultipler, 0 // Self-modified parameter value.
299 | tad i air0 // Add in column offset (1-based).
300 | tad pGridCells // Add in grid base preceding address.
301 | jms i CellBorn // Process new cell birth.
302 | jmp IGLoop // And loop to next cell pattern.
303 | IGFinish, jms i ProcWrap // Process wrap row neighbor counts.
304 | jms i ClrWrap // Clear wrap rows for next iteration.
305 | jmp i srInitGrid // Return.
306 | IGCurrAddr, 0
307 | szIGPattern, . // Null-terminated row/col offset list.
308 | 1;2 // Glider
309 | 2;3
310 | 3;1;3;2;3;3
311 | 0 // Null-terminator.
312 | //
313 | // Subroutine: Randomize Grid cells.
314 | // No parameter.
315 | //
316 | srRandomizeGrid, 0
317 | cla cll
318 | tad pGridCells
319 | dca RGCurrCell
320 | tad pGridCells
321 | tad cNumCells // Compute last cell pointer for grid.
322 | dca RGLastCell
323 | RGLoop, jms i GetRand // Get a random integer.
324 | and mRandBits // Only keep 6 bits (0 to n-1).
325 | iac // Add 1 (1 to n).
326 | tad RGCurrCell // Add random offset to cell pointer.
327 | dca RGCurrCell
328 | tad RGCurrCell // Reload and negate current cell pointer.
329 | cia
330 | tad RGLastCell // Subtract from last cell pointer.
331 | spa // Skip if AC >= 0
332 | jmp RGFinish // Else, finish up if negative.
333 | cla cll
334 | tad RGCurrCell // Load address of current cell into AC.
335 | jms i CellBorn // Process new cell birth.
336 | jmp RGLoop
337 | RGFinish, jms i ProcWrap // Process wrap row neighbor counts.
338 | jms i ClrWrap // Clear wrap rows for next iteration.
339 | jmp i srRandomizeGrid // Return.
340 | RGCurrCell, 0
341 | RGLastCell, 0
342 | //
343 | *0600
344 | //
345 | // Subroutine: Show Grid cells.
346 | // No parameter.
347 | // Registers: air0
348 | //
349 | srShowGrid, 0
350 | cla cll
351 | tad pGridCells // Load address of grid array.
352 | dca air0 // Store pointer in auto-index register.
353 | tad cNumCols
354 | cia
355 | dca SGMColCount // Store minus rows per cell count.
356 | tad SGMColCount
357 | dca SGColCount // Copy to actual column cell loop counter.
358 | tad cNumCells
359 | cia
360 | dca SGLoopCount // Store negative cell count.
361 | SGLoop, cla cll
362 | tad i air0 // Loop thru each grid cell.
363 | and mCellOnLo // Mask just "on" bit in lo half (current state).
364 | sza // Skip if zero (treat as dead).
365 | jmp SGLive // Else treat as live.
366 | SGDead, tad charSpace
367 | jmp SGPutChar
368 | SGLive, cla cll
369 | tad charStar
370 | SGPutChar, jms i PutChar // Display space or star based on cell status.
371 | isz SGLoopCount // See if we have processed all grid cells.
372 | jmp SGRowCheck // If not, check if we've reached the end of a row.
373 | jms i PutNewLine
374 | jmp i srShowGrid // Return.
375 | SGRowCheck, isz SGColCount // Increment columns-per-row counter
376 | jmp SGLoop // Loop to next cell if non-zero.
377 | jms i PutNewLine
378 | cla cll
379 | tad SGMColCount // Reset col-per-row counter.
380 | dca SGColCount
381 | jmp SGLoop // Then loop to next cell.
382 | SGLoopCount, 0
383 | SGMColCount, 0
384 | SGColCount, 0
385 | //
386 | // Subroutine: Process Generation iteration.
387 | // No parameter.
388 | //
389 | srProcessGeneration, 0
390 | isz gGeneration // Increment generation # (Never will be zero, so will never skip.)
391 | jms i ShowSeedAndGeneration
392 | cla cll
393 | tad pGridCells
394 | dca PGCurrAddr // Initialize current cell address.
395 | tad cNumCells // Setup counter for processing each grid cell.
396 | cia // Negate.
397 | dca PGLoopCount
398 | PGCellLoop, isz PGCurrAddr // Increment current grid cell address. (Will never skip.)
399 | cla cll
400 | tad i PGCurrAddr // Load cell state into AC.
401 | sna // Skip if AC non-zero.
402 | jmp PGCheckLoop // Else, loop to next cell if current one is empty (also means no neighbors).
403 | and mNbrCount // Mask to check living neighbor count.
404 | dca PGNbrCount // Save in local variable.
405 | tad i PGCurrAddr // Re-load current cell state.
406 | and mCellOnLo // Mask to check only current state "live" bit.
407 | sna // Skip if AC non-zero (cell is "live").
408 | jmp PGIsDead // Else process "dead" cell.
409 | PGIsLive, cla cll
410 | tad PGNbrCount // Get neighbor count.
411 | tad cMinusTwo // Subtract 2.
412 | spa // Skip if >= 0 (count >= 2).
413 | jmp PGDied // Else cell just died due to under-population.
414 | tad cMinusOne // Subtract 1 (Now at original count - 3).
415 | sma sza // Skip if <= 0 (count <= 3).
416 | jmp PGDied // Else cell just died due to overcrowding.
417 | jmp PGCheckLoop // Otherwise, cell stays alive so process next cell.
418 | PGIsDead, tad PGNbrCount // Get neighbor count. (AC was already zero).
419 | tad cMinusThree // Subtract 3.
420 | sza // Skip if = 0 (count = 3).
421 | jmp PGCheckLoop // Else cell stays dead so process next cell.
422 | PGBorn, tad PGCurrAddr // Load address of current cell. (AC was already zero.)
423 | jms i CellBorn // Create new cell.
424 | jmp PGCheckLoop // Process next cell.
425 | PGDied, cla cll
426 | tad PGCurrAddr // Load address of current cell.
427 | jms i CellDied // Kill cell, then process next cell.
428 | PGCheckLoop, isz PGLoopCount
429 | jmp PGCellLoop // Continue looping if non-zero.
430 | PGFinish, jms i ProcWrap // Process wrapped neighbor counts.
431 | jms i ClrWrap // Clear wrapped counts for next iteration.
432 | jmp i srProcessGeneration // Return
433 | PGCurrAddr, 0
434 | PGLoopCount, 0
435 | PGNbrCount, 0
436 | //
437 | // Subroutine: Cell Born.
438 | // Parameter: AC contains address of cell.
439 | //
440 | srCellBorn, 0
441 | dca CBCellAddr
442 | tad i CBCellAddr // Load current cell state.
443 | mql // Move to MQ register and clear AC.
444 | tad mCellOnHi // Load mask to turn on "live" bit in hi half word.
445 | mqa // "Or" in current cell state.
446 | dca i CBCellAddr // And store back in cell grid position.
447 | tad CBCellAddr // Reload grid cell address.
448 | jms i CellNeighbors // Increment cell neighbor counts
449 | incrNbrCount
450 | jmp i srCellBorn // Return when done.
451 | CBCellAddr, 0
452 | //
453 | // Subroutine: Cell Died.
454 | // Parameter: AC contains address of cell.
455 | //
456 | srCellDied, 0
457 | dca CDCellAddr
458 | tad i CDCellAddr // Load current cell state.
459 | and mCellOffHi // Clear "live" bit in hi half word.
460 | dca i CDCellAddr // And store back in cell grid position.
461 | tad CDCellAddr // Reload grid cell address.
462 | jms i CellNeighbors // Increment cell neighbor counts
463 | decrNbrCount
464 | jmp i srCellDied // Return when done.
465 | CDCellAddr, 0
466 | //
467 | // Subroutine: Cell Neighbor count update.
468 | // Parameter: AC contains address of cell, word after call contains increment or decrement constant.
469 | // Registers: air7
470 | //
471 | srCellNeighbors, 0
472 | dca CNCellAddr
473 | tad i srCellNeighbors // Load increment or decrement.
474 | dca CNIncrDecr
475 | isz srCellNeighbors // Prepare for skip-return.
476 | tad cellOffsets // Load index register with address before neighbor cell offsets list.
477 | dca air7
478 | CNLoop, tad i air7 // Load offset to a neighbor cell.
479 | sna // Skip if non-zero
480 | jmp i srCellNeighbors // Else, return if offset was zero.
481 | tad CNCellAddr // Load address of current cell.
482 | dca CNNbrAddr // And save as neighbor cell address.
483 | tad i CNNbrAddr // Load neighbor cell current state.
484 | tad CNIncrDecr // And increment or decrement that cell's neighbor count (hi half word).
485 | dca i CNNbrAddr // And store back to grid cell.
486 | jmp CNLoop
487 | CNCellAddr, 0
488 | CNNbrAddr, 0
489 | CNIncrDecr, 0
490 | //
491 | *1000
492 | //
493 | // Subroutine: Process Wrap row and cell neighbor counts against intended cells.
494 | // No parameter.
495 | // Registers: air1 air2
496 | //
497 | srProcWrap, 0
498 | cla cll
499 | tad i pNWWrapCell // Load corner wrap cell.
500 | and mHiHalf // Mask to only keep hi half.
501 | tad i pNWPairCell // Add in grid pair cell state.
502 | dca i pNWPairCell // And save back to grid.
503 | tad i pSEWrapCell // Repeat for other corner wrap/pair.
504 | and mHiHalf
505 | tad i pSEPairCell
506 | dca i pSEPairCell
507 | tad pTopWrapRow // Load address of top wrap row.
508 | dca air1 // Set 1st index register to loop thru top wrap row.
509 | tad pBotWrapRow // Load address of bottom wrap row.
510 | dca air2 // Set 2nd index register to loop thru bottom wrap row.
511 | tad pTopPairRow // Load address of top pair row.
512 | dca PWTopAddr // Save in local variable.
513 | tad pBotPairRow // Load address of bottom pair row.
514 | dca PWBotAddr // Save in local variable.
515 | tad cNumCols // Setup counter for clearing top and bottom wrap rows.
516 | cia // Negate.
517 | dca PWLoopCount
518 | PWWrapLoop, tad i air1 // Load wrapped top row neighbor count.
519 | and mHiHalf // Mask to only keep hi half.
520 | isz PWTopAddr // Increment top pair row cell address (will never skip).
521 | tad i PWTopAddr // Add in top pair row cell state
522 | dca i PWTopAddr // Store result back to grid cell.
523 | tad i air2 // Load wrapped bottom row neighbor count.
524 | and mHiHalf // Mask to only keep hi half.
525 | isz PWBotAddr // Increment bottom pair row cell address (will never skip).
526 | tad i PWBotAddr // Add in bottom pair row cell state.
527 | dca i PWBotAddr // Store result back to grid cell.
528 | isz PWLoopCount // Increment loop counter.
529 | jmp PWWrapLoop // Non-zero counter, keep looping.
530 | jmp i srProcWrap // Done looping, so return.
531 | PWLoopCount, 0
532 | PWTopAddr, 0
533 | PWBotAddr, 0
534 | //
535 | // Subroutine: Clone Grid Cells from prior iteration state to current.
536 | // Parameters: None.
537 | // Registers: air1, air2
538 | //
539 | srCloneGrid, 0
540 | cla cll
541 | tad pGridCells // Load address of grid array.
542 | dca air1 // Store pointer in 1st auto-index register.
543 | tad air1 // Copy to 2nd index register.
544 | dca air2
545 | tad cNumCells
546 | cia
547 | dca CGCLoopCount // Store negative cell count.
548 | CGCLoop, tad i air1 // Loop thru each grid cell.
549 | sza // Skip if zero.
550 | jms i CloneCell // Copy hi half (prior state) to lo half (current state).
551 | dca i air2 // Store cloned result back to grid cell.
552 | isz CGCLoopCount // See if we have processed all grid cells.
553 | jmp CGCLoop // If not, keep looping.
554 | jmp i srCloneGrid // Return.
555 | CGCLoopCount, 0
556 | //
557 | // Subroutine: Clone Cell State from prior iteration state to current.
558 | // Clone the left-half of the AC into the right-half.
559 | // Parameter: AC contains the cell contents to be cloned from the left (hi) half to the right (lo) half.
560 | // Returns: Cloned result in AC.
561 | //
562 | srCloneCell, 0
563 | and mHiHalf // Mask to keep only left-half of AC
564 | mql // Move AC to MQ and clear AC.
565 | mqa // Copy MQ back to AC.
566 | rtr // Rotate AC twice right.
567 | rtr // 2 more bits.
568 | rtr // Total of 6 bits rotation.
569 | mqa // OR in original high-half.
570 | jmp i srCloneCell // Return.
571 | //
572 | // Utility Subroutines.
573 | //
574 | *1200
575 | //
576 | // Subroutine: Skip If Character ready.
577 | // Check for keyboard character.
578 | // Skip-return if present, returning the character in the AC.
579 | // Else just return.
580 | //
581 | srSkipIfChar, 0
582 | ksf // Is Keyboard Flag Raised?
583 | jmp i srSkipIfChar // No, just return.
584 | krb // Yes - Read Character to AC.
585 | isz srSkipIfChar // Increment return address.
586 | jmp i srSkipIfChar // Return to "skip" address.
587 | //
588 | // Read a keyboard character. Wait until one appears.
589 | //
590 | srGetChar, 0
591 | ksf // Is Keyboard Flag Raised?
592 | jmp .-1 // No - Loop! (Wait Loop)
593 | krb // Yes - Read Character to AC.
594 | jmp i srGetChar // Return.
595 | //
596 | // Subroutine: Put Character to display.
597 | // Parameter: AC contains character.
598 | //
599 | srPutChar, 0
600 | tsf // Is Printer Ready?
601 | jmp .-1 // No - Loop! (Wait Loop)
602 | tls // Yes - Print the character!
603 | cla cll // Clear AC and Link
604 | jmp i srPutChar // Return
605 | //
606 | // Subroutine: Put String to terminal.
607 | // Display a null-terminated string.
608 | // Parameter: AC contains address of word preceding null-terminated string to display.
609 | // Registers: air6
610 | //
611 | srPutString, 0
612 | dca air6 // Deposit address of string to auto-index register.
613 | tad i air6 // Load character.
614 | sna // Is it a null? - skip if non-zero.
615 | jmp i srPutString / Yes - return if zero.
616 | jms srPutChar / No - display character (subroutines on same page).
617 | jmp .-4 / Get next character.
618 | //
619 | // Subroutine: Put New Line to terminal (Carriage-Return/Line-Feed combination).
620 | // Parameters: None.
621 | //
622 | srPutNewLine, 0
623 | cla cll
624 | tad szNewLine
625 | jms i PutString
626 | jmp i srPutNewLine
627 | //
628 | // Subroutine: Put Octal value to terminal.
629 | // Display a 4-digit octal value.
630 | // Parameter: AC contains the value to display.
631 | //
632 | srPutOctal, 0
633 | mql // Move AC to MQ and clear AC.
634 | mqa // Copy MQ back to AC.
635 | and mLoOctalDigit // Mask to keep only low octal digit.
636 | tad charZero // Convert to display digit.
637 | dca Octal0Digit
638 | mqa // Copy MQ to AC.
639 | rtr // Rotate right 2 bits.
640 | rar // Rotate right 1 bit.
641 | mql // Move AC to MQ and clear AC.
642 | mqa // Copy MQ back to AC.
643 | and mLoOctalDigit // Mask to keep only low octal digit.
644 | tad charZero // Convert to display digit.
645 | dca Octal1Digit
646 | mqa // Copy MQ to AC.
647 | rtr // Rotate right 2 bits.
648 | rar // Rotate right 1 bit.
649 | mql // Move AC to MQ and clear AC.
650 | mqa // Copy MQ back to AC.
651 | and mLoOctalDigit // Mask to keep only low octal digit.
652 | tad charZero // Convert to display digit.
653 | dca Octal2Digit
654 | mqa // Copy MQ to AC.
655 | rtr // Rotate right 2 bits.
656 | rar // Rotate right 1 bit.
657 | and mLoOctalDigit // Mask to keep only low octal digit.
658 | tad charZero // Convert to display digit.
659 | dca Octal3Digit
660 | tad OctalDigits
661 | jms i PutString
662 | jmp i srPutOctal // Return.
663 | OctalDigits, .
664 | Octal3Digit, 0
665 | Octal2Digit, 0
666 | Octal1Digit, 0
667 | Octal0Digit, 0
668 | OctalNullTerminator, 0
669 | //
670 | //------------------------------------------------------------------------------
671 | //
672 | // The following srroutines are courtesy of:
673 | // https://www.grc.com/pdp-8/deepthought-sbc.htm
674 | //
675 | // Subroutine: Set Random number seed.
676 | // Parameter: AC contains seed value.
677 | //
678 | srSetRand, 0
679 | dca LastRand
680 | jmp i srSetRand // Return.
681 | //
682 | // Subroutine: Get Random number.
683 | // This is the simplest way I know of to generate highly random
684 | // looking 12-bit values. It's a Linear Congruential Pseudo Random
685 | // Number Generator (LCPRNG). Each time it's called, it evaluates
686 | // the expression: NextRand = LastRand * 5545 + 541 (all octal)
687 | // No parameters.
688 | // Returns: Random number in AC.
689 | //
690 | srGetRand, 0
691 | CLA CLL
692 | TAD LastRand // get the last PRNG value
693 | JMS I EmuMUY // multiply by the following constant:
694 | 5545 // 2917 base 10 - LCPRNG multiplicand
695 | TAD cRandAdd // sum in our LCPRNG addend
696 | DCA LastRand // save this for next time
697 | TAD AccumHigh // return the HIGH 12-bits as our result
698 | JMP I srGetRand // return the AC to the caller
699 |
700 | LastRand, 0 // our previous random value
701 | cRandAdd, 541 // 353 base 10
702 | //
703 | // Subroutine: Emulate Multiply instruction.
704 | // This is a full 12x12 multiply, needed because the emulated PDP-8
705 | // lacks the EAE "Extended Arithmetic Element" multiplier.
706 | // Parameters:
707 | // AC contains Multiplier.
708 | // The word after the call has Multiplicand.
709 | // Returns:
710 | // Least significant 12-bits in AC.
711 | // Most significant 12-bits in AccumHigh.
712 | //
713 | srEmuMUY, 0
714 | DCA Multiplier // save the multiplier for shifting
715 | TAD cMinus12 // setup our -12 loop counter
716 | DCA PhaseCount
717 | DCA AccumLow // clear our 24-bit results accumulator
718 | DCA AccumHigh
719 |
720 | MultShift, TAD Multiplier // get a bit from the multiplier
721 | CLL RAL // move the high-bit into LINK
722 | DCA Multiplier // put the updated multiplier back
723 | SNL // we do need to add-in the multiplicand
724 | JMP MultIterate // no multiplicand add-in
725 |
726 | TAD I srEmuMUY // add the multiplicand into accumulator
727 | TAD AccumLow // this *may* overflow, clearing the LINK
728 | DCA AccumLow // either way, put the updated low 12 back
729 | SNL // if LINK is still '1', no overflow
730 | ISZ AccumHigh // bump the high-half if we carried out
731 |
732 | MultIterate, ISZ PhaseCount // see whether we've done all 12 bits
733 | JMP Shift24 // not done, so shift and iterate again
734 |
735 | CLL CLA // return the lower 12-bits in AC
736 | TAD AccumLow
737 | ISZ srEmuMUY // return to the instruction after multiplier
738 | JMP I srEmuMUY
739 |
740 | Shift24, TAD AccumLow // get the lower 12-bit half
741 | CLL RAL // shift it left, high bit into LINK
742 | DCA AccumLow // put back the new low half
743 | TAD AccumHigh // get the upper 12-bit half
744 | RAL // shift it left, LINK into low bit
745 | DCA AccumHigh // put back the new high half
746 | JMP MultShift
747 | cMinus12, 7764
748 | PhaseCount, 0 // our multiplier-shift counter
749 | AccumLow, 0 // low 12-bits of 12x12 mult
750 | AccumHigh, 0 // high 12-bits of 12x12 mult
751 | Multiplier, 0 // temp used by multiplication
752 | //
753 | //------------------------------------------------------------------------------
754 | //
755 | // Cell Array Pages.
756 | //
757 | *2007 // Could be *2000, but *2007 aligns better in the PDP-8 emulator debug display.
758 | NWWrapCell, 0 // Extra "northwest" wrap cell.
759 | CellBuffer, 0 // Array of top wrap row, cell grid, bottom wrap row, and "southeast" wrap cell.
760 | //
761 | ///
762 | $Main
763 |
--------------------------------------------------------------------------------
/SW/HELLO.LST:
--------------------------------------------------------------------------------
1 | //
2 | // Code Segment
3 | //
4 | *0200 // Code Segment starts at 0200 octal
5 | //
6 | 0200/7300 Main, cla cll // Clear AC and Link
7 | 0201/6046 tls // Wake Up Printer
8 | 0202/1300 tad Str // Get address of output string
9 | 0203/4353 jms PrtStr // Call PtrStr to Print it
10 | 0204/7402 End, hlt // Done!
11 | 0205/5200 jmp Main // Continue
12 | //
13 | // Data Segment
14 | //
15 | *0300 // Place String at 0300 octal
16 | //
17 | 0300/0300 Str, . // Str stores its own address
18 | 0301/0110 'Hello, World!';13d;10d;0 // string to be displayed - ends with null
19 | 0302/0145
20 | 0303/0154
21 | 0304/0154
22 | 0305/0157
23 | 0306/0054
24 | 0307/0040
25 | 0310/0127
26 | 0311/0157
27 | 0312/0162
28 | 0313/0154
29 | 0314/0144
30 | 0315/0041
31 | 0316/0015
32 | 0317/0012
33 | 0320/0000
34 | //
35 | // Subroutine Segment
36 | //
37 | *0340 // Subroutines begin at address 0340 octal
38 | //
39 | 0340/0000 GetChar, 0 // Return Address Stored Here
40 | 0341/6031 ksf // Is Keyboard Flag Raised ?
41 | 0342/5341 jmp .-1 // No - Loop! (Wait Loop)
42 | 0343/6036 krb // Yes - Read Character to AC
43 | 0344/5740 jmp i GetChar // Return
44 | //
45 | 0345/0000 Type, 0 // Return Address Stored Here
46 | 0346/6041 tsf // Is Printer Ready?
47 | 0347/5346 jmp .-1 // No - Loop! (Wait Loop)
48 | 0350/6046 tls // Yes - Print the character!
49 | 0351/7300 cla cll // Clear AC and Link
50 | 0352/5745 jmp i Type // Return
51 | //
52 | 0353/0000 PrtStr, 0 // Return Address Stored Here
53 | 0354/3010 dca 10 // Deposit address of string to auto-index register 10
54 | 0355/1410 tad i 10 // Load character
55 | 0356/7450 sna // Is it a null? - skip if non-zero
56 | 0357/5753 jmp i PrtStr // yes - return
57 | 0360/4345 jms Type // no - call Type to display
58 | 0361/5355 jmp .-4 // Get next character
59 | $Main
60 | $0200
61 |
62 | User Defined Symbol Table
63 |
64 | Main 0200
65 | End 0204
66 | Str 0300
67 | GetChar 0340
68 | Type 0345
69 | PrtStr 0353
70 |
--------------------------------------------------------------------------------
/SW/Hello.OBJ:
--------------------------------------------------------------------------------
1 | 0200/7300
2 | 0201/6046
3 | 0202/1300
4 | 0203/4353
5 | 0204/7402
6 | 0205/5200
7 | 0300/0300
8 | 0301/0110
9 | 0302/0145
10 | 0303/0154
11 | 0304/0154
12 | 0305/0157
13 | 0306/0054
14 | 0307/0040
15 | 0310/0127
16 | 0311/0157
17 | 0312/0162
18 | 0313/0154
19 | 0314/0144
20 | 0315/0041
21 | 0316/0015
22 | 0317/0012
23 | 0320/0000
24 | 0340/0000
25 | 0341/6031
26 | 0342/5341
27 | 0343/6036
28 | 0344/5740
29 | 0345/0000
30 | 0346/6041
31 | 0347/5346
32 | 0350/6046
33 | 0351/7300
34 | 0352/5745
35 | 0353/0000
36 | 0354/3010
37 | 0355/1410
38 | 0356/7450
39 | 0357/5753
40 | 0360/4345
41 | 0361/5355
42 |
--------------------------------------------------------------------------------
/SW/Hello.RIM:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrutt/PDP8/2e6754233c7c765fcd5dc73a65ff75efb5b5ec38/SW/Hello.RIM
--------------------------------------------------------------------------------
/SW/Hello.pal:
--------------------------------------------------------------------------------
1 | //
2 | // Code Segment
3 | //
4 | *0200 // Code Segment starts at 0200 octal
5 | //
6 | Main, cla cll // Clear AC and Link
7 | tls // Wake Up Printer
8 | tad Str // Get address of output string
9 | jms PrtStr // Call PtrStr to Print it
10 | End, hlt // Done!
11 | jmp Main // Continue
12 | //
13 | // Data Segment
14 | //
15 | *0300 // Place String at 0300 octal
16 | //
17 | Str, . // Str stores its own address
18 | 'Hello, World!';13d;10d;0 // string to be displayed - ends with null
19 | //
20 | // Subroutine Segment
21 | //
22 | *0340 // Subroutines begin at address 0340 octal
23 | //
24 | GetChar, 0 // Return Address Stored Here
25 | ksf // Is Keyboard Flag Raised ?
26 | jmp .-1 // No - Loop! (Wait Loop)
27 | krb // Yes - Read Character to AC
28 | jmp i GetChar // Return
29 | //
30 | Type, 0 // Return Address Stored Here
31 | tsf // Is Printer Ready?
32 | jmp .-1 // No - Loop! (Wait Loop)
33 | tls // Yes - Print the character!
34 | cla cll // Clear AC and Link
35 | jmp i Type // Return
36 | //
37 | PrtStr, 0 // Return Address Stored Here
38 | dca 10 // Deposit address of string to auto-index register 10
39 | tad i 10 // Load character
40 | sna // Is it a null? - skip if non-zero
41 | jmp i PrtStr // yes - return
42 | jms Type // no - call Type to display
43 | jmp .-4 // Get next character
44 | $Main
45 |
--------------------------------------------------------------------------------
/SW/KEYECHO.LST:
--------------------------------------------------------------------------------
1 | // This code segments reads and echoes characters from the keyboard.
2 | // It supports simple backspace correction of typed characters.
3 | // It ends when an escape character is detected.
4 | //
5 | //
6 | // Data Segment
7 | //
8 | *0100
9 | 0100/0000 HOLD, 0 // Location to hold current character
10 | 0101/0010 BS, 8d // ASCII Backspace
11 | 0102/0015 CR, 13d // ASCII Carriage Return
12 | 0103/0012 LF, 10d // ASCII Line Feed
13 | 0104/0033 Esc, 27d // ASCII Escape
14 | 0105/0040 Space, 32d // ASCII Space
15 | //
16 | // Subroutine pointers
17 | //
18 | 0106/0400 pGetChar, GetChar
19 | 0107/0405 pType, Type
20 | //
21 | // Code Segment
22 | //
23 | *200
24 | 0200/7300 Main, cla cll // Clear AC and Link
25 | 0201/6032 kcc // Clear Keyboard Flag
26 | 0202/6046 tls // Wake Up Printer!
27 | 0203/4506 Loop, jms i pGetChar // Get character
28 | 0204/3100 dca HOLD // Store it
29 | 0205/1100 tad HOLD // Compare with Esc by
30 | 0206/7041 cia // subtracting its value
31 | 0207/1104 tad Esc // from ASCII Escape
32 | 0210/7450 sna // If not equal then skip next instruction
33 | 0211/5250 jmp End // else goto end.
34 | 0212/7300 cla cll // Clear AC
35 | 0213/1100 tad HOLD // Compare with CR by
36 | 0214/7041 cia // subtracting its value
37 | 0215/1102 tad CR // from ASCII Carriage Return
38 | 0216/7450 sna // If not equal then skip next instruction
39 | 0217/5232 jmp CrLf // else goto line wrap.
40 | 0220/7300 cla cll // Clear AC
41 | 0221/1100 tad HOLD // Compare with BS by
42 | 0222/7041 cia // subtracting its value
43 | 0223/1101 tad BS // from ASCII Backspace
44 | 0224/7450 sna // If not equal then skip next instruction
45 | 0225/5240 jmp BkSp // else goto backspace.
46 | 0226/7300 cla cll // Echo character
47 | 0227/1100 tad HOLD // by putting it into AC
48 | 0230/4507 jms i pType // and calling Type subroutine.
49 | 0231/5203 jmp Loop // Get another character
50 | 0232/7300 CrLf, cla cll // CR detected - Clear AC and Link
51 | 0233/1102 tad CR // Get Carriage Return
52 | 0234/4507 jms i pType // Print it
53 | 0235/1103 tad LF // Get Line Feed
54 | 0236/4507 jms i pType // Print it
55 | 0237/5203 jmp Loop // Get another character
56 | 0240/7300 BkSp, cla cll // Backspace detected - Clear AC and Link
57 | 0241/1101 tad BS // Echo backspace to terminal to move cursor back
58 | 0242/4507 jms i pType
59 | 0243/1105 tad Space // Type a space to erase prior character
60 | 0244/4507 jms i pType
61 | 0245/1101 tad BS // Backspace again to prepare for next character echo.
62 | 0246/4507 jms i pType
63 | 0247/5203 jmp Loop // Get another character
64 | 0250/7300 End, cla cll // CR detected - Clear AC and Link
65 | 0251/7402 hlt // Halt
66 | 0252/5200 jmp Main // Continue
67 | //
68 | // Subroutine Segment
69 | //
70 | *0400
71 | 0400/0000 GetChar,0 // Store Return Address Here
72 | 0401/6031 ksf // Is Keyboard Flag Raised ?
73 | 0402/5201 jmp .-1 // No - Loop! (Wait Loop)
74 | 0403/6036 krb // Yes - Read Character to AC
75 | 0404/5600 jmp i GetChar // Return
76 | //
77 | 0405/0000 Type, 0 // Store Return Address Here
78 | 0406/6041 tsf // Is Printer Ready?
79 | 0407/5206 jmp .-1 // No - Loop! (Wait Loop)
80 | 0410/6046 tls // Yes - Print the character!
81 | 0411/7300 cla cll // Clear AC and Link
82 | 0412/5605 jmp i Type // Return
83 | //
84 | $Main
85 | $0200
86 |
87 | User Defined Symbol Table
88 |
89 | HOLD 0100
90 | BS 0101
91 | CR 0102
92 | LF 0103
93 | Esc 0104
94 | Space 0105
95 | pGetChar0106
96 | pType 0107
97 | Main 0200
98 | Loop 0203
99 | CrLf 0232
100 | BkSp 0240
101 | End 0250
102 | GetChar 0400
103 | Type 0405
104 |
--------------------------------------------------------------------------------
/SW/KEYECHO.OBJ:
--------------------------------------------------------------------------------
1 | 0100/0000
2 | 0101/0010
3 | 0102/0015
4 | 0103/0012
5 | 0104/0033
6 | 0105/0040
7 | 0106/0400
8 | 0107/0405
9 | 0200/7300
10 | 0201/6032
11 | 0202/6046
12 | 0203/4506
13 | 0204/3100
14 | 0205/1100
15 | 0206/7041
16 | 0207/1104
17 | 0210/7450
18 | 0211/5250
19 | 0212/7300
20 | 0213/1100
21 | 0214/7041
22 | 0215/1102
23 | 0216/7450
24 | 0217/5232
25 | 0220/7300
26 | 0221/1100
27 | 0222/7041
28 | 0223/1101
29 | 0224/7450
30 | 0225/5240
31 | 0226/7300
32 | 0227/1100
33 | 0230/4507
34 | 0231/5203
35 | 0232/7300
36 | 0233/1102
37 | 0234/4507
38 | 0235/1103
39 | 0236/4507
40 | 0237/5203
41 | 0240/7300
42 | 0241/1101
43 | 0242/4507
44 | 0243/1105
45 | 0244/4507
46 | 0245/1101
47 | 0246/4507
48 | 0247/5203
49 | 0250/7300
50 | 0251/7402
51 | 0252/5200
52 | 0400/0000
53 | 0401/6031
54 | 0402/5201
55 | 0403/6036
56 | 0404/5600
57 | 0405/0000
58 | 0406/6041
59 | 0407/5206
60 | 0410/6046
61 | 0411/7300
62 | 0412/5605
63 |
--------------------------------------------------------------------------------
/SW/KEYECHO.RIM:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrutt/PDP8/2e6754233c7c765fcd5dc73a65ff75efb5b5ec38/SW/KEYECHO.RIM
--------------------------------------------------------------------------------
/SW/KeyEcho.pal:
--------------------------------------------------------------------------------
1 | // This code segments reads and echoes characters from the keyboard.
2 | // It supports simple backspace correction of typed characters.
3 | // It ends when an escape character is detected.
4 | //
5 | //
6 | // Data Segment
7 | //
8 | *0100
9 | HOLD, 0 // Location to hold current character
10 | BS, 8d // ASCII Backspace
11 | CR, 13d // ASCII Carriage Return
12 | LF, 10d // ASCII Line Feed
13 | Esc, 27d // ASCII Escape
14 | Space, 32d // ASCII Space
15 | //
16 | // Subroutine pointers
17 | //
18 | pGetChar, GetChar
19 | pType, Type
20 | //
21 | // Code Segment
22 | //
23 | *200
24 | Main, cla cll // Clear AC and Link
25 | kcc // Clear Keyboard Flag
26 | tls // Wake Up Printer!
27 | Loop, jms i pGetChar // Get character
28 | dca HOLD // Store it
29 | tad HOLD // Compare with Esc by
30 | cia // subtracting its value
31 | tad Esc // from ASCII Escape
32 | sna // If not equal then skip next instruction
33 | jmp End // else goto end.
34 | cla cll // Clear AC
35 | tad HOLD // Compare with CR by
36 | cia // subtracting its value
37 | tad CR // from ASCII Carriage Return
38 | sna // If not equal then skip next instruction
39 | jmp CrLf // else goto line wrap.
40 | cla cll // Clear AC
41 | tad HOLD // Compare with BS by
42 | cia // subtracting its value
43 | tad BS // from ASCII Backspace
44 | sna // If not equal then skip next instruction
45 | jmp BkSp // else goto backspace.
46 | cla cll // Echo character
47 | tad HOLD // by putting it into AC
48 | jms i pType // and calling Type subroutine.
49 | jmp Loop // Get another character
50 | CrLf, cla cll // CR detected - Clear AC and Link
51 | tad CR // Get Carriage Return
52 | jms i pType // Print it
53 | tad LF // Get Line Feed
54 | jms i pType // Print it
55 | jmp Loop // Get another character
56 | BkSp, cla cll // Backspace detected - Clear AC and Link
57 | tad BS // Echo backspace to terminal to move cursor back
58 | jms i pType
59 | tad Space // Type a space to erase prior character
60 | jms i pType
61 | tad BS // Backspace again to prepare for next character echo.
62 | jms i pType
63 | jmp Loop // Get another character
64 | End, cla cll // CR detected - Clear AC and Link
65 | hlt // Halt
66 | jmp Main // Continue
67 | //
68 | // Subroutine Segment
69 | //
70 | *0400
71 | GetChar,0 // Store Return Address Here
72 | ksf // Is Keyboard Flag Raised ?
73 | jmp .-1 // No - Loop! (Wait Loop)
74 | krb // Yes - Read Character to AC
75 | jmp i GetChar // Return
76 | //
77 | Type, 0 // Store Return Address Here
78 | tsf // Is Printer Ready?
79 | jmp .-1 // No - Loop! (Wait Loop)
80 | tls // Yes - Print the character!
81 | cla cll // Clear AC and Link
82 | jmp i Type // Return
83 | //
84 | $Main
85 |
--------------------------------------------------------------------------------
/SW/VT100.LST:
--------------------------------------------------------------------------------
1 | /
2 | / Code Segment
3 | /
4 | Esc=27d
5 | /
6 | *0200 / Code Segment starts at 0200o
7 | 0200/7300 Main, cla cll / Clear AC and Link
8 | 0201/6046 tls / Wake Up Printer
9 | 0202/1300 tad Str / Get address of output string
10 | 0203/4353 jms PrtStr / Call PtrStr to Print it
11 | 0204/7402 End, hlt / Done!
12 | 0205/5200 jmp Main / Continue
13 | /
14 | / Data Segment
15 | /
16 | *0300 / Place String at 0300o
17 | 0300/0300 Str, . / Str stores its own address
18 | 0301/0033 Esc;'[2J';Esc;'[0;0H';'Hello ';Esc;'[7m';'World';Esc;'[0m';'!';13d;10d;0 /
19 | 0302/0133
20 | 0303/0062
21 | 0304/0112
22 | 0305/0033
23 | 0306/0133
24 | 0307/0060
25 | 0310/0073
26 | 0311/0060
27 | 0312/0110
28 | 0313/0110
29 | 0314/0145
30 | 0315/0154
31 | 0316/0154
32 | 0317/0157
33 | 0320/0040
34 | 0321/0033
35 | 0322/0133
36 | 0323/0067
37 | 0324/0155
38 | 0325/0127
39 | 0326/0157
40 | 0327/0162
41 | 0330/0154
42 | 0331/0144
43 | 0332/0033
44 | 0333/0133
45 | 0334/0060
46 | 0335/0155
47 | 0336/0041
48 | 0337/0015
49 | 0340/0012
50 | 0341/0000
51 | /
52 | / Subroutine Segment
53 | /
54 | *0340 / Subroutines begin at address 0340o
55 | 0340/0000 GetChar, 0 / Return Address Stored Here
56 | 0341/6031 ksf / Is Keyboard Flag Raised ?
57 | 0342/5341 jmp .-1 / No - Loop! (Wait Loop)
58 | 0343/6036 krb / Yes - Read Character to AC
59 | 0344/5740 jmp i GetChar / Return
60 | 0345/0000 Type, 0 / Return Address Stored Here
61 | 0346/6041 tsf / Is Printer Ready?
62 | 0347/5346 jmp .-1 / No - Loop! (Wait Loop)
63 | 0350/6046 tls / Yes - Print the character!
64 | 0351/7300 cla cll / Clear AC and Link
65 | 0352/5745 jmp i Type / Return
66 | 0353/0000 PrtStr, 0 / Return Address Stored Here
67 | 0354/3010 dca 10 / Deposit address of string to auto-index register 10
68 | 0355/1410 tad i 10 / Load character
69 | 0356/7450 sna / Is it a null? - skip if non-zero
70 | 0357/5753 jmp i PrtStr / yes - return
71 | 0360/4345 jms Type / no - call Type to display
72 | 0361/5355 jmp .-4 / Get next character
73 | $Main
74 | $0200
75 |
76 | User Defined Symbol Table
77 |
78 | Esc 0033
79 | Main 0200
80 | End 0204
81 | Str 0300
82 | GetChar 0340
83 | Type 0345
84 | PrtStr 0353
85 |
--------------------------------------------------------------------------------
/SW/VT100.OBJ:
--------------------------------------------------------------------------------
1 | 0200/7300
2 | 0201/6046
3 | 0202/1300
4 | 0203/4353
5 | 0204/7402
6 | 0205/5200
7 | 0300/0300
8 | 0301/0033
9 | 0302/0133
10 | 0303/0062
11 | 0304/0112
12 | 0305/0033
13 | 0306/0133
14 | 0307/0060
15 | 0310/0073
16 | 0311/0060
17 | 0312/0110
18 | 0313/0110
19 | 0314/0145
20 | 0315/0154
21 | 0316/0154
22 | 0317/0157
23 | 0320/0040
24 | 0321/0033
25 | 0322/0133
26 | 0323/0067
27 | 0324/0155
28 | 0325/0127
29 | 0326/0157
30 | 0327/0162
31 | 0330/0154
32 | 0331/0144
33 | 0332/0033
34 | 0333/0133
35 | 0334/0060
36 | 0335/0155
37 | 0336/0041
38 | 0337/0015
39 | 0340/0012
40 | 0341/0000
41 | 0340/0000
42 | 0341/6031
43 | 0342/5341
44 | 0343/6036
45 | 0344/5740
46 | 0345/0000
47 | 0346/6041
48 | 0347/5346
49 | 0350/6046
50 | 0351/7300
51 | 0352/5745
52 | 0353/0000
53 | 0354/3010
54 | 0355/1410
55 | 0356/7450
56 | 0357/5753
57 | 0360/4345
58 | 0361/5355
59 |
--------------------------------------------------------------------------------
/SW/VT100.RIM:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrutt/PDP8/2e6754233c7c765fcd5dc73a65ff75efb5b5ec38/SW/VT100.RIM
--------------------------------------------------------------------------------
/SW/VT100.pal:
--------------------------------------------------------------------------------
1 | /
2 | / Code Segment
3 | /
4 | Esc=27d
5 | /
6 | *0200 / Code Segment starts at 0200o
7 | Main, cla cll / Clear AC and Link
8 | tls / Wake Up Printer
9 | tad Str / Get address of output string
10 | jms PrtStr / Call PtrStr to Print it
11 | End, hlt / Done!
12 | jmp Main / Continue
13 | /
14 | / Data Segment
15 | /
16 | *0300 / Place String at 0300o
17 | Str, . / Str stores its own address
18 | Esc;'[2J';Esc;'[0;0H';'Hello ';Esc;'[7m';'World';Esc;'[0m';'!';13d;10d;0 / string to be displayed - ends with null
19 | /
20 | / Subroutine Segment
21 | /
22 | *0340 / Subroutines begin at address 0340o
23 | GetChar, 0 / Return Address Stored Here
24 | ksf / Is Keyboard Flag Raised ?
25 | jmp .-1 / No - Loop! (Wait Loop)
26 | krb / Yes - Read Character to AC
27 | jmp i GetChar / Return
28 | Type, 0 / Return Address Stored Here
29 | tsf / Is Printer Ready?
30 | jmp .-1 / No - Loop! (Wait Loop)
31 | tls / Yes - Print the character!
32 | cla cll / Clear AC and Link
33 | jmp i Type / Return
34 | PrtStr, 0 / Return Address Stored Here
35 | dca 10 / Deposit address of string to auto-index register 10
36 | tad i 10 / Load character
37 | sna / Is it a null? - skip if non-zero
38 | jmp i PrtStr / yes - return
39 | jms Type / no - call Type to display
40 | jmp .-4 / Get next character
41 | $Main
42 |
--------------------------------------------------------------------------------
/dosbox-0.74-PDP-8.conf:
--------------------------------------------------------------------------------
1 | [sdl]
2 | windowresolution=1024x768
3 | output=opengl
4 |
5 | [cpu]
6 | cycles=max
7 |
8 | [autoexec]
9 | mount c c:\pdp8
10 | c:
11 | cd sw
12 | ..\pdp8main\pdp8main.exe
13 |
--------------------------------------------------------------------------------
/dosbox-0.74.conf:
--------------------------------------------------------------------------------
1 | # This is the configurationfile for DOSBox 0.74. (Please use the latest version of DOSBox)
2 | # Lines starting with a # are commentlines and are ignored by DOSBox.
3 | # They are used to (briefly) document the effect of each option.
4 |
5 | [sdl]
6 | # fullscreen: Start dosbox directly in fullscreen. (Press ALT-Enter to go back)
7 | # fulldouble: Use double buffering in fullscreen. It can reduce screen flickering, but it can also result in a slow DOSBox.
8 | # fullresolution: What resolution to use for fullscreen: original or fixed size (e.g. 1024x768).
9 | # Using your monitor's native resolution with aspect=true might give the best results.
10 | # If you end up with small window on a large screen, try an output different from surface.
11 | # windowresolution: Scale the window to this size IF the output device supports hardware scaling.
12 | # (output=surface does not!)
13 | # output: What video system to use for output.
14 | # Possible values: surface, overlay, opengl, openglnb, ddraw.
15 | # autolock: Mouse will automatically lock, if you click on the screen. (Press CTRL-F10 to unlock)
16 | # sensitivity: Mouse sensitivity.
17 | # waitonerror: Wait before closing the console if dosbox has an error.
18 | # priority: Priority levels for dosbox. Second entry behind the comma is for when dosbox is not focused/minimized.
19 | # pause is only valid for the second entry.
20 | # Possible values: lowest, lower, normal, higher, highest, pause.
21 | # mapperfile: File used to load/save the key/event mappings from. Resetmapper only works with the defaul value.
22 | # usescancodes: Avoid usage of symkeys, might not work on all operating systems.
23 |
24 | fullscreen=false
25 | fulldouble=false
26 | fullresolution=original
27 | windowresolution=original
28 | output=surface
29 | autolock=true
30 | sensitivity=100
31 | waitonerror=true
32 | priority=higher,normal
33 | mapperfile=mapper-0.74.map
34 | usescancodes=true
35 |
36 | [dosbox]
37 | # language: Select another language file.
38 | # machine: The type of machine tries to emulate.
39 | # Possible values: hercules, cga, tandy, pcjr, ega, vgaonly, svga_s3, svga_et3000, svga_et4000, svga_paradise, vesa_nolfb, vesa_oldvbe.
40 | # captures: Directory where things like wave, midi, screenshot get captured.
41 | # memsize: Amount of memory DOSBox has in megabytes.
42 | # This value is best left at its default to avoid problems with some games,
43 | # though few games might require a higher value.
44 | # There is generally no speed advantage when raising this value.
45 |
46 | language=
47 | machine=svga_s3
48 | captures=capture
49 | memsize=16
50 |
51 | [render]
52 | # frameskip: How many frames DOSBox skips before drawing one.
53 | # aspect: Do aspect correction, if your output method doesn't support scaling this can slow things down!.
54 | # scaler: Scaler used to enlarge/enhance low resolution modes.
55 | # If 'forced' is appended, then the scaler will be used even if the result might not be desired.
56 | # Possible values: none, normal2x, normal3x, advmame2x, advmame3x, advinterp2x, advinterp3x, hq2x, hq3x, 2xsai, super2xsai, supereagle, tv2x, tv3x, rgb2x, rgb3x, scan2x, scan3x.
57 |
58 | frameskip=0
59 | aspect=false
60 | scaler=normal2x
61 |
62 | [cpu]
63 | # core: CPU Core used in emulation. auto will switch to dynamic if available and appropriate.
64 | # Possible values: auto, dynamic, normal, simple.
65 | # cputype: CPU Type used in emulation. auto is the fastest choice.
66 | # Possible values: auto, 386, 386_slow, 486_slow, pentium_slow, 386_prefetch.
67 | # cycles: Amount of instructions DOSBox tries to emulate each millisecond.
68 | # Setting this value too high results in sound dropouts and lags.
69 | # Cycles can be set in 3 ways:
70 | # 'auto' tries to guess what a game needs.
71 | # It usually works, but can fail for certain games.
72 | # 'fixed #number' will set a fixed amount of cycles. This is what you usually need if 'auto' fails.
73 | # (Example: fixed 4000).
74 | # 'max' will allocate as much cycles as your computer is able to handle.
75 | #
76 | # Possible values: auto, fixed, max.
77 | # cycleup: Amount of cycles to decrease/increase with keycombo.(CTRL-F11/CTRL-F12)
78 | # cycledown: Setting it lower than 100 will be a percentage.
79 |
80 | core=auto
81 | cputype=auto
82 | cycles=auto
83 | cycleup=10
84 | cycledown=20
85 |
86 | [mixer]
87 | # nosound: Enable silent mode, sound is still emulated though.
88 | # rate: Mixer sample rate, setting any device's rate higher than this will probably lower their sound quality.
89 | # Possible values: 44100, 48000, 32000, 22050, 16000, 11025, 8000, 49716.
90 | # blocksize: Mixer block size, larger blocks might help sound stuttering but sound will also be more lagged.
91 | # Possible values: 1024, 2048, 4096, 8192, 512, 256.
92 | # prebuffer: How many milliseconds of data to keep on top of the blocksize.
93 |
94 | nosound=false
95 | rate=44100
96 | blocksize=1024
97 | prebuffer=20
98 |
99 | [midi]
100 | # mpu401: Type of MPU-401 to emulate.
101 | # Possible values: intelligent, uart, none.
102 | # mididevice: Device that will receive the MIDI data from MPU-401.
103 | # Possible values: default, win32, alsa, oss, coreaudio, coremidi, none.
104 | # midiconfig: Special configuration options for the device driver. This is usually the id of the device you want to use.
105 | # See the README/Manual for more details.
106 |
107 | mpu401=intelligent
108 | mididevice=default
109 | midiconfig=
110 |
111 | [sblaster]
112 | # sbtype: Type of Soundblaster to emulate. gb is Gameblaster.
113 | # Possible values: sb1, sb2, sbpro1, sbpro2, sb16, gb, none.
114 | # sbbase: The IO address of the soundblaster.
115 | # Possible values: 220, 240, 260, 280, 2a0, 2c0, 2e0, 300.
116 | # irq: The IRQ number of the soundblaster.
117 | # Possible values: 7, 5, 3, 9, 10, 11, 12.
118 | # dma: The DMA number of the soundblaster.
119 | # Possible values: 1, 5, 0, 3, 6, 7.
120 | # hdma: The High DMA number of the soundblaster.
121 | # Possible values: 1, 5, 0, 3, 6, 7.
122 | # sbmixer: Allow the soundblaster mixer to modify the DOSBox mixer.
123 | # oplmode: Type of OPL emulation. On 'auto' the mode is determined by sblaster type. All OPL modes are Adlib-compatible, except for 'cms'.
124 | # Possible values: auto, cms, opl2, dualopl2, opl3, none.
125 | # oplemu: Provider for the OPL emulation. compat might provide better quality (see oplrate as well).
126 | # Possible values: default, compat, fast.
127 | # oplrate: Sample rate of OPL music emulation. Use 49716 for highest quality (set the mixer rate accordingly).
128 | # Possible values: 44100, 49716, 48000, 32000, 22050, 16000, 11025, 8000.
129 |
130 | sbtype=sb16
131 | sbbase=220
132 | irq=7
133 | dma=1
134 | hdma=5
135 | sbmixer=true
136 | oplmode=auto
137 | oplemu=default
138 | oplrate=44100
139 |
140 | [gus]
141 | # gus: Enable the Gravis Ultrasound emulation.
142 | # gusrate: Sample rate of Ultrasound emulation.
143 | # Possible values: 44100, 48000, 32000, 22050, 16000, 11025, 8000, 49716.
144 | # gusbase: The IO base address of the Gravis Ultrasound.
145 | # Possible values: 240, 220, 260, 280, 2a0, 2c0, 2e0, 300.
146 | # gusirq: The IRQ number of the Gravis Ultrasound.
147 | # Possible values: 5, 3, 7, 9, 10, 11, 12.
148 | # gusdma: The DMA channel of the Gravis Ultrasound.
149 | # Possible values: 3, 0, 1, 5, 6, 7.
150 | # ultradir: Path to Ultrasound directory. In this directory
151 | # there should be a MIDI directory that contains
152 | # the patch files for GUS playback. Patch sets used
153 | # with Timidity should work fine.
154 |
155 | gus=false
156 | gusrate=44100
157 | gusbase=240
158 | gusirq=5
159 | gusdma=3
160 | ultradir=C:\ULTRASND
161 |
162 | [speaker]
163 | # pcspeaker: Enable PC-Speaker emulation.
164 | # pcrate: Sample rate of the PC-Speaker sound generation.
165 | # Possible values: 44100, 48000, 32000, 22050, 16000, 11025, 8000, 49716.
166 | # tandy: Enable Tandy Sound System emulation. For 'auto', emulation is present only if machine is set to 'tandy'.
167 | # Possible values: auto, on, off.
168 | # tandyrate: Sample rate of the Tandy 3-Voice generation.
169 | # Possible values: 44100, 48000, 32000, 22050, 16000, 11025, 8000, 49716.
170 | # disney: Enable Disney Sound Source emulation. (Covox Voice Master and Speech Thing compatible).
171 |
172 | pcspeaker=true
173 | pcrate=44100
174 | tandy=auto
175 | tandyrate=44100
176 | disney=true
177 |
178 | [joystick]
179 | # joysticktype: Type of joystick to emulate: auto (default), none,
180 | # 2axis (supports two joysticks),
181 | # 4axis (supports one joystick, first joystick used),
182 | # 4axis_2 (supports one joystick, second joystick used),
183 | # fcs (Thrustmaster), ch (CH Flightstick).
184 | # none disables joystick emulation.
185 | # auto chooses emulation depending on real joystick(s).
186 | # (Remember to reset dosbox's mapperfile if you saved it earlier)
187 | # Possible values: auto, 2axis, 4axis, 4axis_2, fcs, ch, none.
188 | # timed: enable timed intervals for axis. Experiment with this option, if your joystick drifts (away).
189 | # autofire: continuously fires as long as you keep the button pressed.
190 | # swap34: swap the 3rd and the 4th axis. can be useful for certain joysticks.
191 | # buttonwrap: enable button wrapping at the number of emulated buttons.
192 |
193 | joysticktype=auto
194 | timed=true
195 | autofire=false
196 | swap34=false
197 | buttonwrap=false
198 |
199 | [serial]
200 | # serial1: set type of device connected to com port.
201 | # Can be disabled, dummy, modem, nullmodem, directserial.
202 | # Additional parameters must be in the same line in the form of
203 | # parameter:value. Parameter for all types is irq (optional).
204 | # for directserial: realport (required), rxdelay (optional).
205 | # (realport:COM1 realport:ttyS0).
206 | # for modem: listenport (optional).
207 | # for nullmodem: server, rxdelay, txdelay, telnet, usedtr,
208 | # transparent, port, inhsocket (all optional).
209 | # Example: serial1=modem listenport:5000
210 | # Possible values: dummy, disabled, modem, nullmodem, directserial.
211 | # serial2: see serial1
212 | # Possible values: dummy, disabled, modem, nullmodem, directserial.
213 | # serial3: see serial1
214 | # Possible values: dummy, disabled, modem, nullmodem, directserial.
215 | # serial4: see serial1
216 | # Possible values: dummy, disabled, modem, nullmodem, directserial.
217 |
218 | serial1=dummy
219 | serial2=dummy
220 | serial3=disabled
221 | serial4=disabled
222 |
223 | [dos]
224 | # xms: Enable XMS support.
225 | # ems: Enable EMS support.
226 | # umb: Enable UMB support.
227 | # keyboardlayout: Language code of the keyboard layout (or none).
228 |
229 | xms=true
230 | ems=true
231 | umb=true
232 | keyboardlayout=auto
233 |
234 | [ipx]
235 | # ipx: Enable ipx over UDP/IP emulation.
236 |
237 | ipx=false
238 |
239 | [autoexec]
240 | # Lines in this section will be run at startup.
241 | # You can put your MOUNT lines here.
242 |
--------------------------------------------------------------------------------