| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- #!/usr/bin/env python3
- """check_realconst.py -- the six bytes of TP3's Real, against CALC-PORT.md.
- CALC-PORT.md decoded the format from CALCDEMO.MCS, cross-checked against the
- cells holding 1, 2, 3, 4 and 5:
- value = (1 + N/2^39) * 2^(E-129)
- byte 0 = E biased by 129, bytes 1..5 = N little-endian, the sign is bit 7 of
- byte 5, and all-zero is 0.0. No execution oracle can read a Real back yet, so
- this check asserts the OPERAND BYTES in the emitted code instead: integer
- constants stored through a symbol (B8 vv 00 A2 addr), through DI (C6 45 off
- vv), and the six-byte copy (A0 src / 88 45 off).
- The fixture is t80_realconst; its execution still checks the integer fields on
- either side of the Real, which is what pins the store's WIDTH.
- """
- import os
- import re
- import subprocess
- import sys
- HERE = os.path.dirname(os.path.abspath(__file__))
- SHELL = os.path.dirname(HERE)
- FIX = os.path.join(HERE, "fixtures", "t80_realconst.pas")
- # From the measured table (CALC-PORT.md).
- MBF = {
- "0": bytes.fromhex("000000000000"),
- "1": bytes.fromhex("810000000000"),
- "2": bytes.fromhex("820000000000"),
- "3": bytes.fromhex("820000000040"),
- "5": bytes.fromhex("830000000020"),
- }
- def dump():
- r = subprocess.run([os.path.join(SHELL, "compiletest")],
- input=("@image\n" + FIX + "\n").encode(),
- capture_output=True, cwd=SHELL)
- text = r.stdout.decode("latin-1")
- if " OK " not in text:
- sys.exit("the fixture did not compile:\n" + text)
- data = bytearray()
- for line in text.splitlines():
- m = re.match(r"^\s+([0-9A-Fa-f]{4}):\s+((?:[0-9A-Fa-f]{2}\s*)+)$", line)
- if m:
- data.extend(int(t, 16) for t in m.group(2).split())
- return bytes(data)
- def symbol_stores(data):
- """The 6-byte runs of B8 vv 00 A2 lo hi with consecutive addresses."""
- runs = []
- i = 0
- while i + 6 <= len(data):
- if data[i] == 0xB8 and data[i + 2] == 0x00 and data[i + 3] == 0xA2:
- runs.append((data[i + 1], data[i + 4] | (data[i + 5] << 8)))
- i += 6
- else:
- i += 1
- found = {}
- for s in range(len(runs) - 5):
- seg = runs[s:s + 6]
- if all(seg[t + 1][1] == seg[t][1] + 1 for t in range(5)):
- found[bytes(v for v, _ in seg)] = seg[0][1]
- return found
- def main():
- data = dump()
- problems = []
- found = symbol_stores(data)
- for name, want in MBF.items():
- if want not in found:
- problems.append("no symbol store of %s as %s" % (name, want.hex(" ")))
- else:
- print(" %s -> %s at %04xh" % (name, want.hex(" "), found[want]))
- # The DI form of `V := 1'.
- di1 = bytes.fromhex("C6450081C6450100C6450200C6450300C6450400C6450500")
- if di1 not in data:
- problems.append("the DI store of 1 is not C6 45 00 81 ... 05 00")
- # The six-byte copy through DI.
- for k in range(6):
- if bytes([0x88, 0x45, k]) not in data:
- problems.append("the copy never stores byte %d through DI" % k)
- if problems:
- print("FAIL:")
- for p in problems:
- print(" - " + p)
- return 1
- print("PASS: the measured MBF bytes for 0,1,2,3,5 are emitted, the DI "
- "store holds them,\n and the six-byte copy stores every byte")
- return 0
- if __name__ == "__main__":
- sys.exit(main())
|