├── .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 | --------------------------------------------------------------------------------