From dd24f4bb61c8c1a6acbdaf0bc96f43b78eca6ab5 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 24 Mar 2017 16:23:27 -0700 Subject: [PATCH] Added some PDP-10/MACRO-10 blog updates --- ...1-the-macro-10-assembler-50-years-later.md | 91 +++++++++++++++-- ...-24-stepping-through-pdp-10-diagnostica.md | 98 +++++++++++++++++++ apps/pdp10/tests/macro10/README.md | 8 +- modules/pdp10/lib/debugger.js | 1 + modules/pdp10/lib/macro10.js | 2 +- 5 files changed, 188 insertions(+), 12 deletions(-) create mode 100644 _posts/2017-03-24-stepping-through-pdp-10-diagnostica.md diff --git a/_posts/2017-03-21-the-macro-10-assembler-50-years-later.md b/_posts/2017-03-21-the-macro-10-assembler-50-years-later.md index fcc2cd23c..ec81ce9a0 100644 --- a/_posts/2017-03-21-the-macro-10-assembler-50-years-later.md +++ b/_posts/2017-03-21-the-macro-10-assembler-50-years-later.md @@ -1,7 +1,7 @@ --- layout: post title: The MACRO-10 Assembler, 50 Years Later -date: 2017-02-28 22:00:00 +date: 2017-03-21 22:00:00 permalink: /blog/2017/03/21/ machines: - id: testka10 @@ -53,7 +53,7 @@ The above machine uses the Debugger's assemble ('a') command to assemble DEC's " a 30724 /apps/pdp10/diags/klad/dakaa/MYDAKAA.MAC -The Debugger invokes the MACRO-10 mini-assembler whenever the argument following the target address appears to be a URL. +The Debugger invokes the MACRO-10 mini-assembler whenever the target address is followed by an argument ending with ".MAC". As previously described in the section on [PDPjs PDP-10 Opcode Tests](/apps/pdp10/tests/opcodes/), the Debugger already allowed you to assemble instructions directly into memory (eg, `a 100 hrli 1,111111`). This "immediate mode" feature is provided @@ -73,7 +73,7 @@ This command differs from MACRO-10, which uses the `RADIX` pseudo-op to change t Obviously, it would be nice if both the Debugger and the MACRO-10 mini-assembler used matching commands, but the PCjs debuggers were written before MACRO-10 support was a consideration, so for now, that's life. -All of the MACRO-10-style base prefixes are supported (^D for decimal, ^B for binary, an ^O for octal): +All of the MACRO-10-style base prefixes are supported (**^D** for decimal, **^B** for binary, an **^O** for octal): >> print ^D27 0o000000000033 27. @@ -89,7 +89,7 @@ Expressions using angle brackets, another MACRO-10 convention, is also supported >> print ^D<45-22> 0o000000000027 23. -Note that the base modifier (^D) applies to the entire expression. You can also add MACRO-10 suffixes to integers: +Note that the base modifier (**^D**) applies to the entire expression. You can also add MACRO-10 suffixes to integers: K: "kilo-", thousands M: "mega-", millions @@ -118,8 +118,10 @@ so: Binary shifting using a **B** suffix is also supported. Note that MACRO-10 binary shifting is a "bit" unusual by today's standards, because the value after the **B**, *n*, is not a count but rather the desired bit position of the right-most bit of the original value. Moreover, MACRO-10 considers bit 0 the left-most bit, and bit 35 the right-most bit. Last but not least, -*n* is always interpreted as a decimal value, regardless of the current base (radix). *n* can be converted to a shift count -by calculating (35 - n): if the count is positive, it's a left-shift, and if it's negative, it's a right-shift. +*n* is always interpreted as a decimal value, regardless of the current base (radix). + +*n* can be converted to a shift count by calculating (35 - n): if the count is positive, it's a left-shift, and if it's negative, +it's a right-shift. Here are some examples: >> print 1B0 0o400000000000 -34359738368. @@ -140,7 +142,7 @@ by calculating (35 - n): if the count is positive, it's a left-shift, and if it' 0o000000000001 1. And as the [MACRO-10 Assembler Programmer's Reference Manual (June 1972)](http://archive.pcjs.org/pubs/dec/pdp10/tops10/Macro_Assembler_Reference_Manual-Jun72.pdf), -p. 1-17, points out, all the following expressions are equivalent: +p. 1-17, points out, all of the following "binary shifting" expressions are equivalent: >> print 10B32 0o000000000100 64. '@' @@ -208,5 +210,80 @@ useful in assembling the following tests: - [KA10 Basic Instruction Diagnostic #4](/apps/pdp10/diags/klad/dakad/) - [Assorted MACRO-10 Mini-Assembler Tests](/apps/pdp10/tests/macro10/) +However, there's "*assembling*" and then there's "*assembling correctly*". One early problem I had to immediately +address was the handling of literals. I was originally collecting all the literal (square-bracketed) expressions, like the +**[ZZ]** in the following statement: + + MOVE [ZZ] ;MOVE THE CURRENT VALUE OF ZZ INTO E. ZZ IS NON-ZERO + +and processing them at the end of the first pass. Well, since ZZ is a symbol that changes repeatedly inside a REPEAT pseudo-op, it +became clear that I needed to process literals immediately. This meant creating a separate assembly scope while processing each +literal; in fact, it meant a stack of scopes, in case literals contained nested literals. + +As the [MACRO-10 Assembler Programmer's Reference Manual (April 1978)](http://archive.pcjs.org/pubs/dec/pdp10/tops10/Macro_Assembler_Reference_Manual-Apr78.pdf) +explains: + + A literal can include any term, symbol, expression, or statement, but + it must generate at least one but no more than 99 words of data. A + statement that does not generate data (such as a direct-assignment + statement or a RADIX pseudo-op) can be included in a literal, but the + literal must not consist entirely of such statements. + + You can nest literals up to 18 levels. You can include any number of + labels in a literal, but a forward reference to a label in a literal + is illegal. + + If you use a dot (.) in a literal to retrieve the location counter, + remember that the counter is pointing at the statement containing the + literal, not at the literal itself. + + In nested literals, a dot location counter references a statement + outside the outermost literal. + + In the sequence: + + JRST [HRRZ AC1,V + CAIE AC1,OP + JRST .+1 + JRST EVTSTS] + SKIPE C + + the expression .+1 generates the address of SKIPE C, not JRST EVTSTS. + + Literals having the same value are collapsed in MACRO's literal pool. + Thus for the statements: + + PUSH P,[0] + PUSH P,[0] + MOVEI AC1,[ASCIZ /TEST1/] + + the same address is shared by the two literals [0], and by the null + word generated at the end of [ASCIZ /TESTI/]. Literal collapsing is + suppressed for those literals that contain errors, undefined expressions, + or EXTERNAL symbols. + +Our Mini-Assembler doesn't enforce all the above requirements. It doesn't care if less than 1 or more +than 99 words of data are generated, and it doesn't care if you nest more than 18 levels. It does attempt to honor +MACRO-10's scoping rules for the dot (.) operator, however. + +There's also some ambiguity in the above documentation. For example, it says that a literal may contain "any +term, symbol, expression, or statement," but it's not clear if that includes labels. +And when they say that "a forward reference to a label in a literal is illegal," does that only apply to a label +defined *within* the literal, or to *any* forward reference? In other words, which element is illegal in a literal: +the forward reference, or the label? + +In any case, our assembler doesn't care, and it's now able to assemble a simple +[Nested Literal Test](/apps/pdp10/tests/macro10/#nested-literal-test) on the +[MACRO-10 Mini-Assembler Tests](/apps/pdp10/tests/macro10/) page. + +So, things are improving, but it's still too early expect a lot from the MACRO-10 Mini-Assembler. It currently supports +only a handful of pseudo-ops, and all the code and data it generates is intended for absolute loading only; for now, +it makes no distinction between relocatable and absolute addresses, and the **LOC** and **RELOC** pseudo-ops, like every +other unrecognized or unsupported opcode or pseudo-op, will simply generate an error. + +If that sounds like a joke, it's not. This, however, is: + +> A man walks into a bar, asks the bartender for a fixup, and the bartender responds, "Absolutely!" + *[@jeffpar](http://twitter.com/jeffpar)* *Mar 21, 2017* diff --git a/_posts/2017-03-24-stepping-through-pdp-10-diagnostica.md b/_posts/2017-03-24-stepping-through-pdp-10-diagnostica.md new file mode 100644 index 000000000..361b76fb6 --- /dev/null +++ b/_posts/2017-03-24-stepping-through-pdp-10-diagnostica.md @@ -0,0 +1,98 @@ +--- +layout: post +title: Stepping Through PDP-10 Diagnostics +date: 2017-03-24 22:00:00 +permalink: /blog/2017/03/24/ +machines: + - id: testka10 + type: pdp10 + config: /devices/pdp10/machine/ka10/test/debugger/machine.xml + debugger: true + commands: a 30724 /apps/pdp10/diags/klad/dakaa/MYDAKAA.MAC +--- + +Now that the PDPjs MACRO-10 Mini-Assembler is [limping along](/blog/2017/03/21/), it was time to start assembling some +of DEC's PDP-10 diagnostics and loading them into a test machine. The first diagnostic I tried was +[KA10 Basic Instruction Diagnostic #1 (MAINDEC-10-DAKAA-B-D)](/apps/pdp10/diags/klad/dakaa/), which has been loaded into +the machine below. + +{% include machine.html id="testka10" %} + +Here were the results of my first run attempt: + + >> a 30724 /apps/pdp10/diags/klad/dakaa/MYDAKAA.MAC + starting PCjs MACRO-10 Mini-Assembler... + loading MYDAKAA.MAC + CPU will not be auto-started (click Run to start) + 2844 words loaded at 030724-036357 + 00=000000000000 01=000000000000 02=000000000000 03=000000000000 + 04=000000000000 05=000000000000 06=000000000000 07=000000000000 + 10=000000000000 11=000000000000 12=000000000000 13=000000000000 + 14=000000000000 15=000000000000 16=000000000000 17=000000000000 + PC=030724 RA=00000000 EA=000000 C0=0 C1=0 OV=0 ND=0 PD=0 + 030724: 254000 030741 JRST 30741 + >> g + running + undefined opcode: 000000 + stopped (1698 instructions, 1697 cycles, 14 ms, 121214 hz) + 00=000000000000 01=000000000000 02=777777777777 03=000000000000 + 04=777777777777 05=000000000000 06=000000000000 07=777777777777 + 10=777777777777 11=000000000000 12=000000000000 13=000000000000 + 14=000000000000 15=000000000000 16=000000000000 17=000000000000 + PC=035057 RA=00000000 EA=000000 C0=0 C1=0 OV=0 ND=0 PD=0 + 035057: 000000 000000 UUO 0,0 + >> dh + 035044: 444000 036353 EQV 0,36353 ;history=10 + 035045: 332000 000000 SKIPE 0,0 ;history=9 + 035047: 324000 035050 JUMPA 0,35050 ;history=8 + 035050: 200000 036354 MOVE 0,36354 ;history=7 + 035051: 404000 036355 AND 0,36355 ;history=6 + 035052: 444000 036356 EQV 0,36356 ;history=5 + 035053: 444000 036357 EQV 0,36357 ;history=4 + 035054: 332000 000000 SKIPE 0,0 ;history=3 + 035056: 324000 035057 JUMPA 0,35057 ;history=2 + 035057: 000000 000000 UUO 0,0 ;history=1 + +Happily, this was a good outcome, because 035057 is the end of the test. If you look at the diagnostic's +[listing file](/apps/pdp10/diags/klad/dakaa/DAKAA.LST.txt), this is what you would normally see at address 035057: + + 035057 254 00 0 00 030057 ENDXX: JRST BEGEND ;LOOP PROGRAM + +Next, I tried [KA10 Basic Instruction Diagnostic #4 (MAINDEC-10-DAKAD-B-D)](/apps/pdp10/diags/klad/dakad/): + + >> a 30724 /apps/pdp10/diags/klad/dakad/MYDAKAD.MAC + starting PCjs MACRO-10 Mini-Assembler... + loading MYDAKAD.MAC + 1986 words loaded at 030724-034625 + 00=000000000000 01=000000000000 02=777777777777 03=000000000000 + 04=777777777777 05=000000000000 06=000000000000 07=777777777777 + 10=777777777777 11=000000000000 12=000000000000 13=000000000000 + 14=000000000000 15=000000000000 16=000000000000 17=000000000000 + PC=030724 RA=00000000 EA=000000 C0=0 C1=0 OV=0 ND=0 PD=0 + 030724: 254000 030741 JRST 30741 + >> g + running + stopped (450 instructions, 449 cycles, 8 ms, 56125 hz) + 00=000000000017 01=400000000000 02=000000000001 03=400000000000 + 04=000004000004 05=000005000005 06=000006000006 07=000007000007 + 10=000010000010 11=000011000011 12=000012000012 13=000013000013 + 14=000014000014 15=000015000015 16=000016000016 17=000017000017 + PC=032007 RA=00032007 EA=032007 C0=0 C1=0 OV=0 ND=0 PD=0 + 032007: 324000 032010 JUMPA 0,32010 + >> dh + 031774: 201100 000001 MOVEI 2,1 ;history=10 + 031775: 200142 000000 MOVE 3,0(2) ;history=9 + 031776: 312140 034461 CAME 3,34461 ;history=8 + 032000: 324000 032001 JUMPA 0,32001 ;history=7 + 032001: 476000 000003 SETOM 0,3 ;history=6 + 032002: 205040 400000 MOVSI 1,400000 ;history=5 + 032003: 201100 000001 MOVEI 2,1 ;history=4 + 032004: 200142 000000 MOVE 3,0(2) ;history=3 + 032005: 312140 034462 CAME 3,34462 ;history=2 + 032006: 254200 032007 HALT 32007 ;history=1 + +This looked less good. + + +*[@jeffpar](http://twitter.com/jeffpar)* +*Mar 24, 2017* diff --git a/apps/pdp10/tests/macro10/README.md b/apps/pdp10/tests/macro10/README.md index 0ec2df6cc..61e012e41 100644 --- a/apps/pdp10/tests/macro10/README.md +++ b/apps/pdp10/tests/macro10/README.md @@ -25,7 +25,7 @@ and pseudo-ops **IRPC**, **IFE**, **IFN**, and **EXP**. It generates 4 words of {% include machine.html id="testka10" %} -Assemble TEXT.MAC: +Assemble [TEXT.MAC](TEXT.MAC.txt): a 100 TEXT.MAC @@ -48,7 +48,7 @@ Dump the 4 assembled words with the command `db 100 l4`: 000102: 110111 112113 022 004 111 024 045 ..I.% 000103: 114000 000000 023 000 000 000 000 ..... -Source code from TEXT.MAC: +Source code from [TEXT.MAC](TEXT.MAC.txt): {% highlight text %} {% include_relative TEXT.MAC.txt %} @@ -56,11 +56,11 @@ Source code from TEXT.MAC: ### Nested Literal Test -Assemble NESTLIT.MAC: +Assemble [NESTLIT.MAC](NESTLIT.MAC.txt): a 100 NESTLIT.MAC -Source code from NESTLIT.MAC: +Source code from [NESTLIT.MAC](NESTLIT.MAC.txt): {% highlight text %} {% include_relative NESTLIT.MAC.txt %} diff --git a/modules/pdp10/lib/debugger.js b/modules/pdp10/lib/debugger.js index 57b1a7c67..06ace0387 100644 --- a/modules/pdp10/lib/debugger.js +++ b/modules/pdp10/lib/debugger.js @@ -1709,6 +1709,7 @@ class DebuggerPDP10 extends Debugger { */ if (opCode < 0) { sOperands = sOpcode + sOperands; + sOpcode = ""; opCode = 0; } } diff --git a/modules/pdp10/lib/macro10.js b/modules/pdp10/lib/macro10.js index e5796bb7c..317f83284 100644 --- a/modules/pdp10/lib/macro10.js +++ b/modules/pdp10/lib/macro10.js @@ -240,7 +240,7 @@ class Macro10 { * [4]: operand(s), if any * [5]: comment, if any */ - this.reLine = /^\s*([A-Z$%.?][0-9A-Z$%.]*:|)\s*([A-Z$%.][0-9A-Z$%.]*|)(\s*)([^;]+|)(;?[\s\S]*)/i; + this.reLine = /^[ \t]*([A-Z$%.?][0-9A-Z$%.]*:|)[ \t]*([A-Z$%.][0-9A-Z$%.]*|)([ \t]*)([^;]+|)(;?[\s\S]*)/i; this.macroCall = null; // the active macro being called, if any