diff --git a/apps/README.md b/apps/README.md index dce8a53e3..6aca0570c 100644 --- a/apps/README.md +++ b/apps/README.md @@ -13,7 +13,7 @@ PCjs has archived selected software for the following machines: * [IBM PC](pcx86/) * [Challenger 1P](c1p/) -* DEC [PDP-10](pdp10/) and [PDP-11](pdp11/) +* [PDP-10](pdp10/) and [PDP-11](pdp11/) PCjs also includes a small collection of disk images in the [Disk Libraries](/disks/): diff --git a/apps/pdp10/tapes/diags/klad/README.md b/apps/pdp10/tapes/diags/klad/README.md index c77993b2f..ef0b752f7 100644 --- a/apps/pdp10/tapes/diags/klad/README.md +++ b/apps/pdp10/tapes/diags/klad/README.md @@ -11,7 +11,3 @@ We have archived selected files from [PDP-10 KLAD Diagnostics Sources](http://pd including: - [KA10 BASIC INSTRUCTION DIAGNOSTIC (MAINDEC-10-DAKAD-B-D)](dakad/) - -The Debugger command `a 100 http://archive.pcjs.org/apps/pdp10/tapes/diags/klad/dakadm.mac.html` can be used to test the -new [MACRO-10](http://archive.pcjs.org/pubs/dec/pdp10/tops10/02_1973AsmRef_macro.pdf) work-alike assembler being added to -the PDP-10 Emulator. diff --git a/apps/pdp10/tapes/diags/klad/dakad/README.md b/apps/pdp10/tapes/diags/klad/dakad/README.md index 4cc1c92d8..70bb8100c 100644 --- a/apps/pdp10/tapes/diags/klad/dakad/README.md +++ b/apps/pdp10/tapes/diags/klad/dakad/README.md @@ -10,6 +10,10 @@ PDP-10 KA10 BASIC INSTRUCTION DIAGNOSTIC The **PDP-10 KA10 BASIC INSTRUCTION DIAGNOSTIC** (MAINDEC-10-DAKAD-B-D), as extracted from the [original file](http://pdp-10.trailing-edge.com/klad_sources/01/klad.sources/dakaam.mac.html), is shown below. +The Debugger command `a 100 http://archive.pcjs.org/apps/pdp10/tapes/diags/klad/dakadm.mac.html` can be used to test the +new [MACRO-10](http://archive.pcjs.org/pubs/dec/pdp10/tops10/02_1973AsmRef_macro.pdf) work-alike assembler being added to +the PDP-10 Emulator. + ``` SUBTTL DIAGNOSTIC PARAMETERS @@ -33,19 +37,19 @@ DCK=40 ;DIVIDE CHECK ; STOP - USED FOR SCOPE LOOP, IF INSTRUCTION FAILS, CHANGE (JUMPA .+1) ; TO A (JUMPA X) TO CYCLE ON FAILING INSTRUCTION -DEFINE STOP (A)< +DEFINE STOP (A)< HALT .+1 ;TEST FAILED IF PROGRAM HALTS HERE JUMPA .+1 ;IF TEST FAILS, CHANGE THIS INSTRUCTION (JUMPA .+1) ;TO JUMPA X(X IS THE ADDRESS OF THE FIRST ;INSTRUCTION IN THE SUBTEST) TO LOOP ON ERROR - ;AND CHANGE HALT INSTRUCTION TO JUMPA .+1> + ;AND CHANGE HALT INSTRUCTION TO JUMPA .+1> ; SFLAG - USED TO CLEAR ALL FLAGS THEN TO SET REQUESTED FLAG -DEFINE SFLAG (A)< +DEFINE SFLAG (A)< MOVSI 1,A JFCL 17,.+1 ;RESET ALL FLAGS - JRST 2,.+1(1) ;SET A FLAG> + JRST 2,.+1(1) ;SET A FLAG> SUBTTL DIAGNOSTIC SECTION START: SETZM USER# ;CLEAR USER CONTROL WORD @@ -134,12 +138,12 @@ SN=500 ;IF ANY AC DOES NOT CONTAIN ITS ADDRESS, THIS TEST FAILS C500: REPEAT ^D16, -< ZZ=ZZ+1 - MOVEI ZZ,ZZ ;PRELOAD EACH AC WITH ITS ADDR> +< ZZ=ZZ+1 + MOVEI ZZ,ZZ ;PRELOAD EACH AC WITH ITS ADDR> PAGE ZZ=20 - REPEAT ^D16,< + REPEAT ^D16,< ;THIS TEST VERIFIES THAT ALL ACS EXIST. ;FIRST, EACH AC IS PRELOADED WITH ITS OWN ADDRESS; ;THEN, THE CONTENTS OF EACH AC IS CHECKED FOR ITS ADDRESS. @@ -152,7 +156,7 @@ SN=SN+1 ;IN CASE OF FAILURE, LOOP TO C500 ADDRESS ;********** -> +> SN=600 ZZ=0 @@ -162,13 +166,13 @@ SN=600 ;AC IS CHECKED FOR ITS ADDRESS. IF ANY AC DOES NOT CONTAIN ITS ADDRESS, THIS TEST FAILS. C600: REPEAT ^D15, -< ZZ=ZZ+1 +< ZZ=ZZ+1 MOVEI ZZ ;PRELOAD EACH AC WITH ITS ADDRESS - MOVEM ZZ ;BY REFERENCING EACH AC AS MEMORY.> + MOVEM ZZ ;BY REFERENCING EACH AC AS MEMORY.> ZZ=20 - REPEAT ^D15,< + REPEAT ^D15,< ;THIS TEST VERIFIES THAT AN ADDRESS WITHIN THE AC RANGE MAY BE ACCESSED AS ;EITHER AN AC OR A MEMORY LOCATION AND THAT EITHER REFERENCE REFERS TO THE ;SAME HARDWARE. EACH AC IS PRELOADED WITH ITS ADDRESS @@ -182,11 +186,11 @@ SN=SN+1 ;IN CASE OF FAILURE, LOOP TO C600 ADDRESS ;********** -> +> SN=700 ZZ=0 -C700: REPEAT ^D15,< +C700: REPEAT ^D15,< ;THIS TEST VERIFIES THAT THE INDEX REGISTERS ARE ACCESSABLE. ;FIRST, AN INDEX REGISTER IS PRELOADED WITH ITS ADDRESS; THEN, ;IT IS REFERENCED AS AN INDEX REGISTER. IF IT CONTAINS ITS ADDRESS, THIS TEST PASSES. @@ -199,11 +203,11 @@ SN=SN+1 STOP ;********** -> +> SN=1000 ZZ=0 -C1000: REPEAT ^D15,< +C1000: REPEAT ^D15,< ;THIS TEST VERIFIES THAT ALL INDEX REGISTERS INDEX CORRECTLY. ;FIRST, BOTH HALVES OF THE INDEX REGISTER ARE PRELOADED WITH ITS ADDRESS. ;THEN, THE INDEX REGISTER IS REFERENCED. IT IS THEN CHECKED FOR ITS ADDRESS IN BOTH HALVES. @@ -218,7 +222,7 @@ SN=SN+1 STOP ;********** -> +> SUBTTL TEST OF INDEX REGISTER ADDRESSING ;********** @@ -241,7 +245,7 @@ C1100: SETOM 3 ;PRELOAD AC3 WITH -1,,1 SN=1200 ZZ=0 -C1200: REPEAT ^D18,< +C1200: REPEAT ^D18,< ;THIS TEST VERIFIES THAT INDEX REGISTER ADDRESSING FUNCTIONS CORRECTLY. ;IN THIS TEST, A MOVE INSTRUCTION USING INDEXING IS EXECUTED. THE MOVE INSTRUCTION ;SHOULD PLACE THE CONTENTS OF THE LOCATION SPECIFIED BY INDEX REGISTER 2 INTO AC3. @@ -251,7 +255,7 @@ C1200: REPEAT ^D18,< SN=SN+1 ZZ=ZZ+ZZ - IFE ZZ,<ZZ=1> + IFE ZZ, SETOM 3 ;PRELOAD AC3 WITH -1,,-1 MOVEI 1,ZZ ;PRELOAD AC1 WITH FLOATING 1 MOVEI 2,1 ;SETUP INDEX REGISTER @@ -260,11 +264,11 @@ SN=SN+1 STOP ;********** -> +> SN=1300 ZZ=0 -C1300: REPEAT ^D18,< +C1300: REPEAT ^D18,< ;THIS TEST VERIFIES THAT INDEX REGISTER ADDRESSING FUNCTIONS CORRECTLY. ;IN THIS TEST, A MOVE INSTRUCTION USING INDEXING IS EXECUTED. THE MOVE INSTRUCTION ;SHOULD PLACE THE CONTENTS OF THE LOCATION SPECIFIED BY INDEX REGISTER 2 INTO AC3. @@ -274,7 +278,7 @@ C1300: REPEAT ^D18,< SN=SN+1 ZZ=ZZ+ZZ - IFE ZZ,<ZZ=1> + IFE ZZ, SETOM 3 ;PRELOAD AC3 WITH -1,,-1 MOVSI 1,ZZ ;PRELOAD AC1 WITH FLOATING 1 MOVEI 2,1 ;SETUP INDEX REGISTER @@ -283,7 +287,7 @@ SN=SN+1 STOP ;********** -> +> ;THIS TEST VERIFIES THAT INDEX REGISTER ADDRESSING FUNCTIONS CORRECTLY. ;IN THIS TEST, A MOVE INSTRUCTION USING INDEXING IS EXECUTED. THE MOVE INSTRUCTION ;SHOULD PLACE THE CONTENTS OF THE LOCATION SPECIFIED BY INDEX REGISTER 2 INTO AC3. @@ -302,7 +306,7 @@ C1400: SETZM 3 ;PRELOAD AC3 WITH 0 SN=1500 ZZ=0 -C1500: REPEAT ^D18,< +C1500: REPEAT ^D18,< ;THIS TEST VERIFIES THAT INDEX REGISTER ADDRESSING FUNCTIONS CORRECTLY. ;IN THIS TEST, A MOVE INSTRUCTION USING INDEXING IS EXECUTED. THE MOVE INSTRUCTION ;SHOULD PLACE THE CONTENTS OF THE LOCATION SPECIFIED BY INDEX REGISTER 2 INTO AC3. @@ -311,8 +315,8 @@ C1500: REPEAT ^D18,< ;IF C(AC3)=A FLOATING 0, THIS TEST PASSES. SN=SN+1 - ZZ=<ZZ+ZZ+1>&777777 - IFE <ZZ-1>,<ZZ=777776> + ZZ=&777777 + IFE , SETZM 3 ;PRELOAD AC3 WITH 0 HRROI 1,ZZ ;PRELOAD AC1 WITH FLOATING 0 MOVEI 2,1 ;SETUP INDEX REGISTER @@ -321,11 +325,11 @@ SN=SN+1 STOP ;********** -> +> SN=1600 ZZ=0 -C1600: REPEAT ^D18,< +C1600: REPEAT ^D18,< ;THIS TEST VERIFIES THAT INDEX REGISTER ADDRESSING FUNCTIONS CORRECTLY. ;IN THIS TEST, A MOVE INSTRUCTION USING INDEXING IS EXECUTED. THE MOVE INSTRUCTION ;SHOULD PLACE THE CONTENTS OF THE LOCATION SPECIFIED BY INDEX REGISTER 2 INTO AC3. @@ -334,8 +338,8 @@ C1600: REPEAT ^D18,< ;IF C(AC3)=A FLOATING 0, THIS TEST PASSES. SN=SN+1 - ZZ=<ZZ+ZZ+1>&777777 - IFE <ZZ-1>,<ZZ=777776> + ZZ=&777777 + IFE , SETZM 3 ;PRELOAD AC3 WITH 0 HRLOI 1,ZZ ;PRELOAD AC1 WITH FLOATING 0 MOVEI 2,1 ;SETUP INDEX REGISTER @@ -344,7 +348,7 @@ SN=SN+1 STOP ;********** -> +> ;VERIFY INDEXING WHERE 'E' IS NON-ZERO SN=1700 @@ -359,7 +363,7 @@ SN=1700 ;XX+C(ZZ+1 - RIGHT) SHOULD = ZZ. C1700: REPEAT ^D15, -<SN=SN+1 + PAGE SN=2000 ZZ=-1 @@ -381,7 +385,7 @@ SN=2000 ;IF THE RESULT IN THE AC EQUALS 0,,ZZ, THIS TEST PASSES. C2000: REPEAT ^D15, -<SN=SN+1 + SUBTTL TEST OF EXCH INSTRUCTION ;********** @@ -457,7 +461,7 @@ C2710: CAME ,[XWD -1,0] ;PASS IF C(AC)=-1,,0 C3000: MOVE [252525252525] ;PRELOAD AC,E WITH 252525,,252525 REPEAT 7, -< EXCH ;*EXCH SHOULD PLACE 252525,,252525 INTO AC0> +< EXCH ;*EXCH SHOULD PLACE 252525,,252525 INTO AC0> CAME [252525252525] ;PASS IF C(AC0)=252525,,252525 STOP @@ -471,7 +475,7 @@ PAGE C3100: SETZ ;PRELOAD AC WITH 0 SETO 1,0 ;PRELOAD E WITH -1,,-1 REPEAT 7, -< EXCH 1 ;*EXCH SHOULD EXCHANGE C(AC) AND C(E)> +< EXCH 1 ;*EXCH SHOULD EXCHANGE C(AC) AND C(E)> CAME [-1] ;PASS IF C(AC)=-1,,-1 STOP C3110: CAME 1,[0] ;PASS IF C(E)=0 @@ -1525,9 +1529,9 @@ C16100: MOVEI 1 ;PRELOAD AC WITH 1 C16200: AC=17 SETZ AC, ;PRELOAD AC WITH 0 - REPEAT ^D10,< + REPEAT ^D10,< SOJ AC,. ;*SOJ SHOULD SUBTRACT 1 FROM THE AC - AOJ AC,. ;*AOJ SHOULD ADD 1 TO THE AC> + AOJ AC,. ;*AOJ SHOULD ADD 1 TO THE AC> SKIPE AC ;PASS IF C(AC) IS UNCHANGED. I.E. C(AC)=0 STOP diff --git a/modules/pdp10/lib/macro10.js b/modules/pdp10/lib/macro10.js index ea7ed4d6d..468a8a74f 100644 --- a/modules/pdp10/lib/macro10.js +++ b/modules/pdp10/lib/macro10.js @@ -65,46 +65,126 @@ class Macro10 { { this.sURL = sURL; this.nAddr = nAddr; - this.dbg = dbg; this.done = done; + + /* + * Set up all the services we need to use. + */ + this.println = dbg && dbg.println || console.log; + + /* + * Initialize all the tables that MACRO-10 uses. + */ + this.tblMacros = {}; + this.tblSymbols = {}; + var macro10 = this; Web.getResource(sURL, null, true, function(sURL, sResource, nErrorCode) { if (!nErrorCode) { - nErrorCode = macro10.parse(sURL, sResource); + nErrorCode = macro10.parseFile(sURL, sResource); } macro10.done(macro10, sURL, nErrorCode); }); } /** - * parse(sURL, sResource) + * parseFile(sPath, sContents) * * Begin the assembly process. * * @this {Macro10} - * @param {string} sURL - * @param {string} sResource + * @param {string} sPath + * @param {string} sContents * @return {number} */ - parse(sURL, sResource) + parseFile(sPath, sContents) { - var match, re; - var sText = sResource; - if (Str.endsWith(sURL, ".html")) { + var sText = sContents; + if (Str.endsWith(sPath, ".html")) { /* - * We want to parse ONLY text between
...
tags. + * We want to parse ONLY the text between
...
tags, and eliminate any HTML entities. */ sText = ""; - re = /
([\s\S]*?)<\/pre>/gi;
-            while (match = re.exec(sResource)) {
-                sText += match[1];
+            var match, re = /
([\s\S]*?)<\/pre>/gi;
+            while (match = re.exec(sContents)) {
+                var s = match[1];
+                if (s.indexOf('&') >= 0) s = s.replace(/</gi, '<').replace(/>/gi, '>').replace(/&/gi, '&');
+                sText += s;
             }
+            match = sText.match(/&[a-z]+;/i);
+            if (match) this.warning("unrecognized HTML entity: " + match[0]);
         }
         var i;
         var asLines = sText.split(/\r?\n/);
         for (i = 0; i < asLines.length; i++) {
-            //this.dbg.println(asLines[i]);
+            if (!this.parseLine(i + 1, asLines[i])) break;
         }
         return 0;
     }
