160 lines
5.7 KiB
Python
160 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
# Emits the C source of the smoke check "constant shifts and i32 +/- 1",
|
|
# with kExp holding the expected results computed here.
|
|
V32 = [0x00000000, 0xFFFFFFFF, 0x80000000, 0x7FFFFFFF, 0x12345678, 0xFEDCBA98, 0x00018001, 0x8000FFFF]
|
|
V16 = [0x0000, 0xFFFF, 0x8000, 0x7FFF, 0x1234, 0xFEDC, 0x8001, 0x4000]
|
|
# (start, count) for the down-counting loops: each decrements a u32 `count`
|
|
# times from `start` and returns the final value's halves and a checksum.
|
|
DOWN = [(0x00010002, 5), (0x00000002, 4), (0x00020000, 1), (0x80000001, 3), (0x00000000, 1), (0x00030001, 2)]
|
|
UP = [(0x0000FFFE, 5), (0xFFFFFFFE, 4), (0x0001FFFF, 1), (0x7FFFFFFF, 2)]
|
|
|
|
def s32(x):
|
|
x &= 0xFFFFFFFF
|
|
return x - (1 << 32) if x & 0x80000000 else x
|
|
|
|
def s16(x):
|
|
x &= 0xFFFF
|
|
return x - (1 << 16) if x & 0x8000 else x
|
|
|
|
exp = []
|
|
for op in ("shl", "shr", "sar"):
|
|
for n in range(1, 32):
|
|
for v in V32:
|
|
if op == "shl":
|
|
r = (v << n) & 0xFFFFFFFF
|
|
elif op == "shr":
|
|
r = v >> n
|
|
else:
|
|
r = (s32(v) >> n) & 0xFFFFFFFF
|
|
exp += [r & 0xFFFF, r >> 16]
|
|
for n in range(1, 16):
|
|
for v in V16:
|
|
exp.append((s16(v) >> n) & 0xFFFF)
|
|
# Down loops: final value and the sum (mod 2^16) of every low half seen.
|
|
for start, cnt in DOWN:
|
|
v = start
|
|
s = 0
|
|
for _ in range(cnt):
|
|
v = (v - 1) & 0xFFFFFFFF
|
|
s = (s + (v & 0xFFFF) + (v >> 16)) & 0xFFFF
|
|
exp += [v & 0xFFFF, v >> 16, s]
|
|
for start, cnt in UP:
|
|
v = start
|
|
s = 0
|
|
for _ in range(cnt):
|
|
v = (v + 1) & 0xFFFFFFFF
|
|
s = (s + (v & 0xFFFF) + (v >> 16)) & 0xFFFF
|
|
exp += [v & 0xFFFF, v >> 16, s]
|
|
|
|
def rows(vals, per, fmt):
|
|
out = []
|
|
for i in range(0, len(vals), per):
|
|
out.append(" " + ", ".join(fmt % x for x in vals[i:i + per]) + ",")
|
|
return "\n".join(out)
|
|
|
|
print("""// Every constant i32 shift (<< >>u >>s by 1..31) on 8 values, every
|
|
// constant i16 >>s (1..15) on 8 values, and in-place i32 -= 1 / += 1 loop
|
|
// counters across 0x0000 / 0x10000 / 0x80000000 / 0xFFFFFFFF. kExp is
|
|
// computed by genShiftDec.py. Mailbox: 0x025000 = mismatches, 0x025002 =
|
|
// first failing index, 0x025004 = 0xC0DE done. int is 16 bits, long 32.
|
|
typedef unsigned short u16;
|
|
typedef short s16;
|
|
typedef unsigned long u32;
|
|
typedef long s32;
|
|
#define NOI __attribute__((noinline)) static
|
|
#define NV 8
|
|
static const u32 kV32[NV] = { %s };
|
|
static const u16 kV16[NV] = { %s };""" % (", ".join("0x%08XUL" % v for v in V32), ", ".join("0x%04Xu" % v for v in V16)))
|
|
print("static const u16 kExp[%d] = {\n%s\n};" % (len(exp), rows(exp, 12, "0x%04X")))
|
|
print(r"""#define SH(n) \
|
|
NOI u32 shl##n(u32 x) { return x << n; } \
|
|
NOI u32 shr##n(u32 x) { return x >> n; } \
|
|
NOI u32 sar##n(u32 x) { return (u32)((s32)x >> n); }
|
|
#define L7(M, a, b, c, d, e, f, g) M(a) M(b) M(c) M(d) M(e) M(f) M(g)
|
|
#define L8(M, a, b, c, d, e, f, g, h) L7(M, a, b, c, d, e, f, g) M(h)
|
|
L8(SH, 1, 2, 3, 4, 5, 6, 7, 8) L8(SH, 9, 10, 11, 12, 13, 14, 15, 16)
|
|
L8(SH, 17, 18, 19, 20, 21, 22, 23, 24) L7(SH, 25, 26, 27, 28, 29, 30, 31)
|
|
#define S16(n) NOI u16 sa16_##n(u16 x) { return (u16)((s16)x >> n); }
|
|
L8(S16, 1, 2, 3, 4, 5, 6, 7, 8) L7(S16, 9, 10, 11, 12, 13, 14, 15)
|
|
typedef u32 (*Fn32)(u32);
|
|
typedef u16 (*Fn16)(u16);
|
|
#define P31(p) p##1, p##2, p##3, p##4, p##5, p##6, p##7, p##8, p##9, p##10, \
|
|
p##11, p##12, p##13, p##14, p##15, p##16, p##17, p##18, p##19, p##20, \
|
|
p##21, p##22, p##23, p##24, p##25, p##26, p##27, p##28, p##29, p##30, p##31
|
|
static Fn32 const kFn32[93] = { P31(shl), P31(shr), P31(sar) };
|
|
static Fn16 const kFn16[15] = { sa16_1, sa16_2, sa16_3, sa16_4, sa16_5, sa16_6, sa16_7,
|
|
sa16_8, sa16_9, sa16_10, sa16_11, sa16_12, sa16_13, sa16_14, sa16_15 };
|
|
// The counter lives in a frame / direct-page slot across the loop, where
|
|
// W65816I32IncFold turns its -= 1 / += 1 into the conditional-carry form.
|
|
static volatile u16 gSink;
|
|
NOI u32 down(u32 v, u16 n, u16 *sum) {
|
|
u16 s = 0;
|
|
while (n != 0u) {
|
|
v--;
|
|
s = (u16)(s + (u16)v + (u16)(v >> 16));
|
|
gSink = s;
|
|
n--;
|
|
}
|
|
*sum = s;
|
|
return v;
|
|
}
|
|
NOI u32 up(u32 v, u16 n, u16 *sum) {
|
|
u16 s = 0;
|
|
while (n != 0u) {
|
|
v++;
|
|
s = (u16)(s + (u16)v + (u16)(v >> 16));
|
|
gSink = s;
|
|
n--;
|
|
}
|
|
*sum = s;
|
|
return v;
|
|
}""")
|
|
print("static const u32 kDownStart[%d] = { %s };" % (len(DOWN), ", ".join("0x%08XUL" % d[0] for d in DOWN)))
|
|
print("static const u16 kDownCount[%d] = { %s };" % (len(DOWN), ", ".join("%du" % d[1] for d in DOWN)))
|
|
print("static const u32 kUpStart[%d] = { %s };" % (len(UP), ", ".join("0x%08XUL" % d[0] for d in UP)))
|
|
print("static const u16 kUpCount[%d] = { %s };" % (len(UP), ", ".join("%du" % d[1] for d in UP)))
|
|
print(r"""static u16 gBad;
|
|
static u16 gFirst = 0xFFFFu;
|
|
static u16 gIdx;
|
|
static void check(u16 got) {
|
|
if (got != kExp[gIdx] && gBad++ == 0u) {
|
|
gFirst = gIdx;
|
|
}
|
|
gIdx++;
|
|
}
|
|
int main(void) {
|
|
u16 f;
|
|
u16 i;
|
|
u16 s;
|
|
u32 r;
|
|
for (f = 0u; f < 93u; f++) {
|
|
for (i = 0u; i < NV; i++) {
|
|
r = kFn32[f](kV32[i]);
|
|
check((u16)r);
|
|
check((u16)(r >> 16));
|
|
}
|
|
}
|
|
for (f = 0u; f < 15u; f++) {
|
|
for (i = 0u; i < NV; i++) {
|
|
check(kFn16[f](kV16[i]));
|
|
}
|
|
}""")
|
|
print(" for (i = 0u; i < %du; i++) {" % len(DOWN))
|
|
print(r""" r = down(kDownStart[i], kDownCount[i], &s);
|
|
check((u16)r);
|
|
check((u16)(r >> 16));
|
|
check(s);
|
|
}""")
|
|
print(" for (i = 0u; i < %du; i++) {" % len(UP))
|
|
print(r""" r = up(kUpStart[i], kUpCount[i], &s);
|
|
check((u16)r);
|
|
check((u16)(r >> 16));
|
|
check(s);
|
|
}
|
|
*(volatile u16 *)0x025000UL = gBad;
|
|
*(volatile u16 *)0x025002UL = gFirst;
|
|
*(volatile u16 *)0x025004UL = 0xC0DEu;
|
|
for (;;) {
|
|
}
|
|
return 0;
|
|
}""")
|