#!/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())