Jump to content
  • entries
    45
  • comments
    10
  • views
    10,375

APX Pascal Architecture, part four


Atari_Ace

584 views

The last blog entry introduced the tools I'm using to explore the Pascal runtime, and included a preliminary (i.e. rough) disassembly. Now we'll start refining that disassembly and start discussing more of the opcodes.

Firstly, the last listing was erroneous around $B959 to $B991. There are strings there I somehow missed when spot checking the disassembly, so I've fixed up that part of the disassembly. There were also a couple of missing $9B's as well after strings, and the p-code disassembly had a couple of errors as well which I've now fixed.

Now let's discuss some more opcodes. The simplest opcode in the listing is opcode DB. It is just:

AF9D: E8                INX
AF9E: E8                INX
AF9F: 4C 9D 00          JMP NEXT_OP1

Since X is the current evaluation stack pointer, and it grows downwards, this opcode drops the topmost entry of the stack, so let's call it DROP.

Another simple opcode is $DA, which disassembles as:

AF8C: CA                DEX
AF8D: CA                DEX
AF8E: BD 03 06          LDA EVALPAGE+3,X
AF91: 9D 01 06          STA EVALPAGE+1,X
AF94: BD 02 06          LDA EVALPAGE+2,X
AF97: 9D 00 06          STA EVALPAGE,X
AF9A: 4C 9D 00          JMP NEXT_OP1

This adds one entry to the stack, and copies the (previous) top element to it, so we can call this DUP.

Opcode D2 is a bit longer, but just involves moving things around the stack, so that the first two elements are exchanged, so let's call it SWAP.

AF5F: BC 00 06          LDY EVALPAGE,X
AF62: BD 02 06          LDA EVALPAGE+2,X
AF65: 9D 00 06          STA EVALPAGE,X
AF68: 98                TYA
AF69: 9D 02 06          STA EVALPAGE+2,X
AF6C: BC 01 06          LDY EVALPAGE+1,X
AF6F: BD 03 06          LDA EVALPAGE+3,X
AF72: 9D 01 06          STA EVALPAGE+1,X
AF75: 98                TYA
AF76: 9D 03 06          STA EVALPAGE+3,X
AF79: 4C 9D 00          JMP NEXT_OP1

Some other simple stack-only opcodes are 30 (AND), 32 (OR), 34 (NOT), 36 (EOR), 38 (NEG), 40 (ADD) and 44 (SUB). All of these replace the top two values on the stack with the result of the operation.

Opcodes 60 and 70 oddly point to the same code, which looks like this:

B185: BD 01 06          LDA EVALPAGE+1,X
B188: DD 03 06          CMP EVALPAGE+3,X
B18B: D0 5C             BNE $B1E9
B18D: BD 00 06          LDA EVALPAGE,X
B190: DD 02 06          CMP EVALPAGE+2,X
B193: D0 54             BNE $B1E9
B195: F0 5F             BEQ $B1F6
...
B1E9: E8                INX
B1EA: E8                INX
B1EB: A9 00             LDA #0
B1ED: 9D 00 06          STA EVALPAGE,X
B1F0: 9D 01 06          STA EVALPAGE+1,X
B1F3: 4C 9D 00          JMP NEXT_OP1
B1F6: E8                INX
B1F7: E8                INX
B1F8: A9 01             LDA #1
B1FA: 9D 00 06          STA EVALPAGE,X
B1FD: A9 00             LDA #0
B1FF: 9D 01 06          STA EVALPAGE+1,X
B202: 4C 9D 00          JMP NEXT_OP1

If the top two values are equal, we replace them with a 1, otherwise we replace them with a 0. So let's call them EQU. Opcodes 62 and 72 reverses this, so let's call them NEQ. Now why are there two equivalent opcodes? Well, let's look at opcode 64 and 74. 64 is simply:

B1A9: 20 2F BE          JSR $BE2F
B1AC: F0 3B             BEQ $B1E9
B1AE: 30 39             BMI $B1E9
B1B0: 10 44             BPL $B1F6

and 74 is similar:

B1C9: 20 2F BE          JSR $BE2F
B1CC: F0 1B             BEQ $B1E9
B1CE: 90 19             BCC $B1E9
B1D0: B0 24             BCS $B1F6

with

BE2F: BD 02 06          LDA EVALPAGE+2,X
BE32: DD 00 06          CMP EVALPAGE,X
BE35: F0 0B             BEQ $BE42
BE37: BD 03 06          LDA EVALPAGE+3,X
BE3A: FD 01 06          SBC EVALPAGE+1,X
BE3D: 09 01             ORA #1
BE3F: 70 0A             BVS $BE4B
BE41: 60                RTS
BE42: BD 03 06          LDA EVALPAGE+3,X
BE45: FD 01 06          SBC EVALPAGE+1,X
BE48: 70 01             BVS $BE4B
BE4A: 60                RTS
BE4B: 49 80             EOR #$80
BE4D: 09 01             ORA #1
BE4F: 60                RTS

This difference here seems to be whether the 16-bit comparisons here are done signed or unsigned. The 6x opcodes are signed comparisons, and the 7x opcodes are unsigned comparisons. 60 is EQU and 70 is UEQU, which happen to have identical implementations, and 62 and 72 are similarly NEQ and UNEQ. 64, 66, 68 and 6A seem to be greater than (GT), less than (LT), greater than or equal (GTE) and less than or equal (LTE) respectively. 74, 76, 78 and 7A appear to be same, only unsigned.

To further complicate matters, the 8x opcodes also implement comparisons (the same six EQU, NEQ, GT, LT, GTE, LTE operations), but for other types than signed and unsigned integers. The second byte after determines the type, with 00 => bool, 01 => string (both from the stack, so both of these sequences consume 2 bytes), and 02, 03 and 04 being various byte comparisons consuming an additional 2 bytes after the type byte. So our simple p-code disassembler which assumes all opcodes but 2C are fixed size needs to be modified to handle these opcodes a little differently.

That's enough for this post. The runtime disassembly is certainly starting to make a bit more sense, but there are plenty of mysteries left to explore.
 

pascal3.zip

  • Like 3

0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...