+
+    /**
+     * parseLine(nLine, sLine)
+     *
+     * @this {Macro10}
+     * @param {number} nLine (line number)
+     * @param {string} sLine (line contents)
+     * @return {boolean}
+     */
+    parseLine(nLine, sLine)
+    {
+        var reLine = /([A-Z$%.][0-9A-Z$%.]*[:=]|)\s*([^\s;]+|)\s*([^;]+|)\s*(;?.*)/i;
+        var match = sLine.match(reLine);
+        if (!match || match[4] && match[4].slice(0, 1) != ';') {
+            this.warning("failed to parse line " + nLine + ": " + sLine);
+            return false;
+        }
+        var sLabel = match[1];
+        var sOperator = match[2];
+        var sOperands = match[3].trim();
+        var sComment = match[4].slice(1);
+        if (sLabel) {
+            var chSep = sLabel.slice(-1);
+            sLabel = sLabel.slice(0, -1);
+            if (chSep == ':') {
+                this.addLabel(sLabel);
+            } else {
+                this.addVariable(sLabel, sOperands = sOperator + sOperands);
+                sOperator = chSep;
+            }
+        }
+        if (DEBUG) this.println(Str.toDec(nLine, 5) + ": label(" + sLabel + ") operator(" + sOperator + ") operands(" + sOperands + ") comment(" + sComment + ")");
+        return true;
+    }
+
+    /**
+     * warning(sWarning)
+     *
+     * @this {Macro10}
+     * @param {string} sWarning
+     */
+    warning(sWarning)
+    {
+        this.println("warning: " + sWarning);
+    }
+
+    /**
+     * addLabel(sLabel)
+     *
+     * @this {Macro10}
+     * @param {string} sLabel
+     */
+    addLabel(sLabel)
+    {
+    }
+
+    /**
+     * addVariable(sVar, sExp)
+     *
+     * @this {Macro10}
+     * @param {string} sVar
+     * @param {string} sExp
+     */
+    addVariable(sVar, sExp)
+    {
+    }
 }