Merge branch 'master' into gh-pages
This commit is contained in:
commit
ea61907f02
37 changed files with 22950 additions and 46978 deletions
|
|
@ -10,4 +10,5 @@ PDP-10 KLAD Diagnostic Tapes
|
|||
PCjs has archived selected files from [PDP-10 KLAD Diagnostics Sources](http://pdp-10.trailing-edge.com/klad_sources/index.html),
|
||||
including:
|
||||
|
||||
- [KA10 BASIC INSTRUCTION DIAGNOSTIC (MAINDEC-10-DAKAD-B-D)](dakad/)
|
||||
- [KA10 Basic Instruction Diagnostic #1 (MAINDEC-10-DAKAA-B-D)](dakaa/)
|
||||
- [KA10 Basic Instruction Diagnostic #4 (MAINDEC-10-DAKAD-B-D)](dakad/)
|
||||
|
|
|
|||
10131
apps/pdp10/tapes/diags/klad/dakaa/DAKAA.LST.txt
Normal file
10131
apps/pdp10/tapes/diags/klad/dakaa/DAKAA.LST.txt
Normal file
File diff suppressed because it is too large
Load diff
1042
apps/pdp10/tapes/diags/klad/dakaa/DAKAA.MAC.txt
Normal file
1042
apps/pdp10/tapes/diags/klad/dakaa/DAKAA.MAC.txt
Normal file
File diff suppressed because it is too large
Load diff
294
apps/pdp10/tapes/diags/klad/dakaa/README.md
Normal file
294
apps/pdp10/tapes/diags/klad/dakaa/README.md
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
---
|
||||
layout: page
|
||||
title: PDP-10 KA10 Basic Instruction Diagnostic #1
|
||||
permalink: /apps/pdp10/tapes/diags/klad/dakaa/
|
||||
machines:
|
||||
- id: testka10
|
||||
type: pdp10
|
||||
config: /devices/pdp10/machine/ka10/test/debugger/machine.xml
|
||||
debugger: true
|
||||
commands: a 30724 /apps/pdp10/tapes/diags/klad/dakaa/TEST.MAC
|
||||
---
|
||||
|
||||
PDP-10 KA10 Basic Instruction Diagnostic #1
|
||||
-------------------------------------------
|
||||
|
||||
The *PDP-10 KA10 Basic Instruction Diagnostic #1* (MAINDEC-10-DAKAA-B-D) test code has been extracted from
|
||||
[DAKAA.MAC](DAKAA.MAC.txt) [[original](http://pdp-10.trailing-edge.com/klad_sources/01/klad.sources/dakaam.mac.html)]
|
||||
for use with the [PDP-10 Test Machine with Debugger](/devices/pdp10/machine/ka10/test/debugger/) below.
|
||||
|
||||
Resources for this test include:
|
||||
|
||||
- [Instructions](#dakaatxt)
|
||||
- [History](#dakaahst)
|
||||
- [Source Code](#dakaamac) [[file](DAKAA.MAC.txt)]
|
||||
- [MACRO-10 Listing](#dakaalst) [[file](DAKAA.LST.txt)]
|
||||
- [Additional Information](#dakaaseq)
|
||||
|
||||
{% include machine.html id="testka10" %}
|
||||
|
||||
The Debugger's assemble ("a") command can be used to test the new built-in
|
||||
[MACRO-10 mini-assembler](/modules/pdp10/lib/macro10.js), which supports a subset
|
||||
of the [MACRO-10](http://archive.pcjs.org/pubs/dec/pdp10/tops10/02_1973AsmRef_macro.pdf) assembly language.
|
||||
This command:
|
||||
|
||||
a 30724 /apps/pdp10/tapes/diags/klad/dakaa/TEST.MAC
|
||||
|
||||
will automatically read the [TEST.MAC](TEST.MAC.txt) source file (a slightly modified copy of [DAKAA.MAC](DAKAA.MAC.txt)),
|
||||
assemble it, and then load the binary output at the specified address.
|
||||
|
||||
---
|
||||
|
||||
DAKAA.TXT
|
||||
---------
|
||||
|
||||
```
|
||||
MAINDEC-10-DAKAA
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
IDENTIFICATION
|
||||
--------------
|
||||
|
||||
PRODUCT CODE: MAINDEC-10-DAKAA-B-D
|
||||
|
||||
PRODUCT NAME: DECSYSTEM10 PDP-10 KA10 BASIC
|
||||
INSTRUCTION DIAGNOSTIC (1)
|
||||
|
||||
FUNCTION: BASIC INSTRUCTIONS
|
||||
|
||||
VERSION: 0.2
|
||||
|
||||
DATE RELEASED: JANUARY 1977
|
||||
|
||||
MAINTAINED BY: DIAGNOSTIC ENGINEERING GROUP
|
||||
|
||||
AUTHOR: JOHN R. KIRCHOFF
|
||||
|
||||
COPYRIGHT(C) 1976,1977
|
||||
DIGITAL EQUIPMENT CORPORATION
|
||||
MARLBORO, MASS. 01752
|
||||
|
||||
THIS SOFTWARE IS FURNISHED UNDER A LICENSE FOR USE ONLY
|
||||
ON A SINGLE COMPUTER SYSTEM AND MAY BE COPIED ONLY WITH
|
||||
THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE,
|
||||
OR ANY OTHER COPIES THEREOF, MAY NOT BE PROVIDED OR OTHERWISE
|
||||
MADE AVAILABLE TO ANY OTHER PERSON EXECPT FOR USE ON SUCH SYSTEM
|
||||
AND TO ONE WHO AGREES TO THESE LICENSE TERMS. TITLE TO AND
|
||||
OWNERSHIP OF THE SOFTWARE SHALL AT ALL TIMES REMAIN IN DEC.
|
||||
|
||||
THE INFORMATION IN THIS DOCUMENT IS SUBJECT TO CHANGE WITHOUT
|
||||
NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL
|
||||
EQUIPMENT CORPORATION.
|
||||
|
||||
DEC ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
|
||||
SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DEC.
|
||||
MAINDEC-10-DAKAA.TXT
|
||||
PAGE 2
|
||||
|
||||
|
||||
TABLE OF CONTENTS
|
||||
-----------------
|
||||
|
||||
1.0 ABSTRACT
|
||||
|
||||
2.0 REQUIREMENTS
|
||||
|
||||
2.1 EQUIPMENT
|
||||
|
||||
2.2 STORAGE
|
||||
|
||||
2.3 PRELIMINARY PROGRAMS
|
||||
|
||||
3.0 PROGRAM PROCEDURES
|
||||
|
||||
3.1 LOADING PROCEDURE
|
||||
|
||||
3.2 STARTING PROCEDURE
|
||||
|
||||
3.3 OPERATING PROCEDURE
|
||||
|
||||
4.0 ERRORS
|
||||
|
||||
5.0 ITERATION COUNTER
|
||||
|
||||
6.0 CYCLE TIME
|
||||
|
||||
7.0 OPERATIONAL VARIATIONS
|
||||
|
||||
8.0 MISCELLANEOUS
|
||||
|
||||
9.0 LISTING
|
||||
MAINDEC-10-DAKAA.TXT
|
||||
PAGE 3
|
||||
|
||||
|
||||
1.0 ABSTRACT
|
||||
|
||||
THIS PDP-10 KA10 BASIC INSTRUCTION DIAGNOSTIC IS THE FIRST IN A
|
||||
SERIES OF PDP-10 KA10 PROCESSOR DIAGNOSTICS. IT IS THE MOST
|
||||
BASIC OF THE PROCESSOR DIAGNOSTICS. THIS DIAGNOSTIC
|
||||
ASSUMES THE HALT INSTRUCTION AND THE COMPUTER CONSOLE
|
||||
TO BE OPERATIVE. IT MAKES NO FURTHER ASSUMPTIONS EXCEPT
|
||||
THAT IT IS LOADED INTO MEMORY CORRECTLY.
|
||||
|
||||
THE DIAGNOSTIC TESTS SOME OF THE MOVE AND SKIP INSTRUCTIONS.
|
||||
IT ALSO TESTS THE ADDERS AND OTHER LOGIC WITH AND, XOR, EQV,
|
||||
AND ALL BOOLE INSTRUCTIONS.
|
||||
|
||||
2.0 REQUIREMENTS
|
||||
|
||||
2.1 EQUIPMENT
|
||||
|
||||
A PDP-10 KA10 WITH A MINIMUM OF 32K OF MEMORY
|
||||
|
||||
PAPER TAPE READER
|
||||
DECTAPE (OPTIONAL)
|
||||
CONSOLE TELETYPE
|
||||
|
||||
2.2 STORAGE
|
||||
|
||||
THE PROGRAM RUNS WITHIN 32K OF MEMORY.
|
||||
|
||||
2.3 PRELIMINARY PROGRAMS
|
||||
|
||||
CONSOLE FUNCTIONS WORKING PROPERLY
|
||||
PAPER TAPE OR DECTAPE READ-IN WORKING PROPERLY
|
||||
MAINDEC-10-DAKAA.TXT
|
||||
PAGE 4
|
||||
|
||||
|
||||
3.0 PROGRAM PROCEDURES
|
||||
|
||||
3.1 LOADING PROCEDURE
|
||||
|
||||
PAPER TAPE - HARDWARE READ-IN (READER DEVICE CODE 104)
|
||||
DECTAPE - LOAD WITH DIAMON (DECTAPE DEVICE CODE 320)
|
||||
|
||||
3.2 STARTING PROCEDURE
|
||||
|
||||
STAND-ALONE STARTING ADDRESS IS 30000.
|
||||
|
||||
IF THE DIAGNOSTIC FAILS TO START CORRECTLY TRY STARTING AT THE
|
||||
FIRST TEST INSTEAD OF AT THE BEGINNING OF THE CONTROL SEQUENCE.
|
||||
(SEE LISTING).
|
||||
|
||||
3.3 OPERATING PROCEDURE
|
||||
|
||||
ONCE STARTED THE PROGRAM WILL CYCLE CONTINUALLY UNTIL STOPPED
|
||||
OR AN ERROR OCCURS.
|
||||
|
||||
4.0 ERRORS
|
||||
|
||||
ERRORS ARE IN THE FORM OF HALT INSTRUCTIONS. THE LISTING
|
||||
SHOULD BE CONSULTED TO DETERMINE THE CAUSE OF THE ERROR. A
|
||||
NO OPERATION (JUMP) INSTRUCTION FOLLOWS EACH HALT. THIS
|
||||
MAY BE USEFUL IN CONSTRUCTING A SCOPE LOOP TO CYCLE ON THE
|
||||
FAILING INSTRUCTION.
|
||||
|
||||
5.0 ITERATION COUNTER
|
||||
|
||||
THE ITERATION COUNT OF THE PROGRAM IS DISPLAYED IN THE MEM-
|
||||
ORY INDICATORS (MI). THIS COUNT IS A DECREMENTING COUNT AND
|
||||
INITIALLY STARTS AT -1 IN STAND-ALONE OPERATION.
|
||||
|
||||
6.0 CYCLE TIME
|
||||
|
||||
THE CYCLE TIME OF THE PROGRAM IS IN THE MILLISECOND RANGE AND
|
||||
IS THEREFORE SUITABLE FOR TAKING MARGINS, VIBRATION TESTS, ETC.
|
||||
|
||||
MAINDEC-10-DAKAA.TXT
|
||||
PAGE 5
|
||||
|
||||
|
||||
7.0 OPERATIONAL VARIATIONS
|
||||
|
||||
A. DIAGNOSTIC MONITOR
|
||||
|
||||
THE PROGRAM IS USABLE WITH THE DIAGNOSTIC MONITOR TO PRO-
|
||||
VIDE RELIABILITY TESTS, ACCEPTANCE TESTS, AND/OR TO PRO-
|
||||
VIDE A QUICK METHOD OF ISOLATION OF A FAULT TO A PARTICULAR
|
||||
AREA OF THE PROCESSOR. CERTAIN PROCEDURES ARE USED WHEN
|
||||
THE PROGRAM IS USED IN THIS MANNER. THEY ARE:
|
||||
|
||||
1. THE DIAGNOSTIC MONITOR TRANSFERS CONTROL TO THE PRO-
|
||||
GRAM AND STARTS IT AT LOCATION 30002.
|
||||
|
||||
2. MONCTL - LOCATION 30043 IS USED AS THE DIAGNOSTIC MON-
|
||||
ITOR CONTROL FLAG WORD.
|
||||
|
||||
B. USER MODE
|
||||
|
||||
THE PROGRAM WILL OPERATE IN USER MODE AND AS SUCH PROVIDES
|
||||
ASSURANCE THAT THE PROCESSOR IS PERFORMING ALL FUNCTIONS
|
||||
CORRECTLY. USER MODE STARTING ADDRESS IS 30000.
|
||||
|
||||
C. SYSTEM EXERCISER
|
||||
|
||||
STARTING ADDRESS IS 30003. NO DATA SWITCHES ARE USED BY
|
||||
THIS PROGRAM.
|
||||
|
||||
8.0 MISCELLANEOUS
|
||||
|
||||
NONE
|
||||
|
||||
9.0 LISTING
|
||||
|
||||
```
|
||||
|
||||
DAKAA.HST
|
||||
---------
|
||||
|
||||
```
|
||||
THIS IS A HISTORY OF THE DEVELOPMENT OF MAINDEC-10-DAKAA
|
||||
|
||||
************************************************************************
|
||||
|
||||
PRODUCT CODE: MAINDEC-10-DAKAA
|
||||
|
||||
PRODUCT NAME: BASIC INSTRUCTION DIAGNOSTIC #1
|
||||
|
||||
DATE RELEASED: JANUARY 1977
|
||||
|
||||
VERSION: 0.2
|
||||
|
||||
UPDATE AUTHOR: JOHN R. KIRCHOFF
|
||||
|
||||
CHANGES MADE:
|
||||
|
||||
1. UPGRADE TO ALLOW COMPATABILITY WITH THE SUBROUTINE PACKAGE.
|
||||
|
||||
************************************************************************
|
||||
|
||||
ORIGINAL VERSION: 0.1
|
||||
|
||||
ORIGINAL AUTHOR: RICHARD MALISKA
|
||||
|
||||
ORIGINAL RELEASE: 16-MAR-72
|
||||
|
||||
************************************************************************
|
||||
```
|
||||
|
||||
DAKAA.MAC
|
||||
---------
|
||||
|
||||
{% highlight text %}
|
||||
{% include_relative DAKAA.MAC.txt %}
|
||||
{% endhighlight %}
|
||||
|
||||
DAKAA.LST
|
||||
---------
|
||||
|
||||
{% highlight text %}
|
||||
{% include_relative DAKAA.LST.txt %}
|
||||
{% endhighlight %}
|
||||
|
||||
DAKAA.SEQ
|
||||
---------
|
||||
|
||||
To view the contents of **DAKAA.SEQ**, the source of all the above information, click
|
||||
[here](http://archive.pcjs.org/apps/pdp10/tapes/diags/klad/dakaa/DAKAA.SEQ.txt).
|
||||
1054
apps/pdp10/tapes/diags/klad/dakaa/TEST.MAC.txt
Normal file
1054
apps/pdp10/tapes/diags/klad/dakaa/TEST.MAC.txt
Normal file
File diff suppressed because it is too large
Load diff
7993
apps/pdp10/tapes/diags/klad/dakad/DAKAD.LST.txt
Normal file
7993
apps/pdp10/tapes/diags/klad/dakad/DAKAD.LST.txt
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,12 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml-stylesheet type="text/xsl" href="/versions/pdpjs/1.34.2/machine.xsl"?>
|
||||
<machine id="testka10" type="pdp10" border="1" pos="center" background="#FAEBD7">
|
||||
<name pos="center">PDP-10 Test Machine with Debugger</name>
|
||||
<name pos="center">PDP-10 (Model KA10) with Debugger</name>
|
||||
<computer id="computer" busWidth="18"/>
|
||||
<cpu id="cpu" model="1001" cycles="1000000"/>
|
||||
<ram id="ram" addr="0x0000" size="0x4000" file="/apps/pdp10/tests/optest-v01.json"/>
|
||||
<device id="default" type="default"/>
|
||||
<serial id="serial" adapter="0" binding="print" upperCase="true"/>
|
||||
<panel ref="/devices/pdp10/panel/test/debugger/terminal.xml"/>
|
||||
<debugger id="debugger" base="8" messages='' commands='a 100 "/apps/pdp10/tapes/diags/klad/dakad/TEST.MAC"'/>
|
||||
<panel ref="/devices/pdp10/panel/ka10/debugger/front.xml"/>
|
||||
<debugger id="debugger" base="8" messages='' commands=''/>
|
||||
</machine>
|
||||
|
|
|
|||
|
|
@ -7,4 +7,5 @@ permalink: /devices/pdp11/panel/
|
|||
PDP-10 Control Panels
|
||||
---------------------
|
||||
|
||||
* [KA10 Front Panels](ka10/)
|
||||
* [Terminal Test Panels](test/)
|
||||
|
|
|
|||
10
devices/pdp10/panel/ka10/README.md
Normal file
10
devices/pdp10/panel/ka10/README.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
layout: page
|
||||
title: "PDP-10 (Model KA10) Front Panels"
|
||||
permalink: /devices/pdp10/panel/ka10/
|
||||
---
|
||||
|
||||
PDP-10 (Model KA10) Front Panels
|
||||
--------------------------------
|
||||
|
||||
* [Front Panel with Debugger](debugger/)
|
||||
10
devices/pdp10/panel/ka10/debugger/README.md
Normal file
10
devices/pdp10/panel/ka10/debugger/README.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
layout: page
|
||||
title: "PDP-10 (Model KA10) Front Panel with Debugger"
|
||||
permalink: /devices/pdp10/panel/ka10/debugger/
|
||||
---
|
||||
|
||||
PDP-10 (Model KA10) Front Panel with Debugger
|
||||
--------------------------------------------
|
||||
|
||||
* [Front Panel with Debugger](front.xml)
|
||||
84
devices/pdp10/panel/ka10/debugger/front.xml
Normal file
84
devices/pdp10/panel/ka10/debugger/front.xml
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<panel id="panel" width="100%" padding="8px">
|
||||
<name>Control Panel</name>
|
||||
<control type="container" class="pcjs-panel-group" width="100%" padBottom="8px">
|
||||
<control type="container" class="pcjs-triplet" width="9.3%" pos="right">
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">STRT</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">STEP</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">E/H</control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="START" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="STEP" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="ENABLE" width="100%" container="center"/></control>
|
||||
</control>
|
||||
<control type="container" class="pcjs-triplet" width="9.3%" pos="right">
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">CONT</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">DEP</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">EXAM</control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="CONT" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="DEP" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="EXAM" width="100%" container="center"/></control>
|
||||
</control>
|
||||
<control type="container" class="pcjs-triplet" width="6.2%" pos="right">
|
||||
<control type="container" class="pcjs-swlbl" width="50%" pos="right">LOAD</control>
|
||||
<control type="container" class="pcjs-swlbl" width="50%" pos="right">TEST</control>
|
||||
<control type="container" class="pcjs-swpad" width="50%" pos="right" style="clear:both;"><control type="switch" binding="LOAD" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="50%" pos="right"><control type="switch" binding="TEST" width="100%" container="center"/></control>
|
||||
</control>
|
||||
<control type="container" class="pcjs-triplet" width="9.3%" pos="right">
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">17</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">16</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">15</control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S17" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S16" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S15" width="100%" container="center"/></control>
|
||||
</control>
|
||||
<control type="container" class="pcjs-triplet" width="9.3%" pos="right">
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">14</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">13</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">12</control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S14" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S13" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S12" width="100%" container="center"/></control>
|
||||
</control>
|
||||
<control type="container" class="pcjs-triplet" width="9.3%" pos="right">
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">11</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">10</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">9</control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S11" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S10" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S9" width="100%" container="center"/></control>
|
||||
</control>
|
||||
<control type="container" class="pcjs-triplet" width="9.3%" pos="right">
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">8</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">7</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">6</control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S8" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S7" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S6" width="100%" container="center"/></control>
|
||||
</control>
|
||||
<control type="container" class="pcjs-triplet" width="9.3%" pos="right">
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">5</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">4</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">3</control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S5" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S4" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S3" width="100%" container="center"/></control>
|
||||
</control>
|
||||
<control type="container" class="pcjs-triplet" width="9.3%" pos="right">
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">2</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">1</control>
|
||||
<control type="container" class="pcjs-swlbl" width="33%" pos="right">0</control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S2" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S1" width="100%" container="center"/></control>
|
||||
<control type="container" class="pcjs-swpad" width="33%" pos="right"><control type="switch" binding="S10" width="100%" container="center"/></control>
|
||||
</control>
|
||||
</control>
|
||||
<control type="container" class="pcjs-textarea" width="100%" padBottom="8px">
|
||||
<control type="textarea" binding="print" width="100%" height="340px" padRight="8px" pos="relative" style="resize:vertical;"/>
|
||||
<control type="container" width="100%">
|
||||
<control type="text" binding="debugInput" width="auto"/>
|
||||
<control type="button" binding="debugEnter">Enter</control>
|
||||
<control type="button" binding="clear">Clear</control>
|
||||
</control>
|
||||
</control>
|
||||
</panel>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -959,7 +959,7 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* parseAddr(sAddr, fCode, fNoChecks, fPrint)
|
||||
* parseAddr(sAddr, fCode, fNoChecks)
|
||||
*
|
||||
* Address evaluation and validation (eg, range checks) are no longer performed at this stage. That's
|
||||
* done later, by getAddr(), which returns CPUDef.ADDR_INVALID for invalid segments, out-of-range offsets,
|
||||
|
|
@ -972,10 +972,9 @@ if (DEBUGGER) {
|
|||
* @param {string|undefined} sAddr
|
||||
* @param {boolean} [fCode] (true if target is code, false if target is data)
|
||||
* @param {boolean} [fNoChecks] (true when setting breakpoints that may not be valid now, but will be later)
|
||||
* @param {boolean} [fPrint]
|
||||
* @return {DbgAddr6502|null|undefined}
|
||||
*/
|
||||
Debugger6502.prototype.parseAddr = function(sAddr, fCode, fNoChecks, fPrint)
|
||||
Debugger6502.prototype.parseAddr = function(sAddr, fCode, fNoChecks)
|
||||
{
|
||||
var dbgAddr;
|
||||
var dbgAddrNext = (fCode? this.dbgAddrNextCode : this.dbgAddrNextData);
|
||||
|
|
@ -984,7 +983,7 @@ if (DEBUGGER) {
|
|||
sAddr = this.parseReference(sAddr);
|
||||
dbgAddr = this.findSymbolAddr(sAddr);
|
||||
if (dbgAddr) return dbgAddr;
|
||||
addr = this.parseExpression(sAddr, fPrint);
|
||||
addr = this.parseExpression(sAddr);
|
||||
}
|
||||
if (addr != null) {
|
||||
dbgAddr = this.newAddr(addr);
|
||||
|
|
@ -3801,7 +3800,7 @@ if (DEBUGGER) {
|
|||
sCmd = str.trim(sCmd);
|
||||
var a = sCmd.match(/^(['"])(.*?)\1$/);
|
||||
if (!a) {
|
||||
this.parseExpression(sCmd, true);
|
||||
this.parseExpression(sCmd, false);
|
||||
} else {
|
||||
this.println(this.replaceRegs(a[2]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -473,7 +473,7 @@ class Debugger8080 extends Debugger {
|
|||
}
|
||||
|
||||
/**
|
||||
* parseAddr(sAddr, fCode, fNoChecks, fPrint)
|
||||
* parseAddr(sAddr, fCode, fNoChecks)
|
||||
*
|
||||
* Address evaluation and validation (eg, range checks) are no longer performed at this stage. That's
|
||||
* done later, by getAddr(), which returns CPUDef8080.ADDR_INVALID for invalid segments, out-of-range offsets,
|
||||
|
|
@ -486,10 +486,9 @@ class Debugger8080 extends Debugger {
|
|||
* @param {string|undefined} sAddr
|
||||
* @param {boolean} [fCode] (true if target is code, false if target is data)
|
||||
* @param {boolean} [fNoChecks] (true when setting breakpoints that may not be valid now, but will be later)
|
||||
* @param {boolean} [fPrint]
|
||||
* @return {DbgAddr8080|null|undefined}
|
||||
*/
|
||||
parseAddr(sAddr, fCode, fNoChecks, fPrint)
|
||||
parseAddr(sAddr, fCode, fNoChecks)
|
||||
{
|
||||
var dbgAddr;
|
||||
var dbgAddrNext = (fCode? this.dbgAddrNextCode : this.dbgAddrNextData);
|
||||
|
|
@ -498,7 +497,7 @@ class Debugger8080 extends Debugger {
|
|||
sAddr = this.parseReference(sAddr) || sAddr;
|
||||
dbgAddr = this.findSymbolAddr(sAddr);
|
||||
if (dbgAddr) return dbgAddr;
|
||||
addr = this.parseExpression(sAddr, fPrint);
|
||||
addr = this.parseExpression(sAddr);
|
||||
}
|
||||
if (addr != null) {
|
||||
dbgAddr = this.newAddr(addr);
|
||||
|
|
@ -3337,7 +3336,7 @@ class Debugger8080 extends Debugger {
|
|||
sCmd = Str.trim(sCmd);
|
||||
var a = sCmd.match(/^(['"])(.*?)\1$/);
|
||||
if (!a) {
|
||||
this.parseExpression(sCmd, true);
|
||||
this.parseExpression(sCmd, false);
|
||||
} else {
|
||||
this.println(this.replaceRegs(a[2]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1375,7 +1375,7 @@ class DebuggerX86 extends Debugger {
|
|||
}
|
||||
|
||||
/**
|
||||
* parseAddr(sAddr, fCode, fNoChecks, fPrint)
|
||||
* parseAddr(sAddr, fCode, fNoChecks, fQuiet)
|
||||
*
|
||||
* As discussed above, dbgAddr variables contain one or more of: off, sel, and addr. They represent
|
||||
* a segmented address (sel:off) when sel is defined or a linear address (addr) when sel is undefined
|
||||
|
|
@ -1400,10 +1400,10 @@ class DebuggerX86 extends Debugger {
|
|||
* @param {string|undefined} sAddr
|
||||
* @param {boolean} [fCode] (true if target is code, false if target is data)
|
||||
* @param {boolean} [fNoChecks] (true when setting breakpoints that may not be valid now, but will be later)
|
||||
* @param {boolean} [fPrint]
|
||||
* @param {boolean} [fQuiet]
|
||||
* @return {DbgAddrX86|null|undefined}
|
||||
*/
|
||||
parseAddr(sAddr, fCode, fNoChecks, fPrint)
|
||||
parseAddr(sAddr, fCode, fNoChecks, fQuiet)
|
||||
{
|
||||
var dbgAddr;
|
||||
var dbgAddrNext = (fCode? this.dbgAddrNextCode : this.dbgAddrNextData);
|
||||
|
|
@ -1451,16 +1451,16 @@ class DebuggerX86 extends Debugger {
|
|||
|
||||
if (iColon < 0) {
|
||||
if (sel != null) {
|
||||
off = this.parseExpression(sAddr, fPrint);
|
||||
off = this.parseExpression(sAddr, fQuiet);
|
||||
addr = null;
|
||||
} else {
|
||||
addr = this.parseExpression(sAddr, fPrint);
|
||||
addr = this.parseExpression(sAddr, fQuiet);
|
||||
if (addr == null) off = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sel = this.parseExpression(sAddr.substring(0, iColon), fPrint);
|
||||
off = this.parseExpression(sAddr.substring(iColon + 1), fPrint);
|
||||
sel = this.parseExpression(sAddr.substring(0, iColon), fQuiet);
|
||||
off = this.parseExpression(sAddr.substring(iColon + 1), fQuiet);
|
||||
addr = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1598,7 +1598,7 @@ class DebuggerX86 extends Debugger {
|
|||
var sInfo = "no information";
|
||||
if (BACKTRACK) {
|
||||
var sAddr = asArgs[0];
|
||||
var dbgAddr = this.parseAddr(sAddr, true, true, false);
|
||||
var dbgAddr = this.parseAddr(sAddr, true, true, true);
|
||||
if (dbgAddr) {
|
||||
var addr = this.getAddr(dbgAddr);
|
||||
if (dbgAddr.type != DebuggerX86.ADDRTYPE.PHYSICAL) {
|
||||
|
|
@ -5907,7 +5907,7 @@ class DebuggerX86 extends Debugger {
|
|||
sCmd = Str.trim(sCmd);
|
||||
var a = sCmd.match(/^(['"])(.*?)\1$/);
|
||||
if (!a) {
|
||||
this.parseExpression(sCmd, true);
|
||||
this.parseExpression(sCmd, false);
|
||||
} else {
|
||||
this.println(this.replaceRegs(a[2]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ The module is currently comprised of the following components, as listed in [pac
|
|||
* [bus.js](/modules/pdp10/lib/bus.js)
|
||||
* [computer.js](/modules/pdp10/lib/computer.js)
|
||||
* [cpu.js](/modules/pdp10/lib/cpu.js)
|
||||
* [cpuop.js](/modules/pdp10/lib/cpuop.js)
|
||||
* [cpuops.js](/modules/pdp10/lib/cpuops.js)
|
||||
* [cpustate.js](/modules/pdp10/lib/cpustate.js)
|
||||
* [debugger.js](/modules/pdp10/lib/debugger.js)
|
||||
* [defines.js](/modules/pdp10/lib/defines.js)
|
||||
|
|
|
|||
|
|
@ -2232,7 +2232,31 @@ PDP10.opAOBJN = function(op, acc)
|
|||
*/
|
||||
PDP10.opJRST = function(op, acc)
|
||||
{
|
||||
if (acc & 0b0001) {
|
||||
/*
|
||||
* Enter user mode.
|
||||
*/
|
||||
this.setUserMode();
|
||||
}
|
||||
if (acc & 0b0010) {
|
||||
/*
|
||||
* Restore the flags.
|
||||
*/
|
||||
this.setPS(this.regLA);
|
||||
}
|
||||
if (acc & 0b0100) {
|
||||
/*
|
||||
* Halt the processor.
|
||||
*/
|
||||
this.stopCPU();
|
||||
}
|
||||
if (acc & 0b1000) {
|
||||
/*
|
||||
* Restore interrupt channel.
|
||||
*/
|
||||
this.opUndefined(op);
|
||||
}
|
||||
this.setPC(this.regEA);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -6378,8 +6402,11 @@ PDP10.split72 = function(res, ext)
|
|||
PDP10.setAddFlags = function(dst, src, res)
|
||||
{
|
||||
/*
|
||||
* Isolate the top two bits of dst, src, and res by "shifting" them into bits 0 and 1 of the following variables.
|
||||
* Isolate the top two bits of dst, src, and res by "shifting" them into bits 0 and 1 of the
|
||||
* following variables. Note that shifting with division only works when the values are unsigned
|
||||
* (which they MUST be).
|
||||
*/
|
||||
Component.assert(dst >= 0 && src >= 0 && res >= 0);
|
||||
var dst01 = Math.trunc(dst / PDP10.TWO_POW34);
|
||||
var src01 = Math.trunc(src / PDP10.TWO_POW34);
|
||||
var res01 = Math.trunc(res / PDP10.TWO_POW34);
|
||||
|
|
@ -6440,7 +6467,11 @@ PDP10.AND = function(dst, src)
|
|||
* WARNING: When using JavaScript's 32-bit operators with values that could set bit 31 and produce a
|
||||
* negative value, it's critical to perform a final right-shift of 0, ensuring that the final result is
|
||||
* positive.
|
||||
*
|
||||
* Finally, all 36-bit data within a PDP-10 machine should ALWAYS be unsigned, which we now assert,
|
||||
* because the divisions below would not yield correct results with negative inputs.
|
||||
*/
|
||||
Component.assert(dst >= 0 && src >= 0);
|
||||
return ((((dst / PDP10.TWO_POW32)|0) & ((src / PDP10.TWO_POW32)|0)) * PDP10.TWO_POW32) + ((dst & src) >>> 0);
|
||||
};
|
||||
|
||||
|
|
@ -6491,7 +6522,11 @@ PDP10.EQV = function(dst, src)
|
|||
* WARNING: When using JavaScript's 32-bit operators with values that could set bit 31 and produce a
|
||||
* negative value, it's critical to perform a final right-shift of 0, ensuring that the final result is
|
||||
* positive.
|
||||
*
|
||||
* Finally, all 36-bit data within a PDP-10 machine should ALWAYS be unsigned, which we now assert,
|
||||
* because the divisions below would not yield correct results with negative inputs.
|
||||
*/
|
||||
Component.assert(dst >= 0 && src >= 0);
|
||||
return ((~(((dst / PDP10.TWO_POW32)|0) ^ ((src / PDP10.TWO_POW32)|0)) & 0o17) * PDP10.TWO_POW32) + (~(dst ^ src) >>> 0);
|
||||
};
|
||||
|
||||
|
|
@ -6514,7 +6549,11 @@ PDP10.IOR = function(dst, src)
|
|||
* WARNING: When using JavaScript's 32-bit operators with values that could set bit 31 and produce a
|
||||
* negative value, it's critical to perform a final right-shift of 0, ensuring that the final result is
|
||||
* positive.
|
||||
*
|
||||
* Finally, all 36-bit data within a PDP-10 machine should ALWAYS be unsigned, which we now assert,
|
||||
* because the divisions below would not yield correct results with negative inputs.
|
||||
*/
|
||||
Component.assert(dst >= 0 && src >= 0);
|
||||
return ((((dst / PDP10.TWO_POW32)|0) | ((src / PDP10.TWO_POW32)|0)) * PDP10.TWO_POW32) + ((dst | src) >>> 0);
|
||||
};
|
||||
|
||||
|
|
@ -6536,7 +6575,11 @@ PDP10.NOT = function(src)
|
|||
* WARNING: When using JavaScript's 32-bit operators with values that could set bit 31 and produce a
|
||||
* negative value, it's critical to perform a final right-shift of 0, ensuring that the final result is
|
||||
* positive.
|
||||
*
|
||||
* Finally, all 36-bit data within a PDP-10 machine should ALWAYS be unsigned, which we now assert,
|
||||
* because the divisions below would not yield correct results with negative inputs.
|
||||
*/
|
||||
Component.assert(src >= 0);
|
||||
return ((~((src / PDP10.TWO_POW32)|0) & 0o17) * PDP10.TWO_POW32) + (~src >>> 0);
|
||||
};
|
||||
|
||||
|
|
@ -6572,7 +6615,11 @@ PDP10.XOR = function(dst, src)
|
|||
* WARNING: When using JavaScript's 32-bit operators with values that could set bit 31 and produce a
|
||||
* negative value, it's critical to perform a final right-shift of 0, ensuring that the final result is
|
||||
* positive.
|
||||
*
|
||||
* Finally, all 36-bit data within a PDP-10 machine should ALWAYS be unsigned, which we now assert,
|
||||
* because the divisions below would not yield correct results with negative inputs.
|
||||
*/
|
||||
Component.assert(dst >= 0 && src >= 0);
|
||||
return ((((dst / PDP10.TWO_POW32)|0) ^ ((src / PDP10.TWO_POW32)|0)) * PDP10.TWO_POW32) + ((dst ^ src) >>> 0);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -174,7 +174,12 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
*/
|
||||
initCPU()
|
||||
{
|
||||
this.regEA = this.regRA = this.regOP = 0;
|
||||
/*
|
||||
* regEA is the last effective address, while regLA is the last fetch from an effective address
|
||||
* calculation. regRA is the last reference address used to calculate the last effective address.
|
||||
*/
|
||||
this.regEA = this.regRA = 0;
|
||||
this.regLA = this.regOP = 0;
|
||||
this.regPC = this.lastPC = this.addrReset;
|
||||
this.regXC = -1; // if >= 0 this supersedes regPC (refers to an opcode from XCT)
|
||||
this.regBP = -1; // active byte pointer (-1 if none)
|
||||
|
|
@ -287,6 +292,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
state.set(0, [
|
||||
this.regEA,
|
||||
this.regRA,
|
||||
this.regLA,
|
||||
this.regOP,
|
||||
this.regPC,
|
||||
this.regXC,
|
||||
|
|
@ -320,6 +326,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
[
|
||||
this.regEA,
|
||||
this.regRA,
|
||||
this.regLA,
|
||||
this.regOP,
|
||||
this.regPC,
|
||||
this.regXC,
|
||||
|
|
@ -355,6 +362,38 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
return (this.regPS & PDP10.HALF_MASK) * PDP10.HALF_SHIFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* setPS(w)
|
||||
*
|
||||
* Sets the processor state flags in the format used by various program control operations (eg, JRST).
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} w
|
||||
*/
|
||||
setPS(w)
|
||||
{
|
||||
w = (w / PDP10.HALF_SHIFT)|0;
|
||||
this.regPS = (this.regPS & ~PDP10.PSFLAG.SET_MASK) | (w & PDP10.PSFLAG.SET_MASK);
|
||||
this.regPS |= (w & PDP10.PSFLAG.USER_MODE);
|
||||
if (!(w & PDP10.PSFLAG.USER_IO)) {
|
||||
this.regPS &= ~PDP10.PSFLAG.USER_IO;
|
||||
} else {
|
||||
if (!(this.regPS & PDP10.PSFLAG.USER_MODE)) this.regPS |= PDP10.PSFLAG.USER_IO;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setUserMode()
|
||||
*
|
||||
* Sets the processor's USER_MODE flag.
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
*/
|
||||
setUserMode()
|
||||
{
|
||||
this.regPS |= PDP10.PSFLAG.USER_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* readFlags()
|
||||
*
|
||||
|
|
@ -401,7 +440,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
getOpcode()
|
||||
{
|
||||
if ((this.regRA & PDP10.OPCODE.I_BIT)) {
|
||||
this.regRA = this.readWord(this.regEA);
|
||||
this.regRA = this.regLA = this.readWord(this.regEA);
|
||||
} else if (this.regXC >= 0) {
|
||||
this.regRA = this.regOP = this.readWord(this.regXC);
|
||||
this.regXC = -1;
|
||||
|
|
@ -429,7 +468,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
*/
|
||||
this.regEA = this.regRA & PDP10.OPCODE.Y_MASK;
|
||||
var x = (this.regRA >> PDP10.OPCODE.X_SHIFT) & PDP10.OPCODE.X_MASK;
|
||||
if (x) this.regEA = (this.regEA + this.readWord(x)) & PDP10.ADDR_MASK;
|
||||
if (x) this.regEA = (this.regEA + (this.regLA = this.readWord(x))) & PDP10.ADDR_MASK;
|
||||
|
||||
return (this.regRA & PDP10.OPCODE.I_BIT)? -1 : ((this.regOP / PDP10.OPCODE.A_SCALE)|0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -331,11 +331,17 @@ class DebuggerPDP10 extends Debugger {
|
|||
this.nBusWidth = bus.getWidth();
|
||||
|
||||
/*
|
||||
* Re-initialize Debugger message support if necessary
|
||||
* Override the Debugger's message configuration if specified.
|
||||
*/
|
||||
var sMessages = /** @type {string|undefined} */ (cmp.getMachineParm('messages'));
|
||||
if (sMessages) this.messageInit(sMessages);
|
||||
|
||||
/*
|
||||
* Override the Debugger's initialization commands if specified.
|
||||
*/
|
||||
var sCommands = /** @type {string|undefined} */ (cmp.getMachineParm('commands'));
|
||||
if (sCommands) this.sInitCommands = sCommands;
|
||||
|
||||
/*
|
||||
* Update aOpReserved as appropriate for the current model
|
||||
*/
|
||||
|
|
@ -502,7 +508,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
}
|
||||
|
||||
/**
|
||||
* parseAddr(sAddr, dbgAddr, fPrint)
|
||||
* parseAddr(sAddr, dbgAddr)
|
||||
*
|
||||
* Address evaluation and validation (eg, range checks) are no longer performed at this stage. That's
|
||||
* done later, by getAddr(), which returns PDP10.ADDR_INVALID for invalid segments, out-of-range offsets,
|
||||
|
|
@ -514,10 +520,9 @@ class DebuggerPDP10 extends Debugger {
|
|||
* @this {DebuggerPDP10}
|
||||
* @param {string|undefined} sAddr
|
||||
* @param {DbgAddrPDP10} [dbgAddr]
|
||||
* @param {boolean} [fPrint]
|
||||
* @return {DbgAddrPDP10|null|undefined}
|
||||
*/
|
||||
parseAddr(sAddr, dbgAddr, fPrint)
|
||||
parseAddr(sAddr, dbgAddr)
|
||||
{
|
||||
var fPhysical, nBase;
|
||||
if (!dbgAddr) dbgAddr = this.newAddr();
|
||||
|
|
@ -538,7 +543,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
} else if (sAddr.indexOf('.') >= 0) {
|
||||
nBase = 10;
|
||||
}
|
||||
addr = this.parseExpression(sAddr, fPrint);
|
||||
addr = this.parseExpression(sAddr);
|
||||
}
|
||||
if (addr != null) {
|
||||
addr = this.validateWord(addr, this.nBusWidth);
|
||||
|
|
@ -1547,14 +1552,13 @@ class DebuggerPDP10 extends Debugger {
|
|||
} else {
|
||||
n = (opCode >> PDP10.OPCODE.A_SHIFT) & PDP10.OPCODE.A_MASK;
|
||||
sOperand = this.toStrBase(n, -1);
|
||||
if (n) {
|
||||
for (var m = 0; m < DebuggerPDP10.ALTOPS.length; m++) {
|
||||
for (var m = 0; sOperand && m < DebuggerPDP10.ALTOPS.length; m++) {
|
||||
if (opNum == DebuggerPDP10.ALTOPS[m][0]) {
|
||||
var opAlt = DebuggerPDP10.ALTOPS[m][n];
|
||||
if (opAlt) {
|
||||
sOperation = DebuggerPDP10.OPNAMES[opAlt];
|
||||
sOperand = "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1611,19 +1615,27 @@ class DebuggerPDP10 extends Debugger {
|
|||
}
|
||||
|
||||
/**
|
||||
* parseInstruction(sOpcode, sOperands, addr)
|
||||
* parseInstruction(sOpcode, sOperands, addr, fQuiet)
|
||||
*
|
||||
* @this {DebuggerPDP10}
|
||||
* @param {string} sOpcode
|
||||
* @param {string} [sOperands]
|
||||
* @param {number} [addr] of memory where this instruction is being assembled
|
||||
* @param {boolean} [fQuiet]
|
||||
* @return {number} (opcode, or -1 if unrecognized instruction)
|
||||
*/
|
||||
parseInstruction(sOpcode, sOperands, addr)
|
||||
parseInstruction(sOpcode, sOperands, addr, fQuiet)
|
||||
{
|
||||
var opCode = -1;
|
||||
var opMask, opNum;
|
||||
|
||||
/*
|
||||
* It's best to always clear sUndefined up front, because the caller won't
|
||||
* necessarily know whether or not we had to call parseExpression() for this
|
||||
* instruction.
|
||||
*/
|
||||
this.sUndefined = null;
|
||||
|
||||
if (!sOpcode) {
|
||||
/*
|
||||
* MACRO-10 permits instructions to be assembled without an explicit opcode;
|
||||
|
|
@ -1700,7 +1712,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
var sOperand = aOperands[i].trim();
|
||||
if (!sOperand) continue;
|
||||
if (i > 1) {
|
||||
this.println("too many operands: " + sOperand);
|
||||
this.println("too many operands: " + sOperands);
|
||||
opCode = -1;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1722,7 +1734,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
sOperand = sOperand.replace(/(^|[^0-9])\./g, "$1" + this.toStrOffset(addr));
|
||||
}
|
||||
}
|
||||
var operand = this.parseExpression(sOperand);
|
||||
var operand = this.parseExpression(sOperand, fQuiet);
|
||||
if (operand == undefined) {
|
||||
opCode = -1;
|
||||
break;
|
||||
|
|
@ -1751,7 +1763,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
opCode += operand;
|
||||
sOperand = match[3];
|
||||
if (sOperand) {
|
||||
operand = this.parseExpression(sOperand);
|
||||
operand = this.parseExpression(sOperand, fQuiet);
|
||||
if (operand == undefined) {
|
||||
opCode = -1;
|
||||
break;
|
||||
|
|
@ -1774,7 +1786,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
// }
|
||||
}
|
||||
|
||||
if (opCode < 0 && sOperands != null) {
|
||||
if (opCode < 0 && !fQuiet) {
|
||||
this.println("unknown instruction: " + sOpcode + ' ' + sOperands);
|
||||
}
|
||||
|
||||
|
|
@ -2469,20 +2481,20 @@ class DebuggerPDP10 extends Debugger {
|
|||
*/
|
||||
loadBin(aWords, addrLoad)
|
||||
{
|
||||
/*
|
||||
* TODO: Decide what to do about addrLoad; either drop it or use it.
|
||||
*/
|
||||
var nWords = 0;
|
||||
var bus = this.bus;
|
||||
var dbg = this.dbg;
|
||||
aWords.forEach(function(w, addr) {
|
||||
bus.setWordDirect(addr, w);
|
||||
if (addrLoad == null) addrLoad = addr;
|
||||
nWords++;
|
||||
});
|
||||
if (!nWords) {
|
||||
this.println("no data");
|
||||
} else {
|
||||
this.println(nWords + " words loaded at " + this.toStrBase(addrLoad) + '-' + this.toStrBase(addrLoad + nWords - 1));
|
||||
this.cpu.setPC(addrLoad || 0);
|
||||
this.updateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2591,12 +2603,22 @@ class DebuggerPDP10 extends Debugger {
|
|||
dbg.println("assembly already in progress");
|
||||
}
|
||||
else {
|
||||
var sFile = match[2];
|
||||
var addrLoad = dbgAddr.addr;
|
||||
this.macro10 = new Macro10(match[2], addrLoad, sOptions, dbg, function doneMacro10(nErrorCode, sURL) {
|
||||
this.macro10 = new Macro10(sFile, addrLoad, sOptions, dbg, function doneMacro10(nErrorCode, sURL) {
|
||||
if (!nErrorCode) {
|
||||
/*
|
||||
* NOTE: Most Debugger operations run in the context of doCommand(), which catches any exceptions;
|
||||
* however, this callback may be running in a different context (eg, a network request callback), so
|
||||
* better safe than sorry.
|
||||
*/
|
||||
try {
|
||||
dbg.loadBin(dbg.macro10.getBin(), addrLoad);
|
||||
} catch(e) {
|
||||
dbg.println(e.message);
|
||||
}
|
||||
} else {
|
||||
dbg.println("error (" + nErrorCode + ") processing " + sURL);
|
||||
dbg.println("error (" + nErrorCode + ") processing " + (sURL || sFile));
|
||||
}
|
||||
dbg.macro10 = null;
|
||||
});
|
||||
|
|
@ -2834,7 +2856,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
|
||||
var size = (sCmd == "db"? 1 : 2);
|
||||
var nWords = len || 32;
|
||||
var nWordsPerLine = (size == 1? 2 : 4);
|
||||
var nWordsPerLine = (size == 1? 1 : 4);
|
||||
var nLines = (((nWords + nWordsPerLine - 1) / nWordsPerLine)|0) || 1;
|
||||
|
||||
var sDump = "";
|
||||
|
|
@ -2857,7 +2879,9 @@ class DebuggerPDP10 extends Debugger {
|
|||
var nBits = 7;
|
||||
var shift = 36 - nBits;
|
||||
for (var i = 0; size == 1 && shift >= 0; i++) {
|
||||
var c = ((w / Math.pow(2, shift)) % Math.pow(2, nBits)) + (nBits == 6? 0x20 : 0);
|
||||
var c = ((w / Math.pow(2, shift)) % Math.pow(2, nBits));
|
||||
sData += this.toStrBase(c, nBits);
|
||||
c += (nBits == 6? 0x20 : 0);
|
||||
sChars += (c < 0x20? '.' : String.fromCharCode(c));
|
||||
shift -= nBits;
|
||||
}
|
||||
|
|
@ -3318,7 +3342,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
sCmd = Str.trim(sCmd);
|
||||
var a = sCmd.match(/^(['"])(.*?)\1$/);
|
||||
if (!a) {
|
||||
this.parseExpression(sCmd, true);
|
||||
this.parseExpression(sCmd, false);
|
||||
} else {
|
||||
if (a[2].length > 1) {
|
||||
this.println(this.replaceRegs(a[2]));
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@ var PDP10 = {
|
|||
USER_IO: 0o004000, // User I/O
|
||||
FP_UNFL: 0o000100, // Floating-Point Underflow
|
||||
NO_DIVIDE: 0o000040, // No Divide
|
||||
SET_MASK: 0o760140, // the flags that are always settable/clearable
|
||||
/*
|
||||
* Only the low 18 bits (above) are returned by getPS(); the following (bits 18 to 31)
|
||||
* are defined for internal use only.
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ var Sym;
|
|||
/**
|
||||
* @typedef {{
|
||||
* nLocation:(number),
|
||||
* aValues:(Array.<string>),
|
||||
* sValue:(string)
|
||||
* }}
|
||||
*/
|
||||
var Fixup;
|
||||
|
|
@ -214,14 +214,22 @@ class Macro10 {
|
|||
this.done(this.parseFile());
|
||||
return;
|
||||
}
|
||||
|
||||
var macro10 = this;
|
||||
Web.getResource(this.asURLs[this.iURL++], null, true, function processMacro10(sURL, sResource, nErrorCode) {
|
||||
var sURL = this.asURLs[this.iURL++];
|
||||
|
||||
/*
|
||||
* We know that local resources ending with ".MAC" are actually stored with a ".txt" extension.
|
||||
*/
|
||||
if (sURL[0] == '/' && sURL.slice(-4) == ".MAC") sURL += ".txt";
|
||||
|
||||
Web.getResource(sURL, null, true, function processMacro10(sFile, sResource, nErrorCode) {
|
||||
if (nErrorCode) {
|
||||
macro10.done(nErrorCode, sURL);
|
||||
macro10.done(nErrorCode, sFile);
|
||||
return;
|
||||
}
|
||||
var sText = sResource;
|
||||
if (Str.endsWith(sURL, ".html")) {
|
||||
if (Str.endsWith(sFile, ".html")) {
|
||||
/*
|
||||
* We want to parse ONLY the text between <PRE>...</PRE> tags, and eliminate any HTML entities.
|
||||
*/
|
||||
|
|
@ -246,6 +254,8 @@ class Macro10 {
|
|||
/**
|
||||
* getBin()
|
||||
*
|
||||
* Service for the Debugger to obtain the data after a (hopefully) successful assembly process.
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @return {Array.<number>}
|
||||
*/
|
||||
|
|
@ -301,50 +311,14 @@ class Macro10 {
|
|||
}
|
||||
|
||||
this.aFixups.forEach(function processFixup(fixup){
|
||||
var value = 0;
|
||||
var sValue = fixup.aValues[0];
|
||||
var sOperand = fixup.aValues[1];
|
||||
var nLocation = fixup.nLocation;
|
||||
if (fixup.aValues.length == 1) {
|
||||
if (sValue.indexOf('@') >= 0 || sValue.indexOf('(') >= 0) {
|
||||
sOperand = sValue;
|
||||
sValue = "";
|
||||
}
|
||||
}
|
||||
if (sOperand != null) {
|
||||
value = macro10.dbg.parseInstruction(sValue, sOperand, nLocation);
|
||||
if (value < 0) {
|
||||
macro10.error("unable to parse instruction: " + fixup.aValues[0] + ' ' + fixup.aValues[1]);
|
||||
}
|
||||
} else {
|
||||
value = macro10.parseExpression(sValue, nLocation);
|
||||
var value = macro10.parseExpression(fixup.sValue, undefined, nLocation);
|
||||
if (value === undefined) {
|
||||
macro10.error("unable to parse expression: " + sValue);
|
||||
macro10.error("unable to parse expression: " + fixup.sValue);
|
||||
return;
|
||||
}
|
||||
else if (macro10.aWords[nLocation] === undefined) {
|
||||
macro10.error("undefined fixup location: " + Str.toOct(nLocation, 0, true));
|
||||
}
|
||||
else {
|
||||
value += macro10.aWords[nLocation];
|
||||
}
|
||||
}
|
||||
/*
|
||||
* At the end of the day, we only want unsigned 36-bit values, and some of our internal calculations
|
||||
* already adhere to that (eg, the parseExpression() concatenation of two unsigned 18-bit values).
|
||||
* But in general, the expression parser is allowed to return negative values, so that signed arithmetic
|
||||
* works naturally. Perhaps that decision should be revisited, but for now, this particular mix of
|
||||
* behaviors means that when checking for out-of-range values, the upper bound must be the unsigned
|
||||
* WORD_LIMIT, while the lower bound must be the signed INT_LIMIT.
|
||||
*
|
||||
* In a perfect world, the bounds would either be -INT_LIMIT,INT_LIMIT-1 or 0,WORD_LIMIT-1. In any
|
||||
* event, the truncate() call will ensure everything is an unsigned 36-bit value. The warning should
|
||||
* trigger only if the original value contained more than 36 significant bits.
|
||||
*/
|
||||
var w = macro10.dbg.truncate(value || 0, 36, true);
|
||||
if (value < -PDP10.INT_LIMIT || value >= PDP10.WORD_LIMIT) {
|
||||
macro10.warning("truncated value " + Str.toOct(value) + " at location " + Str.toOct(nLocation) + " to " + Str.toOct(w));
|
||||
}
|
||||
macro10.aWords[nLocation] = w;
|
||||
macro10.aWords[nLocation] = macro10.truncate(value, nLocation);
|
||||
});
|
||||
|
||||
} catch(err) {
|
||||
|
|
@ -384,7 +358,7 @@ class Macro10 {
|
|||
sLine = this.addASCII(sLine);
|
||||
}
|
||||
|
||||
var reLine = /\s*([A-Z$%._][0-9A-Z$%.]*[:=]|)\s*([A-Z$%.][0-9A-Z$%.]*|)\s*([^;]+|)\s*(;?.*)/i;
|
||||
var reLine = /\s*([A-Z$%._][0-9A-Z$%.]*[:=]|)\s*([A-Z$%.][0-9A-Z$%.]*|)\s*([^;]+|)(;?[\s\S]*)/i;
|
||||
var match = sLine.match(reLine);
|
||||
if (!match || match[4] && match[4].slice(0, 1) != ';') {
|
||||
this.error("failed to parse line: " + sLine);
|
||||
|
|
@ -394,7 +368,9 @@ class Macro10 {
|
|||
var sLabel = match[1];
|
||||
var sOperator = match[2].toUpperCase();
|
||||
var sOperands = match[3].trim();
|
||||
var sComment = match[4].slice(1);
|
||||
var sComment = match[4];
|
||||
var sRemainder = match[3] + match[4];
|
||||
|
||||
if (sLabel) {
|
||||
var chSep = sLabel.slice(-1);
|
||||
sLabel = sLabel.slice(0, -1);
|
||||
|
|
@ -406,8 +382,7 @@ class Macro10 {
|
|||
}
|
||||
}
|
||||
|
||||
this.sOperator = sOperator;
|
||||
sOperands = sOperands.trim();
|
||||
if (!sOperator && !sOperands) return true;
|
||||
|
||||
/*
|
||||
* My initial read of the MACRO-10 specification suggested that lines may begin with EITHER
|
||||
|
|
@ -418,6 +393,7 @@ class Macro10 {
|
|||
sOperands = sOperands.substr(1);
|
||||
sOperator = '=';
|
||||
}
|
||||
this.sOperator = sOperator;
|
||||
|
||||
/*
|
||||
* Check the operands for a literal. If the line contains and/or ends with a literal
|
||||
|
|
@ -440,12 +416,6 @@ class Macro10 {
|
|||
if (!this.parseMacro(sOperator, sOperands)) {
|
||||
|
||||
switch (sOperator) {
|
||||
case "":
|
||||
if (sOperands) {
|
||||
this.genWord(0, [sOperands]);
|
||||
}
|
||||
break;
|
||||
|
||||
case "=":
|
||||
this.addAssign(sLabel, sOperands);
|
||||
break;
|
||||
|
|
@ -453,7 +423,7 @@ class Macro10 {
|
|||
case Macro10.PSEUDO_OP.ASCII:
|
||||
case Macro10.PSEUDO_OP.ASCIZ:
|
||||
case Macro10.PSEUDO_OP.SIXBIT:
|
||||
this.addASCII(sOperands);
|
||||
this.addASCII(sRemainder);
|
||||
break;
|
||||
|
||||
case Macro10.PSEUDO_OP.XWD:
|
||||
|
|
@ -471,10 +441,7 @@ class Macro10 {
|
|||
break;
|
||||
|
||||
default:
|
||||
if (!this.parseOpcode(sOperator, sOperands)) {
|
||||
this.genWord(0, [sOperator + sOperands]);
|
||||
// if (DEBUG) this.println(Str.toDec(this.nLine, 5) + ": label(" + sLabel + ") operator(" + sOperator + ") operands(" + sOperands + ") comment(" + sComment + ")");
|
||||
}
|
||||
this.addWord(sOperator, sOperands);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -529,24 +496,6 @@ class Macro10 {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* parseOpcode(sOpcode, sOperands)
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {string} sOpcode
|
||||
* @param {string} sOperands
|
||||
* @return {boolean}
|
||||
*/
|
||||
parseOpcode(sOpcode, sOperands)
|
||||
{
|
||||
var opCode = this.dbg.parseInstruction(sOpcode);
|
||||
if (opCode >= 0) {
|
||||
this.genWord(opCode, [sOpcode, sOperands]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* isSymbolChar(ch)
|
||||
*
|
||||
|
|
@ -653,7 +602,7 @@ class Macro10 {
|
|||
}
|
||||
|
||||
/**
|
||||
* parseExpression(sOperand, nLocation)
|
||||
* parseExpression(sOperand, fPass1, nLocation)
|
||||
*
|
||||
* This is a wrapper around the Debugger's parseExpression() function to take care of some
|
||||
* additional requirements we have, such as interpreting a period as the current location and
|
||||
|
|
@ -662,19 +611,24 @@ class Macro10 {
|
|||
*
|
||||
* @this {Macro10}
|
||||
* @param {string} sOperand
|
||||
* @param {number} [nLocation]
|
||||
* @param {boolean|undefined} [fPass1]
|
||||
* @param {number|undefined} [nLocation]
|
||||
* @return {number|undefined}
|
||||
*/
|
||||
parseExpression(sOperand, nLocation)
|
||||
parseExpression(sOperand, fPass1, nLocation)
|
||||
{
|
||||
var result;
|
||||
|
||||
if (nLocation === undefined) nLocation = this.nLocation;
|
||||
|
||||
/*
|
||||
* Check for the "period" syntax that MACRO-10 uses to represent the value of the current
|
||||
* location. The Debugger's parseInstruction() method understands that syntax, but its
|
||||
* parseExpression() method does not.
|
||||
* Check for the "double comma" syntax that MACRO-10 uses to express a 36-bit value as two 18-bit halves,
|
||||
* and invoke ourselves recursively for each half.
|
||||
*/
|
||||
var match = sOperand.match(/^([^,]*),,([^,]*)$/);
|
||||
if (!match) {
|
||||
if (nLocation === undefined) nLocation = this.nLocation;
|
||||
/*
|
||||
* Check for the "period" syntax that MACRO-10 uses to represent the value of the current location.
|
||||
* The Debugger's parseInstruction() method understands that syntax, but its parseExpression() method
|
||||
* does not.
|
||||
*
|
||||
* Note that the Debugger's parseInstruction() replaces any period not PRECEDED by a decimal
|
||||
* digit with the current address, because our Debuggers' only other interpretation of a period
|
||||
|
|
@ -682,21 +636,17 @@ class Macro10 {
|
|||
* is (I think) as the decimal point within a floating-point number, so here we only replace
|
||||
* periods that are not FOLLOWED by a decimal digit.
|
||||
*/
|
||||
sOperand = sOperand.replace(/\.([^0-9]|$)/g, this.dbg.toStrBase(nLocation, -1) + "$1");
|
||||
|
||||
/*
|
||||
* Check for the "double comma" syntax that MACRO-10 uses to express a 36-bit value as two 18-bit halves.
|
||||
*/
|
||||
var match = sOperand.match(/^([^,]*),,([^,]*)$/);
|
||||
if (!match) {
|
||||
result = this.dbg.parseExpression(sOperand);
|
||||
result = this.dbg.parseExpression(sOperand.replace(/\.([^0-9]|$)/g, this.dbg.toStrBase(nLocation, -1) + "$1"), fPass1);
|
||||
if (result === undefined) {
|
||||
this.error("error parsing expression: " + sOperand);
|
||||
}
|
||||
} else {
|
||||
var wLeft = match[1]? this.dbg.parseExpression(match[1]) : 0;
|
||||
var wLeft = match[1]? this.parseExpression(match[1]) : 0;
|
||||
if (wLeft !== undefined) {
|
||||
var wRight = match[2]? this.dbg.parseExpression(match[2]) : 0;
|
||||
var wRight = match[2]? this.parseExpression(match[2]) : 0;
|
||||
if (wRight !== undefined) {
|
||||
/*
|
||||
* NOTE: These must be combined as UNSIGNED values, so that's what we tell truncate().
|
||||
* NOTE: These must be combined as UNSIGNED values, so that's what we tell truncate() to produce.
|
||||
*/
|
||||
result = this.dbg.truncate(wLeft, 18, true) * Math.pow(2, 18) + this.dbg.truncate(wRight, 18, true);
|
||||
}
|
||||
|
|
@ -880,6 +830,9 @@ class Macro10 {
|
|||
aParms = aDefaults = [];
|
||||
|
||||
if (sOperator == Macro10.PSEUDO_OP.DEFINE) {
|
||||
/*
|
||||
* This is a DEFINE (macro) block.
|
||||
*/
|
||||
match = sOperands.match(/([A-Z$%.][0-9A-Z$%.]*)\s*(\([^)]*\)|)\s*(<|)(.*)/i);
|
||||
if (!match) {
|
||||
this.error("unrecognized " + sOperator + " definition: " + sOperands);
|
||||
|
|
@ -902,6 +855,9 @@ class Macro10 {
|
|||
iMatch = 3;
|
||||
}
|
||||
else if (sOperator == Macro10.PSEUDO_OP.LITERAL) {
|
||||
/*
|
||||
* This is a LITERAL block.
|
||||
*/
|
||||
this.chMacroOpen = '[';
|
||||
this.chMacroClose = ']';
|
||||
name = '_' + Str.toDec(this.nLocation, 5);
|
||||
|
|
@ -914,6 +870,9 @@ class Macro10 {
|
|||
iMatch = 0;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* This must be a REPEAT or CONDITIONAL block.
|
||||
*/
|
||||
var sOperand = this.getExpression(sOperands);
|
||||
if (!sOperand) {
|
||||
this.error("missing " + sOperator + " expression: " + sOperands);
|
||||
|
|
@ -923,6 +882,10 @@ class Macro10 {
|
|||
sOperand = sOperand.trim();
|
||||
match = sOperands.match(/\s*(<|)(.*)/i);
|
||||
name = '_' + sOperator;
|
||||
/*
|
||||
* The expression is either a repeat count or a condition. Either way, we must be able to
|
||||
* resolve it now, so we don't set fPass1 (but that doesn't mean it's the second pass, either).
|
||||
*/
|
||||
nOperand = this.parseExpression(sOperand) || 0;
|
||||
iMatch = 1;
|
||||
}
|
||||
|
|
@ -1008,6 +971,36 @@ class Macro10 {
|
|||
this.dbg.setVariable(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* addWord(sOperator, sOperands)
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {string} sOperator
|
||||
* @param {string} sOperands
|
||||
*/
|
||||
addWord(sOperator, sOperands)
|
||||
{
|
||||
var w;
|
||||
var sExp = sOperator + sOperands;
|
||||
if (sExp.indexOf(",,") >= 0 || !sOperator && sExp.indexOf('@') < 0 && sExp.indexOf('(') < 0) {
|
||||
w = this.parseExpression(sExp, true);
|
||||
} else {
|
||||
w = this.dbg.parseInstruction(sOperator, sOperands, this.nLocation, true);
|
||||
if (w < 0) {
|
||||
/*
|
||||
* MACRO-10 also allows instructions to be assembled without an opcode (ie, just an address reference).
|
||||
*/
|
||||
w = this.dbg.parseInstruction("", sExp, this.nLocation, true);
|
||||
if (w < 0) w = undefined;
|
||||
}
|
||||
}
|
||||
if (w !== undefined) {
|
||||
this.genWord(w, this.dbg.sUndefined);
|
||||
} else {
|
||||
this.error("unrecognized expression: " + sExp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* addXWD()
|
||||
*
|
||||
|
|
@ -1019,7 +1012,7 @@ class Macro10 {
|
|||
*/
|
||||
addXWD(sOperands)
|
||||
{
|
||||
this.genWord(0, [sOperands.replace(",", ",,")]);
|
||||
this.genWord(0, sOperands.replace(",", ",,"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1068,18 +1061,35 @@ class Macro10 {
|
|||
}
|
||||
|
||||
/**
|
||||
* genWord(w, aValues)
|
||||
* genWord(value, sFixup)
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {number} w (default value for the current location)
|
||||
* @param {Array.<string>} [aValues] (optional fixup value(s) to evaluate later)
|
||||
* @param {number} value (default value for the current location)
|
||||
* @param {string|null} [sFixup] (optional fixup value to evaluate later)
|
||||
*/
|
||||
genWord(w, aValues)
|
||||
genWord(value, sFixup)
|
||||
{
|
||||
this.aWords[this.nLocation] = w;
|
||||
if (aValues) this.aFixups.push({nLocation: this.nLocation, aValues});
|
||||
this.aWords[this.nLocation] = this.truncate(value);
|
||||
if (sFixup != null) this.aFixups.push({nLocation: this.nLocation, sValue: sFixup});
|
||||
this.nLocation++;
|
||||
}
|
||||
|
||||
/**
|
||||
* truncate(value, nLocation)
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {number} value
|
||||
* @param {number} [nLocation]
|
||||
* @return {number}
|
||||
*/
|
||||
truncate(value, nLocation = this.nLocation)
|
||||
{
|
||||
var w = this.dbg.truncate(value || 0, 36, true);
|
||||
if (value < -PDP10.INT_LIMIT || value >= PDP10.WORD_LIMIT) {
|
||||
this.warning("truncated value " + Str.toOct(value) + " at location " + Str.toOct(nLocation) + " to " + Str.toOct(w));
|
||||
}
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
Macro10.PSEUDO_OP = {
|
||||
|
|
|
|||
|
|
@ -532,7 +532,7 @@ class DebuggerPDP11 extends Debugger {
|
|||
}
|
||||
|
||||
/**
|
||||
* parseAddr(sAddr, fCode, fNoChecks, fPrint)
|
||||
* parseAddr(sAddr, fCode, fNoChecks)
|
||||
*
|
||||
* Address evaluation and validation (eg, range checks) are no longer performed at this stage. That's
|
||||
* done later, by getAddr(), which returns PDP11.ADDR_INVALID for invalid segments, out-of-range offsets,
|
||||
|
|
@ -545,10 +545,9 @@ class DebuggerPDP11 extends Debugger {
|
|||
* @param {string|undefined} sAddr
|
||||
* @param {boolean} [fCode] (true if target is code, false if target is data)
|
||||
* @param {boolean} [fNoChecks] (true when setting breakpoints that may not be valid now, but will be later)
|
||||
* @param {boolean} [fPrint]
|
||||
* @return {DbgAddrPDP11|null|undefined}
|
||||
*/
|
||||
parseAddr(sAddr, fCode, fNoChecks, fPrint)
|
||||
parseAddr(sAddr, fCode, fNoChecks)
|
||||
{
|
||||
var dbgAddr;
|
||||
var dbgAddrNext = (fCode? this.dbgAddrNextCode : this.dbgAddrNextData);
|
||||
|
|
@ -570,7 +569,7 @@ class DebuggerPDP11 extends Debugger {
|
|||
} else if (sAddr.indexOf('.') >= 0) {
|
||||
nBase = 10;
|
||||
}
|
||||
addr = this.parseExpression(sAddr, fPrint);
|
||||
addr = this.parseExpression(sAddr);
|
||||
}
|
||||
if (addr != null) {
|
||||
dbgAddr = this.newAddr(addr, fPhysical, nBase);
|
||||
|
|
@ -3483,7 +3482,7 @@ class DebuggerPDP11 extends Debugger {
|
|||
sCmd = Str.trim(sCmd);
|
||||
var a = sCmd.match(/^(['"])(.*?)\1$/);
|
||||
if (!a) {
|
||||
this.parseExpression(sCmd, true);
|
||||
this.parseExpression(sCmd, false);
|
||||
} else {
|
||||
if (a[2].length > 1) {
|
||||
this.println(this.replaceRegs(a[2]));
|
||||
|
|
|
|||
|
|
@ -77,7 +77,8 @@ var DbgAddr;
|
|||
*
|
||||
* @unrestricted
|
||||
*/
|
||||
class Debugger extends Component {
|
||||
class Debugger extends Component
|
||||
{
|
||||
/**
|
||||
* Debugger(parmsDbg)
|
||||
*
|
||||
|
|
@ -91,7 +92,8 @@ class Debugger extends Component {
|
|||
*
|
||||
* @param {Object} parmsDbg
|
||||
*/
|
||||
constructor(parmsDbg) {
|
||||
constructor(parmsDbg)
|
||||
{
|
||||
if (DEBUGGER) {
|
||||
|
||||
super("Debugger", parmsDbg);
|
||||
|
|
@ -107,6 +109,19 @@ class Debugger extends Component {
|
|||
*/
|
||||
this.nBits = 32;
|
||||
|
||||
/*
|
||||
* sUndefined is set to the last unknown variable that parseExpression() encounters, if if
|
||||
* is called in "quiet mode"; the value used for the variable is zero. This mode was added
|
||||
* for components that need to support expressions containing "fixups" (ie, values that
|
||||
* must be determined later).
|
||||
*
|
||||
* TODO: Only one unknown (fixup) per expression is supported, and we don't indicate what
|
||||
* operation was performed with the value (callers generally assume addition). If a call
|
||||
* encounters more than one undefined value, it will revert to normal error reporting and
|
||||
* return an undefined value for the entire expression.
|
||||
*/
|
||||
this.sUndefined = null;
|
||||
|
||||
this.achGroup = ['{','}'];
|
||||
this.achAddress = ['[',']'];
|
||||
|
||||
|
|
@ -163,7 +178,8 @@ class Debugger extends Component {
|
|||
* @param {number} [off] optional offset into sReg
|
||||
* @return {number} register index, or -1 if not found
|
||||
*/
|
||||
getRegIndex(sReg, off) {
|
||||
getRegIndex(sReg, off)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +192,8 @@ class Debugger extends Component {
|
|||
* @param {number} iReg
|
||||
* @return {number|undefined}
|
||||
*/
|
||||
getRegValue(iReg) {
|
||||
getRegValue(iReg)
|
||||
{
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
|
@ -192,7 +209,8 @@ class Debugger extends Component {
|
|||
* @param {string} sAddr
|
||||
* @return {string}
|
||||
*/
|
||||
parseAddrReference(s, sAddr) {
|
||||
parseAddrReference(s, sAddr)
|
||||
{
|
||||
return s.replace('[' + sAddr + ']', "unimplemented");
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +220,8 @@ class Debugger extends Component {
|
|||
* @this {Debugger}
|
||||
* @return {string}
|
||||
*/
|
||||
getNextCommand() {
|
||||
getNextCommand()
|
||||
{
|
||||
var sCmd;
|
||||
if (this.iPrevCmd > 0) {
|
||||
sCmd = this.aPrevCmds[--this.iPrevCmd];
|
||||
|
|
@ -219,7 +238,8 @@ class Debugger extends Component {
|
|||
* @this {Debugger}
|
||||
* @return {string|null}
|
||||
*/
|
||||
getPrevCommand() {
|
||||
getPrevCommand()
|
||||
{
|
||||
var sCmd = null;
|
||||
if (this.iPrevCmd < this.aPrevCmds.length - 1) {
|
||||
sCmd = this.aPrevCmds[++this.iPrevCmd];
|
||||
|
|
@ -236,7 +256,8 @@ class Debugger extends Component {
|
|||
* @param {string} [chSep] is the command separator character (default is ';')
|
||||
* @return {Array.<string>}
|
||||
*/
|
||||
parseCommand(sCmd, fSave, chSep) {
|
||||
parseCommand(sCmd, fSave, chSep)
|
||||
{
|
||||
if (fSave) {
|
||||
if (!sCmd) {
|
||||
if (this.fAssemble) {
|
||||
|
|
@ -329,6 +350,11 @@ class Debugger extends Component {
|
|||
if (this.nBits <= 32) {
|
||||
return dst & src;
|
||||
}
|
||||
/*
|
||||
* Negative values don't yield correct results when dividing, so pass them through an unsigned truncate().
|
||||
*/
|
||||
dst = this.truncate(dst, 0, true);
|
||||
src = this.truncate(src, 0, true);
|
||||
return ((((dst / Debugger.TWO_POW32)|0) & ((src / Debugger.TWO_POW32)|0)) * Debugger.TWO_POW32) + ((dst & src) >>> 0);
|
||||
}
|
||||
|
||||
|
|
@ -358,9 +384,48 @@ class Debugger extends Component {
|
|||
if (this.nBits <= 32) {
|
||||
return dst | src;
|
||||
}
|
||||
/*
|
||||
* Negative values don't yield correct results when dividing, so pass them through an unsigned truncate().
|
||||
*/
|
||||
dst = this.truncate(dst, 0, true);
|
||||
src = this.truncate(src, 0, true);
|
||||
return ((((dst / Debugger.TWO_POW32)|0) | ((src / Debugger.TWO_POW32)|0)) * Debugger.TWO_POW32) + ((dst | src) >>> 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* evalXOR(dst, src)
|
||||
*
|
||||
* Adapted from /modules/pdp10/lib/cpuops.js:PDP10.XOR().
|
||||
*
|
||||
* Performs the logical "exclusive-or" (XOR) of two operands > 32 bits.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number} (dst ^ src)
|
||||
*/
|
||||
evalXOR(dst, src)
|
||||
{
|
||||
/*
|
||||
* We XOR the low 32 bits separately from the higher bits, and then combine them with addition.
|
||||
* Since all bits above 32 will be zero, and since 0 XOR 0 is 0, no special masking for the higher
|
||||
* bits is required.
|
||||
*
|
||||
* WARNING: When using JavaScript's 32-bit operators with values that could set bit 31 and produce a
|
||||
* negative value, it's critical to perform a final right-shift of 0, ensuring that the final result is
|
||||
* positive.
|
||||
*/
|
||||
if (this.nBits <= 32) {
|
||||
return dst | src;
|
||||
}
|
||||
/*
|
||||
* Negative values don't yield correct results when dividing, so pass them through an unsigned truncate().
|
||||
*/
|
||||
dst = this.truncate(dst, 0, true);
|
||||
src = this.truncate(src, 0, true);
|
||||
return ((((dst / Debugger.TWO_POW32)|0) ^ ((src / Debugger.TWO_POW32)|0)) * Debugger.TWO_POW32) + ((dst ^ src) >>> 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* truncate(v, nBits, fUnsigned)
|
||||
*
|
||||
|
|
@ -394,9 +459,16 @@ class Debugger extends Component {
|
|||
if (nBits <= 32) {
|
||||
vNew = v | 0;
|
||||
} else {
|
||||
/*
|
||||
* For negative values, we require them to fit within nBits - 1, reserving the left-most bit
|
||||
* for the sign bit, but for positive values, we can't really be sure if the caller is treating
|
||||
* the left-most bit as a sign bit or not, so the upper range is based on nBits.
|
||||
*/
|
||||
limit = Math.pow(2, nBits - 1);
|
||||
if (v < -limit || v >= limit) {
|
||||
if (v < -limit) {
|
||||
vNew = v % limit;
|
||||
} else if (v >= limit * 2) {
|
||||
vNew = v % (limit * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -434,7 +506,8 @@ class Debugger extends Component {
|
|||
* @param {number} [cOps] (default is -1 for all)
|
||||
* @return {boolean} true if successful, false if error
|
||||
*/
|
||||
evalOps(aVals, aOps, cOps = -1) {
|
||||
evalOps(aVals, aOps, cOps = -1)
|
||||
{
|
||||
while (cOps-- && aOps.length) {
|
||||
var chOp = aOps.pop();
|
||||
if (aVals.length < 2) return false;
|
||||
|
|
@ -447,7 +520,7 @@ class Debugger extends Component {
|
|||
break;
|
||||
case '/':
|
||||
if (!val2) return false;
|
||||
valNew = val1 / val2;
|
||||
valNew = Math.trunc(val1 / val2);
|
||||
break;
|
||||
case '%':
|
||||
if (!val2) return false;
|
||||
|
|
@ -494,7 +567,7 @@ class Debugger extends Component {
|
|||
valNew = this.evalIOR(val1, val2);
|
||||
break;
|
||||
case '^^': // since MACRO-10 uses '^' for base overrides, you must now use '^^' for bitwise exclusive-or (XOR)
|
||||
valNew = val1 ^ val2;
|
||||
valNew = this.evalXOR(val1, val2);
|
||||
break;
|
||||
case '&&':
|
||||
valNew = (val1 && val2? 1 : 0);
|
||||
|
|
@ -502,16 +575,144 @@ class Debugger extends Component {
|
|||
case '||':
|
||||
valNew = (val1 || val2? 1 : 0);
|
||||
break;
|
||||
case '><':
|
||||
valNew = val1;
|
||||
val2 = 35 - (val2 & 0xff);
|
||||
if (val2) {
|
||||
/*
|
||||
* Since binary shifting is a logical operation, and since shifting by division only works properly
|
||||
* with positive numbers, we must convert a negative value to a positive value, by computing the two's
|
||||
* complement.
|
||||
*/
|
||||
if (valNew < 0) valNew += Math.pow(2, 36);
|
||||
if (val2 > 0) {
|
||||
valNew *= Math.pow(2, val2);
|
||||
} else {
|
||||
valNew = Math.trunc(valNew / Math.pow(2, -val2));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
aVals.push(this.truncate(valNew, this.nBits));
|
||||
aVals.push(this.truncate(valNew));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* parseExpression(sExp, fPrint)
|
||||
* parseArray(asValues, iValue, iLimit, nBase, fQuiet)
|
||||
*
|
||||
* parseExpression() takes a complete expression and divides it into array elements, where even elements
|
||||
* are values (which may be empty if two or more operators appear consecutively) and odd elements are operators.
|
||||
*
|
||||
* For example, if the original expression was "2*{3+{4/2}}", parseExpression() would call parseArray() with:
|
||||
*
|
||||
* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
||||
* - - - - - - - - - - -- -- -- -- --
|
||||
* 2 * _ { 3 + _ { 4 / 2 } _ } _
|
||||
*
|
||||
* This function takes care of recursively processing sub-expressions, by processing subsets of the array,
|
||||
* as well as handling certain base overrides (eg, temporarily switching to base-10 for binary shift suffixes).
|
||||
*
|
||||
* @param {Array.<string>} asValues
|
||||
* @param {number} iValue
|
||||
* @param {number} iLimit
|
||||
* @param {number} nBase
|
||||
* @param {boolean} [fQuiet]
|
||||
* @return {number|undefined}
|
||||
*/
|
||||
parseArray(asValues, iValue, iLimit, nBase, fQuiet)
|
||||
{
|
||||
var value;
|
||||
var sValue, sOp;
|
||||
var fError = false;
|
||||
var fNegate = false;
|
||||
var aVals = [], aOps = [];
|
||||
|
||||
var nBasePrev = this.nBase;
|
||||
this.nBase = nBase;
|
||||
|
||||
while (iValue < iLimit) {
|
||||
var v;
|
||||
sValue = asValues[iValue++].trim();
|
||||
sOp = (iValue < iLimit? asValues[iValue++] : "");
|
||||
|
||||
if (!sValue) {
|
||||
if (sOp == '{') {
|
||||
var cOpen = 1;
|
||||
var iStart = iValue;
|
||||
while (iValue < iLimit) {
|
||||
sValue = asValues[iValue++].trim();
|
||||
sOp = (iValue < asValues.length? asValues[iValue++] : "");
|
||||
if (sOp == '{') {
|
||||
cOpen++;
|
||||
} else if (sOp == '}') {
|
||||
if (!--cOpen) break;
|
||||
}
|
||||
}
|
||||
v = this.parseArray(asValues, iStart, iValue-1, this.nBase, fQuiet);
|
||||
sValue = (iValue < iLimit? asValues[iValue++].trim() : "");
|
||||
sOp = (iValue < iLimit? asValues[iValue++] : "");
|
||||
}
|
||||
else {
|
||||
if (sOp != '-') {
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
fNegate = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
v = this.parseValue(sValue, null, fQuiet, fNegate);
|
||||
}
|
||||
|
||||
if (v === undefined) {
|
||||
if (this.sUndefined == null && fQuiet) {
|
||||
this.sUndefined = sValue;
|
||||
v = 0;
|
||||
} else {
|
||||
fError = true;
|
||||
fQuiet = !fQuiet;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
aVals.push(this.truncate(v));
|
||||
if (!sOp) break;
|
||||
|
||||
this.assert(Debugger.aBinOpPrecedence[sOp] != null);
|
||||
if (aOps.length && Debugger.aBinOpPrecedence[sOp] < Debugger.aBinOpPrecedence[aOps[aOps.length - 1]]) {
|
||||
this.evalOps(aVals, aOps, 1);
|
||||
}
|
||||
|
||||
aOps.push(sOp);
|
||||
|
||||
/*
|
||||
* The MACRO-10 binary shifting operator assumes a base-10 shift count, regardless of the current
|
||||
* base, so we must override the current base to ensure the count is parsed correctly.
|
||||
*/
|
||||
this.nBase = (sOp == '><')? 10 : nBase;
|
||||
fNegate = false;
|
||||
}
|
||||
|
||||
if (!this.evalOps(aVals, aOps) || aVals.length != 1) {
|
||||
fError = true;
|
||||
}
|
||||
|
||||
if (!fError) {
|
||||
value = aVals.pop();
|
||||
} else if (fQuiet === false) {
|
||||
this.println("parse error (" + (sValue || sOp) + ")");
|
||||
}
|
||||
|
||||
this.nBase = nBasePrev;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* parseExpression(sExp, fQuiet)
|
||||
*
|
||||
* A quick-and-dirty expression parser. It takes an expression like:
|
||||
*
|
||||
|
|
@ -527,92 +728,70 @@ class Debugger extends Component {
|
|||
* ...
|
||||
*
|
||||
* We pop 1 "binop" from aOps and 2 values from aVals whenever a "binop" of lower priority than its
|
||||
* predecessor is encountered, evaluate, and push the result back onto aVals. Unary operators like
|
||||
* '~' and ternary operators like '?:' are not supported.
|
||||
*
|
||||
* parseReference() makes it possible to write parenthetical-style sub-expressions by using whatever
|
||||
* characters achGroup contains (default is braces}. Address references are resolved using the characters
|
||||
* in achAddress (default is brackets).
|
||||
*
|
||||
* Why not always use parentheses for sub-expressions? Because parseReference() serves multiple purposes,
|
||||
* the other being reference replacement in message strings passing through replaceRegs(), and some
|
||||
* Debuggers don't want parentheses taking on a new meaning in message strings.
|
||||
*
|
||||
* However, a Debugger can override these choices by modifying achGroup and/or achAddress, if there's no
|
||||
* conflict in its replaceRegs() implementation.
|
||||
* predecessor is encountered, evaluate, and push the result back onto aVals. Only selected unary
|
||||
* operators are supported (eg, minus), and ternary operators like '?:' are not supported at all.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {string|undefined} sExp
|
||||
* @param {boolean} [fPrint] is true to print all resolved values, false for quiet parsing
|
||||
* @param {boolean} [fQuiet] (true for quiet parsing)
|
||||
* @return {number|undefined} numeric value, or undefined if sExp contains any undefined or invalid values
|
||||
*/
|
||||
parseExpression(sExp, fPrint) {
|
||||
parseExpression(sExp, fQuiet)
|
||||
{
|
||||
var value;
|
||||
|
||||
/*
|
||||
* First process (and eliminate) any references, aka sub-expressions.
|
||||
*/
|
||||
if (sExp) sExp = this.parseReference(sExp);
|
||||
this.sUndefined = null;
|
||||
|
||||
if (sExp) {
|
||||
var i = 0;
|
||||
var fError = false;
|
||||
var sExpOrig = sExp;
|
||||
var aVals = [], aOps = [];
|
||||
|
||||
/*
|
||||
* The default grouping characters for sub-expressions are braces; they can be changed by altering
|
||||
* achGroup, but when that happens, instead of changing our regular expressions and operator tables,
|
||||
* we simply replace all achGroup characters with braces in the given expression.
|
||||
*
|
||||
* Why not just always use parentheses for sub-expressions? Because some debuggers use parseReference()
|
||||
* to perform parenthetical value replacements in message strings, and they don't want parentheses taking
|
||||
* on a different meaning. And for some machines, like the PDP-10, the convention is to use parentheses
|
||||
* for indexed addressing and angle brackets for sub-expressions.
|
||||
*/
|
||||
if (this.achGroup[0] != '{') {
|
||||
sExp = sExp.split(this.achGroup[0]).join('{').split(this.achGroup[1]).join('}');
|
||||
}
|
||||
|
||||
/*
|
||||
* All browsers (including, I believe, IE9 and up) support the following idiosyncrasy of a RegExp split():
|
||||
* when the RegExp uses a capturing pattern, the resulting array will include entries for all the pattern
|
||||
* matches along with the non-matches. This effectively means that, in the set of expressions that we
|
||||
* support, all even entries in asValues will contain "values" and all odd entries will contain "operators".
|
||||
*
|
||||
* Although I starting listing the operators in the RegExp in "precedential" order, that's not important;
|
||||
* Although I started listing the operators in the RegExp in "precedential" order, that's not important;
|
||||
* what IS important is listing operators than contain shorter operators first. For example, bitwise
|
||||
* shift operators must be listed BEFORE the logical less-than or greater-than operators.
|
||||
*
|
||||
* Finally, to better accommodate MACRO-10 syntax, I've replaced the single '^' for XOR with '^^', since
|
||||
* Also, to better accommodate MACRO-10 syntax, I've replaced the single '^' for XOR with '^^', since
|
||||
* MACRO-10 uses prefixes like "^D", "^O" and "^B" with numeric constants to indicate a base override, and
|
||||
* I've added '!' as an alias for '|' to perform bitwise inclusive-or.
|
||||
*
|
||||
* The MACRO-10 binary shifting suffix ('B') is a bit more problematic, since a capital B can also appear
|
||||
* inside symbols. So I pre-scan for that operator and replace non-symbolic occurrences with an internal
|
||||
* operator ('><').
|
||||
*
|
||||
* Note that Str.parseInt(), which parseValue() relies on, supports both the MACRO-10 base prefix overrides
|
||||
* and the binary shifting suffix. But since the B suffix can also be a bracketed expression, we have to
|
||||
* support it here as well.
|
||||
*
|
||||
* MACRO-10 supports only a subset of all the PCjs operators; for example, MACRO-10 doesn't support bitwise
|
||||
* exclusive-or, shift operators, or any of the boolean logical/compare operators. But unless we run into
|
||||
* conflicts, I prefer sticking with this common set of operators.
|
||||
*
|
||||
* WARNING: Whenever you make changes to this RegExp, make sure you update aBinOpPrecedence as needed, too.
|
||||
*/
|
||||
var regExp = /(\|\||&&|\||^^|&|!=|!|==|>=|>>>|>>|>|<=|<<|<|-|\+|%|\/|\*)/;
|
||||
var regExp = /(\{|}|\|\||&&|\||\^\^|><|&|!=|!|==|>=|>>>|>>|>|<=|<<|<|-|\+|%|\/|\*)/;
|
||||
sExp = sExp.replace(/(^|[^A-Z0-9$%.])([0-9]+)B/, "$1$2><");
|
||||
var asValues = sExp.split(regExp);
|
||||
while (i < asValues.length) {
|
||||
var sValue = asValues[i++];
|
||||
var cchValue = sValue.length;
|
||||
var s = Str.trim(sValue);
|
||||
if (!s) {
|
||||
fError = true;
|
||||
break;
|
||||
}
|
||||
var v = this.parseValue(s, null, fPrint === false);
|
||||
if (v === undefined) {
|
||||
fError = true;
|
||||
fPrint = false;
|
||||
break;
|
||||
}
|
||||
aVals.push(this.truncate(v, this.nBits));
|
||||
if (i == asValues.length) break;
|
||||
var sOp = asValues[i++], cchOp = sOp.length;
|
||||
this.assert(Debugger.aBinOpPrecedence[sOp] != null);
|
||||
if (aOps.length && Debugger.aBinOpPrecedence[sOp] < Debugger.aBinOpPrecedence[aOps[aOps.length-1]]) {
|
||||
this.evalOps(aVals, aOps, 1);
|
||||
}
|
||||
aOps.push(sOp);
|
||||
sExp = sExp.substr(cchValue + cchOp);
|
||||
}
|
||||
if (!this.evalOps(aVals, aOps) || aVals.length != 1) {
|
||||
fError = true;
|
||||
}
|
||||
if (!fError) {
|
||||
value = aVals.pop();
|
||||
if (fPrint) this.printValue(null, value);
|
||||
} else {
|
||||
if (fPrint) this.println("error parsing '" + sExpOrig + "' at character " + (sExpOrig.length - sExp.length));
|
||||
value = this.parseArray(asValues, 0, asValues.length, this.nBase, fQuiet);
|
||||
if (value !== undefined && fQuiet === false) {
|
||||
this.printValue(null, value);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
|
|
@ -629,7 +808,8 @@ class Debugger extends Component {
|
|||
* @param {string} s
|
||||
* @return {string|undefined}
|
||||
*/
|
||||
parseReference(s) {
|
||||
parseReference(s)
|
||||
{
|
||||
var a;
|
||||
var chOpen = this.achGroup[0];
|
||||
var chClose = this.achGroup[1];
|
||||
|
|
@ -677,7 +857,8 @@ class Debugger extends Component {
|
|||
* @param {string} s
|
||||
* @return {string}
|
||||
*/
|
||||
parseSysVars(s) {
|
||||
parseSysVars(s)
|
||||
{
|
||||
var a;
|
||||
while (a = s.match(/\$([a-z]+)/i)) {
|
||||
var v = null;
|
||||
|
|
@ -693,15 +874,17 @@ class Debugger extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* parseValue(sValue, sName, fQuiet)
|
||||
* parseValue(sValue, sName, fQuiet, fNegate)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {string|undefined} sValue
|
||||
* @param {string|null} [sName] is the name of the value, if any
|
||||
* @param {boolean} [fQuiet]
|
||||
* @param {boolean} [fNegate]
|
||||
* @return {number|undefined} numeric value, or undefined if sValue is either undefined or invalid
|
||||
*/
|
||||
parseValue(sValue, sName, fQuiet) {
|
||||
parseValue(sValue, sName, fQuiet, fNegate)
|
||||
{
|
||||
var value;
|
||||
if (sValue != null) {
|
||||
var iReg = this.getRegIndex(sValue);
|
||||
|
|
@ -710,12 +893,17 @@ class Debugger extends Component {
|
|||
} else {
|
||||
value = this.getVariable(sValue);
|
||||
if (value == null) {
|
||||
value = Str.parseInt(sValue, this.nBase);
|
||||
value = Str.parseInt(fNegate? ('-' + sValue) : sValue, this.nBase);
|
||||
fNegate = false;
|
||||
}
|
||||
}
|
||||
if (value == null && !fQuiet) {
|
||||
if (value != null) {
|
||||
if (fNegate) value = -value;
|
||||
} else {
|
||||
if (!fQuiet) {
|
||||
this.println("invalid " + (sName? sName : "value") + ": " + sValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!fQuiet) {
|
||||
this.println("missing " + (sName || "value"));
|
||||
|
|
@ -732,7 +920,8 @@ class Debugger extends Component {
|
|||
* @param {number|undefined} value
|
||||
* @return {boolean} true if value defined, false if not
|
||||
*/
|
||||
printValue(sVar, value) {
|
||||
printValue(sVar, value)
|
||||
{
|
||||
var sValue;
|
||||
var fDefined = false;
|
||||
if (value !== undefined) {
|
||||
|
|
@ -753,7 +942,8 @@ class Debugger extends Component {
|
|||
* @this {Debugger}
|
||||
* @return {Object}
|
||||
*/
|
||||
resetVariables() {
|
||||
resetVariables()
|
||||
{
|
||||
var a = this.aVariables;
|
||||
this.aVariables = {};
|
||||
return a;
|
||||
|
|
@ -765,7 +955,8 @@ class Debugger extends Component {
|
|||
* @this {Debugger}
|
||||
* @param {Object} a (from previous resetVariables() call)
|
||||
*/
|
||||
restoreVariables(a) {
|
||||
restoreVariables(a)
|
||||
{
|
||||
this.aVariables = a;
|
||||
}
|
||||
|
||||
|
|
@ -776,7 +967,8 @@ class Debugger extends Component {
|
|||
* @param {string} [sVar]
|
||||
* @return {boolean} true if all value(s) defined, false if not
|
||||
*/
|
||||
printVariable(sVar) {
|
||||
printVariable(sVar)
|
||||
{
|
||||
if (sVar) {
|
||||
return this.printValue(sVar, this.aVariables[sVar]);
|
||||
}
|
||||
|
|
@ -794,7 +986,8 @@ class Debugger extends Component {
|
|||
* @this {Debugger}
|
||||
* @param {string} sVar
|
||||
*/
|
||||
delVariable(sVar) {
|
||||
delVariable(sVar)
|
||||
{
|
||||
delete this.aVariables[sVar];
|
||||
}
|
||||
|
||||
|
|
@ -805,7 +998,8 @@ class Debugger extends Component {
|
|||
* @param {string} sVar
|
||||
* @return {number|undefined}
|
||||
*/
|
||||
getVariable(sVar) {
|
||||
getVariable(sVar)
|
||||
{
|
||||
return this.aVariables[sVar];
|
||||
}
|
||||
|
||||
|
|
@ -816,7 +1010,8 @@ class Debugger extends Component {
|
|||
* @param {string} sVar
|
||||
* @param {number} value
|
||||
*/
|
||||
setVariable(sVar, value) {
|
||||
setVariable(sVar, value)
|
||||
{
|
||||
this.aVariables[sVar] = value;
|
||||
}
|
||||
|
||||
|
|
@ -830,7 +1025,8 @@ class Debugger extends Component {
|
|||
* @param {number} [nBits] (-1 to strip leading zeros, 0 to allow a variable number of digits)
|
||||
* @return {string}
|
||||
*/
|
||||
toStrBase(n, nBits = 0) {
|
||||
toStrBase(n, nBits = 0)
|
||||
{
|
||||
var s;
|
||||
switch(this.nBase) {
|
||||
case 8:
|
||||
|
|
@ -873,7 +1069,10 @@ if (DEBUGGER) {
|
|||
'+': 8, // addition
|
||||
'%': 9, // remainder
|
||||
'/': 9, // division
|
||||
'*': 9 // multiplication
|
||||
'*': 9, // multiplication
|
||||
'><': 10, // internal binary shift operator (MACRO-10-style; converted from a 'B' suffix)
|
||||
'{': 11, // open sub-expression (achGroup[0] default)
|
||||
'}': 11 // close sub-expression (achGroup[1] default)
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ class Str {
|
|||
* allowed; we remove them all before calling the built-in parseInt().
|
||||
*
|
||||
* More recently, we've added support for "^D", "^O", and "^B" prefixes to accommodate the base overrides
|
||||
* that the PDP-10's MACRO-10 assembly language supports. If this support turns out to adversely affect
|
||||
* other debuggers, then it will have to be "conditionalized".
|
||||
* that the PDP-10's MACRO-10 assembly language supports (decimal, octal, and binary, respectively).
|
||||
* If this support turns out to adversely affect other debuggers, then it will have to be "conditionalized".
|
||||
*
|
||||
* To summarize our non-standard alternatives: a 'y' suffix indicates binary, a '#' prefix indicates
|
||||
* octal, a '$' prefix indicates hex, and a "0b" prefix indicates binary IF at least one comma is present.
|
||||
|
|
@ -149,13 +149,37 @@ class Str {
|
|||
if (chSuffix == null) s = s.substr(0, s.length - 1);
|
||||
}
|
||||
}
|
||||
var v;
|
||||
/*
|
||||
* This adds support for the MACRO-10 binary shifting (Bn) suffix, which must be stripped from the
|
||||
* number before parsing, and then applied to the value after parsing. If n is omitted, 35 is assumed,
|
||||
* which is a net shift of zero. If n < 35, then a left shift of (35 - n) is required; if n > 35, then
|
||||
* a right shift of -(35 - n) is required.
|
||||
*/
|
||||
var v, shift = 0;
|
||||
var match = s.match(/(-?[0-9]+)B([0-9]*)/);
|
||||
if (match) {
|
||||
s = match[1];
|
||||
shift = 35 - ((match[2] || 35) & 0xff);
|
||||
}
|
||||
if (Str.isValidInt(s, base) && !isNaN(v = parseInt(s, base))) {
|
||||
/*
|
||||
* With the need to support larger (eg, 36-bit) integers, truncating to 32 bits is no longer helpful.
|
||||
*
|
||||
* value = v|0;
|
||||
*/
|
||||
if (shift) {
|
||||
/*
|
||||
* Since binary shifting is a logical operation, and since shifting by division only works properly
|
||||
* with positive numbers, we must convert a negative value to a positive value, by computing the two's
|
||||
* complement.
|
||||
*/
|
||||
if (v < 0) v += Math.pow(2, 36);
|
||||
if (shift > 0) {
|
||||
v *= Math.pow(2, shift);
|
||||
} else {
|
||||
v = Math.trunc(v / Math.pow(2, -shift));
|
||||
}
|
||||
}
|
||||
value = v;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue