CharlesCNorton commited on
Commit ·
22baf26
1
Parent(s): f6bd63a
rv32: FCVT.W.S honors the instruction rounding-mode field (RNE/RTZ/RDN/RUP/RMM), verified against an exact rational reference across all modes
Browse files- src/machines.py +158 -26
- todo.md +0 -1
src/machines.py
CHANGED
|
@@ -222,22 +222,48 @@ def fcvt_s_w_ref(x: int) -> int:
|
|
| 222 |
return struct.unpack("<I", struct.pack("<f", float(xi)))[0]
|
| 223 |
|
| 224 |
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
s, e, f = (w >> 31) & 1, (w >> 23) & 0xFF, w & 0x7FFFFF
|
| 229 |
if e == 0xFF:
|
| 230 |
return 0x7FFFFFFF if f else (0x80000000 if s else 0x7FFFFFFF)
|
| 231 |
-
|
| 232 |
-
if
|
| 233 |
-
|
| 234 |
-
mant = (1 << 23) | f
|
| 235 |
-
if E >= 31:
|
| 236 |
if s and E == 31 and f == 0:
|
| 237 |
-
return 0x80000000
|
| 238 |
return 0x80000000 if s else 0x7FFFFFFF
|
| 239 |
-
|
| 240 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 241 |
|
| 242 |
|
| 243 |
def sext(v: int, bits: int) -> int:
|
|
@@ -343,7 +369,8 @@ class Asm:
|
|
| 343 |
if mn == "fmv.x.w":
|
| 344 |
return (0x70 << 25) | (a[1] << 15) | (a[0] << 7) | 0x53
|
| 345 |
if mn == "fcvt.w.s":
|
| 346 |
-
|
|
|
|
| 347 |
if mn == "fcvt.s.w":
|
| 348 |
return (0x68 << 25) | (a[1] << 15) | (a[0] << 7) | 0x53
|
| 349 |
if mn in ("fsgnj.s", "fsgnjn.s", "fsgnjx.s"):
|
|
@@ -498,7 +525,7 @@ class RefRV32:
|
|
| 498 |
from eval import float_bits_to_value
|
| 499 |
x, y = float_bits_to_value(fa, 8, 23), float_bits_to_value(fb, 8, 23)
|
| 500 |
wr(1 if [x <= y, x < y, x == y][f3] else 0)
|
| 501 |
-
elif f7 == 0x60: wr(fcvt_w_s_ref(FR[rs1]))
|
| 502 |
elif f7 == 0x68: FR[rd] = fcvt_s_w_ref(R[rs1]) # FCVT.S.W
|
| 503 |
elif f7 == 0x78: FR[rd] = a
|
| 504 |
elif f7 == 0x70: wr(FR[rs1])
|
|
@@ -749,18 +776,15 @@ class Rv32ThresholdCPU:
|
|
| 749 |
exp += 1
|
| 750 |
return (s << 31) | (exp << 23) | frac
|
| 751 |
|
| 752 |
-
def fcvt_w_s(self, w):
|
| 753 |
-
"""float32 -> signed int32
|
| 754 |
-
|
|
|
|
| 755 |
s, e, f = (w >> 31) & 1, (w >> 23) & 0xFF, w & 0x7FFFFF
|
| 756 |
if e == 0xFF:
|
| 757 |
-
if f
|
| 758 |
-
|
| 759 |
-
|
| 760 |
-
E = e - 127
|
| 761 |
-
if E < 0:
|
| 762 |
-
return 0
|
| 763 |
-
mant = (1 << 23) | f
|
| 764 |
if E >= 31:
|
| 765 |
if s and E == 31 and f == 0:
|
| 766 |
return 0x80000000 # exactly -2^31
|
|
@@ -768,8 +792,14 @@ class Rv32ThresholdCPU:
|
|
| 768 |
if E >= 23:
|
| 769 |
mag = self.sll(mant, E - 23)
|
| 770 |
else:
|
| 771 |
-
|
| 772 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 773 |
|
| 774 |
def neur(self, x_reg, w_reg):
|
| 775 |
x = int_to_bits(x_reg & 0xFF, 8) # MSB-first bits of low byte
|
|
@@ -1043,7 +1073,7 @@ class Rv32ThresholdCPU:
|
|
| 1043 |
s_out = self._bitwise("xor", sa << 31, sb << 31) >> 31 # FSGNJX.S
|
| 1044 |
FR[rd] = (FR[rs1] & 0x7FFFFFFF) | (s_out << 31)
|
| 1045 |
elif f7 == 0x60: # FCVT.W.S: float -> signed int, gate-routed
|
| 1046 |
-
wr(self.fcvt_w_s(FR[rs1]))
|
| 1047 |
elif f7 == 0x68: # FCVT.S.W: signed int -> float, gate-routed
|
| 1048 |
FR[rd] = self.fcvt_s_w(R[rs1])
|
| 1049 |
elif f7 == 0x78:
|
|
@@ -1553,6 +1583,33 @@ def prog_fcvt():
|
|
| 1553 |
return mem, 30, lambda s: s["regs"][3] == 8 and s["regs"][5] == (-5 & 0xFFFFFFFF)
|
| 1554 |
|
| 1555 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1556 |
def rv32_netlist_check() -> bool:
|
| 1557 |
"""Verify the rv32-specific sub-circuits (NEUR, hazard, MULHU accumulator)
|
| 1558 |
are recoverable and correct from the shipped .inputs metadata alone."""
|
|
@@ -1616,6 +1673,79 @@ def rv32_netlist_check() -> bool:
|
|
| 1616 |
return ok
|
| 1617 |
|
| 1618 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1619 |
def rv32_test() -> int:
|
| 1620 |
print("Loading neural_rv32...")
|
| 1621 |
cpu = Rv32ThresholdCPU()
|
|
@@ -1627,6 +1757,7 @@ def rv32_test() -> int:
|
|
| 1627 |
("muldiv", prog_muldiv),
|
| 1628 |
("float_subset", prog_float),
|
| 1629 |
("fcvt_roundtrip", prog_fcvt),
|
|
|
|
| 1630 |
("neur_xor_net", prog_neur),
|
| 1631 |
("mmio_print", prog_mmio),
|
| 1632 |
]
|
|
@@ -1635,6 +1766,7 @@ def rv32_test() -> int:
|
|
| 1635 |
mem, budget, check = builder()
|
| 1636 |
all_ok &= lockstep(cpu, mem, budget, name, check)
|
| 1637 |
all_ok &= rv32_netlist_check()
|
|
|
|
| 1638 |
print(f"dual-issue pairs retired: {cpu.pairs_issued}")
|
| 1639 |
print("RV32:", "PASS" if all_ok else "FAIL")
|
| 1640 |
return 0 if all_ok else 1
|
|
|
|
| 222 |
return struct.unpack("<I", struct.pack("<f", float(xi)))[0]
|
| 223 |
|
| 224 |
|
| 225 |
+
RM_NAMES = {"rne": 0, "rtz": 1, "rdn": 2, "rup": 3, "rmm": 4, "dyn": 7}
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
def _fcvt_round_up(rm: int, sign: int, guard: int, sticky: int, lsb: int) -> int:
|
| 229 |
+
"""Whether the truncated magnitude rounds up by one ULP under the RISC-V
|
| 230 |
+
rounding mode (000 RNE, 001 RTZ, 010 RDN, 011 RUP, 100 RMM; 111 DYN has no
|
| 231 |
+
fcsr in this machine and follows RNE). guard is the half bit just below the
|
| 232 |
+
integer, sticky the OR of everything beneath it."""
|
| 233 |
+
if rm == 1: # RTZ: truncate
|
| 234 |
+
return 0
|
| 235 |
+
if rm == 2: # RDN: toward -inf
|
| 236 |
+
return 1 if (sign and (guard or sticky)) else 0
|
| 237 |
+
if rm == 3: # RUP: toward +inf
|
| 238 |
+
return 1 if ((not sign) and (guard or sticky)) else 0
|
| 239 |
+
if rm == 4: # RMM: nearest, ties away
|
| 240 |
+
return 1 if guard else 0
|
| 241 |
+
return 1 if (guard and (sticky or lsb)) else 0 # RNE / DYN
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
def fcvt_w_s_ref(w: int, rm: int = 1) -> int:
|
| 245 |
+
"""float32 word -> signed int32 under rounding mode `rm`, saturating;
|
| 246 |
+
NaN -> INT_MAX, infinities -> INT_MIN/INT_MAX."""
|
| 247 |
s, e, f = (w >> 31) & 1, (w >> 23) & 0xFF, w & 0x7FFFFF
|
| 248 |
if e == 0xFF:
|
| 249 |
return 0x7FFFFFFF if f else (0x80000000 if s else 0x7FFFFFFF)
|
| 250 |
+
mant = ((1 << 23) | f) if e else f # subnormal: no implicit 1
|
| 251 |
+
E = (e - 127) if e else -126 # subnormal exponent 1-bias
|
| 252 |
+
if E >= 31: # |value| >= 2^31: saturate
|
|
|
|
|
|
|
| 253 |
if s and E == 31 and f == 0:
|
| 254 |
+
return 0x80000000 # exactly -2^31
|
| 255 |
return 0x80000000 if s else 0x7FFFFFFF
|
| 256 |
+
if E >= 23:
|
| 257 |
+
mag = mant << (E - 23) # exact integer, no fraction
|
| 258 |
+
else:
|
| 259 |
+
sh = 23 - E
|
| 260 |
+
mag = mant >> sh
|
| 261 |
+
guard = (mant >> (sh - 1)) & 1
|
| 262 |
+
sticky = 1 if (mant & ((1 << (sh - 1)) - 1)) else 0
|
| 263 |
+
mag += _fcvt_round_up(rm, s, guard, sticky, mag & 1)
|
| 264 |
+
if s:
|
| 265 |
+
return 0x80000000 if mag >= 0x80000000 else (-mag) & MASK32
|
| 266 |
+
return 0x7FFFFFFF if mag > 0x7FFFFFFF else mag & MASK32
|
| 267 |
|
| 268 |
|
| 269 |
def sext(v: int, bits: int) -> int:
|
|
|
|
| 369 |
if mn == "fmv.x.w":
|
| 370 |
return (0x70 << 25) | (a[1] << 15) | (a[0] << 7) | 0x53
|
| 371 |
if mn == "fcvt.w.s":
|
| 372 |
+
rm = RM_NAMES.get(a[2], a[2]) if len(a) > 2 else 1 # default rtz
|
| 373 |
+
return (0x60 << 25) | (a[1] << 15) | (rm << 12) | (a[0] << 7) | 0x53
|
| 374 |
if mn == "fcvt.s.w":
|
| 375 |
return (0x68 << 25) | (a[1] << 15) | (a[0] << 7) | 0x53
|
| 376 |
if mn in ("fsgnj.s", "fsgnjn.s", "fsgnjx.s"):
|
|
|
|
| 525 |
from eval import float_bits_to_value
|
| 526 |
x, y = float_bits_to_value(fa, 8, 23), float_bits_to_value(fb, 8, 23)
|
| 527 |
wr(1 if [x <= y, x < y, x == y][f3] else 0)
|
| 528 |
+
elif f7 == 0x60: wr(fcvt_w_s_ref(FR[rs1], f3)) # FCVT.W.S (rm=funct3)
|
| 529 |
elif f7 == 0x68: FR[rd] = fcvt_s_w_ref(R[rs1]) # FCVT.S.W
|
| 530 |
elif f7 == 0x78: FR[rd] = a
|
| 531 |
elif f7 == 0x70: wr(FR[rs1])
|
|
|
|
| 776 |
exp += 1
|
| 777 |
return (s << 31) | (exp << 23) | frac
|
| 778 |
|
| 779 |
+
def fcvt_w_s(self, w, rm=1):
|
| 780 |
+
"""float32 -> signed int32 under rounding mode `rm`, saturating. The
|
| 781 |
+
shifts run through the barrel shifter; the round decision is control
|
| 782 |
+
logic, as in fcvt_s_w. NaN -> INT_MAX; overflow saturates."""
|
| 783 |
s, e, f = (w >> 31) & 1, (w >> 23) & 0xFF, w & 0x7FFFFF
|
| 784 |
if e == 0xFF:
|
| 785 |
+
return 0x7FFFFFFF if f else (0x80000000 if s else 0x7FFFFFFF)
|
| 786 |
+
mant = ((1 << 23) | f) if e else f
|
| 787 |
+
E = (e - 127) if e else -126
|
|
|
|
|
|
|
|
|
|
|
|
|
| 788 |
if E >= 31:
|
| 789 |
if s and E == 31 and f == 0:
|
| 790 |
return 0x80000000 # exactly -2^31
|
|
|
|
| 792 |
if E >= 23:
|
| 793 |
mag = self.sll(mant, E - 23)
|
| 794 |
else:
|
| 795 |
+
sh = 23 - E
|
| 796 |
+
mag = self.srl(mant, sh) if sh <= 31 else 0
|
| 797 |
+
guard = (mant >> (sh - 1)) & 1
|
| 798 |
+
sticky = 1 if (mant & ((1 << (sh - 1)) - 1)) else 0
|
| 799 |
+
mag += _fcvt_round_up(rm, s, guard, sticky, mag & 1)
|
| 800 |
+
if s:
|
| 801 |
+
return 0x80000000 if mag >= 0x80000000 else self.neg32(mag)
|
| 802 |
+
return 0x7FFFFFFF if mag > 0x7FFFFFFF else (mag & MASK32)
|
| 803 |
|
| 804 |
def neur(self, x_reg, w_reg):
|
| 805 |
x = int_to_bits(x_reg & 0xFF, 8) # MSB-first bits of low byte
|
|
|
|
| 1073 |
s_out = self._bitwise("xor", sa << 31, sb << 31) >> 31 # FSGNJX.S
|
| 1074 |
FR[rd] = (FR[rs1] & 0x7FFFFFFF) | (s_out << 31)
|
| 1075 |
elif f7 == 0x60: # FCVT.W.S: float -> signed int, gate-routed
|
| 1076 |
+
wr(self.fcvt_w_s(FR[rs1], f3))
|
| 1077 |
elif f7 == 0x68: # FCVT.S.W: signed int -> float, gate-routed
|
| 1078 |
FR[rd] = self.fcvt_s_w(R[rs1])
|
| 1079 |
elif f7 == 0x78:
|
|
|
|
| 1583 |
return mem, 30, lambda s: s["regs"][3] == 8 and s["regs"][5] == (-5 & 0xFFFFFFFF)
|
| 1584 |
|
| 1585 |
|
| 1586 |
+
def prog_fcvt_rm():
|
| 1587 |
+
# FCVT.W.S honors the instruction's rounding-mode field. Convert 2.5, 3.5,
|
| 1588 |
+
# -2.5, 2.75 under several modes and check each against the IEEE result.
|
| 1589 |
+
import struct as _st
|
| 1590 |
+
a = Asm()
|
| 1591 |
+
a.lui(10, 0x1) # x10 = 0x1000 (data base)
|
| 1592 |
+
a.flw(1, 10, 0) # f1 = 2.5
|
| 1593 |
+
a.flw(2, 10, 4) # f2 = 3.5
|
| 1594 |
+
a.flw(3, 10, 8) # f3 = -2.5
|
| 1595 |
+
a.flw(4, 10, 12) # f4 = 2.75
|
| 1596 |
+
a.fcvt_w_s(1, 1, "rup") # x1 = ceil(2.5) = 3
|
| 1597 |
+
a.fcvt_w_s(2, 2, "rne") # x2 = 3.5 ties to even = 4
|
| 1598 |
+
a.fcvt_w_s(3, 1, "rne") # x3 = 2.5 ties to even = 2
|
| 1599 |
+
a.fcvt_w_s(4, 3, "rdn") # x4 = floor(-2.5) = -3
|
| 1600 |
+
a.fcvt_w_s(5, 4, "rtz") # x5 = trunc(2.75) = 2
|
| 1601 |
+
a.fcvt_w_s(6, 1, "rmm") # x6 = 2.5 ties away = 3
|
| 1602 |
+
a.ecall()
|
| 1603 |
+
mem = a.assemble()
|
| 1604 |
+
for i, v in enumerate((2.5, 3.5, -2.5, 2.75)):
|
| 1605 |
+
wb = _st.unpack("<I", _st.pack("<f", v))[0]
|
| 1606 |
+
for b in range(4):
|
| 1607 |
+
mem[0x1000 + i * 4 + b] = (wb >> (8 * b)) & 0xFF
|
| 1608 |
+
return mem, 40, lambda s: (s["regs"][1] == 3 and s["regs"][2] == 4
|
| 1609 |
+
and s["regs"][3] == 2 and s["regs"][4] == (-3 & 0xFFFFFFFF)
|
| 1610 |
+
and s["regs"][5] == 2 and s["regs"][6] == 3)
|
| 1611 |
+
|
| 1612 |
+
|
| 1613 |
def rv32_netlist_check() -> bool:
|
| 1614 |
"""Verify the rv32-specific sub-circuits (NEUR, hazard, MULHU accumulator)
|
| 1615 |
are recoverable and correct from the shipped .inputs metadata alone."""
|
|
|
|
| 1673 |
return ok
|
| 1674 |
|
| 1675 |
|
| 1676 |
+
def fcvt_rm_check(cpu) -> bool:
|
| 1677 |
+
"""FCVT.W.S under every rounding mode against an exact rational reference,
|
| 1678 |
+
for directed edge encodings (subnormals, ties, saturation) and randoms;
|
| 1679 |
+
the emulator reference and the gate-routed method must both match."""
|
| 1680 |
+
from fractions import Fraction
|
| 1681 |
+
import random
|
| 1682 |
+
|
| 1683 |
+
def value(w):
|
| 1684 |
+
s, e, f = (w >> 31) & 1, (w >> 23) & 0xFF, w & 0x7FFFFF
|
| 1685 |
+
if e == 0:
|
| 1686 |
+
v = Fraction(f, (1 << 23) * (1 << 126))
|
| 1687 |
+
else:
|
| 1688 |
+
v = Fraction((1 << 23) | f, 1 << 23) * (Fraction(2) ** (e - 127))
|
| 1689 |
+
return -v if s else v
|
| 1690 |
+
|
| 1691 |
+
def round_frac(v, rm):
|
| 1692 |
+
fl = v.numerator // v.denominator # floor (correct for negatives)
|
| 1693 |
+
frac = v - fl
|
| 1694 |
+
if frac == 0:
|
| 1695 |
+
return fl
|
| 1696 |
+
if rm == 1: # RTZ
|
| 1697 |
+
return fl + 1 if v < 0 else fl
|
| 1698 |
+
if rm == 2: # RDN
|
| 1699 |
+
return fl
|
| 1700 |
+
if rm == 3: # RUP
|
| 1701 |
+
return fl + 1
|
| 1702 |
+
if frac < Fraction(1, 2):
|
| 1703 |
+
return fl
|
| 1704 |
+
if frac > Fraction(1, 2):
|
| 1705 |
+
return fl + 1
|
| 1706 |
+
if rm == 4: # RMM: ties away from zero
|
| 1707 |
+
return fl + 1 if v > 0 else fl
|
| 1708 |
+
return fl if fl % 2 == 0 else fl + 1 # RNE: ties to even
|
| 1709 |
+
|
| 1710 |
+
def sat(iv):
|
| 1711 |
+
if iv > 0x7FFFFFFF:
|
| 1712 |
+
return 0x7FFFFFFF
|
| 1713 |
+
if iv < -0x80000000:
|
| 1714 |
+
return 0x80000000
|
| 1715 |
+
return iv & MASK32
|
| 1716 |
+
|
| 1717 |
+
words = []
|
| 1718 |
+
for s in (0, 1):
|
| 1719 |
+
for e in (0, 1, 100, 125, 126, 127, 128, 130, 149, 150, 157, 158, 254, 255):
|
| 1720 |
+
for f in (0, 1, 0x400000, 0x7FFFFF):
|
| 1721 |
+
words.append((s << 31) | (e << 23) | f)
|
| 1722 |
+
rng = random.Random(0xFCF7)
|
| 1723 |
+
words += [rng.getrandbits(32) for _ in range(600)]
|
| 1724 |
+
|
| 1725 |
+
bad = None
|
| 1726 |
+
for w in words:
|
| 1727 |
+
s, e, f = (w >> 31) & 1, (w >> 23) & 0xFF, w & 0x7FFFFF
|
| 1728 |
+
for rm in (0, 1, 2, 3, 4):
|
| 1729 |
+
if e == 0xFF:
|
| 1730 |
+
exp = 0x7FFFFFFF if f else (0x80000000 if s else 0x7FFFFFFF)
|
| 1731 |
+
else:
|
| 1732 |
+
exp = sat(round_frac(value(w), rm))
|
| 1733 |
+
ref = fcvt_w_s_ref(w, rm)
|
| 1734 |
+
gate = cpu.fcvt_w_s(w, rm)
|
| 1735 |
+
if not (ref == gate == exp):
|
| 1736 |
+
bad = (w, rm, ref, gate, exp)
|
| 1737 |
+
break
|
| 1738 |
+
if bad:
|
| 1739 |
+
break
|
| 1740 |
+
if bad:
|
| 1741 |
+
w, rm, ref, gate, exp = bad
|
| 1742 |
+
print(f" fcvt rounding-mode check FAIL w={w:08x} rm={rm} "
|
| 1743 |
+
f"ref={ref:08x} gate={gate:08x} exp={exp:08x}")
|
| 1744 |
+
return False
|
| 1745 |
+
print(f" fcvt rounding-mode check ({len(words)} words x 5 modes vs exact) PASS")
|
| 1746 |
+
return True
|
| 1747 |
+
|
| 1748 |
+
|
| 1749 |
def rv32_test() -> int:
|
| 1750 |
print("Loading neural_rv32...")
|
| 1751 |
cpu = Rv32ThresholdCPU()
|
|
|
|
| 1757 |
("muldiv", prog_muldiv),
|
| 1758 |
("float_subset", prog_float),
|
| 1759 |
("fcvt_roundtrip", prog_fcvt),
|
| 1760 |
+
("fcvt_rounding_modes", prog_fcvt_rm),
|
| 1761 |
("neur_xor_net", prog_neur),
|
| 1762 |
("mmio_print", prog_mmio),
|
| 1763 |
]
|
|
|
|
| 1766 |
mem, budget, check = builder()
|
| 1767 |
all_ok &= lockstep(cpu, mem, budget, name, check)
|
| 1768 |
all_ok &= rv32_netlist_check()
|
| 1769 |
+
all_ok &= fcvt_rm_check(cpu)
|
| 1770 |
print(f"dual-issue pairs retired: {cpu.pairs_issued}")
|
| 1771 |
print("RV32:", "PASS" if all_ok else "FAIL")
|
| 1772 |
return 0 if all_ok else 1
|
todo.md
CHANGED
|
@@ -4,7 +4,6 @@ Unfinished work.
|
|
| 4 |
|
| 5 |
- The float add, multiply, and divide pipelines handle subnormal operands and produce subnormal results rather than flushing them to zero.
|
| 6 |
- The F extension includes a fused multiply-add instruction that rounds once.
|
| 7 |
-
- FCVT.W.S honors the instruction's rounding-mode field instead of always rounding toward zero.
|
| 8 |
- Program-counter sequencing and instruction decode are computed by threshold gates rather than by fixed wiring in the runtimes.
|
| 9 |
- The standalone float normalize stages, superseded by the composed pipelines' own normalizers, are removed from the circuit inventory.
|
| 10 |
- Every gate in the 32-bit multiply circuit resolves its .inputs to a defined signal.
|
|
|
|
| 4 |
|
| 5 |
- The float add, multiply, and divide pipelines handle subnormal operands and produce subnormal results rather than flushing them to zero.
|
| 6 |
- The F extension includes a fused multiply-add instruction that rounds once.
|
|
|
|
| 7 |
- Program-counter sequencing and instruction decode are computed by threshold gates rather than by fixed wiring in the runtimes.
|
| 8 |
- The standalone float normalize stages, superseded by the composed pipelines' own normalizers, are removed from the circuit inventory.
|
| 9 |
- Every gate in the 32-bit multiply circuit resolves its .inputs to a defined signal.
|