diff options
Diffstat (limited to 'WinQuake')
| -rw-r--r-- | WinQuake/pum_render.c | 111 |
1 files changed, 74 insertions, 37 deletions
diff --git a/WinQuake/pum_render.c b/WinQuake/pum_render.c index e030f72..af0d3b5 100644 --- a/WinQuake/pum_render.c +++ b/WinQuake/pum_render.c @@ -1,7 +1,5 @@ /* -============================================================================== PUM_RENDER.C -- DRAM Bender based Process-using-Memory (PuM) renderer -============================================================================== This file implements the host-side half of the PuM rendering pipeline. It turns high-level "bulk bitwise" requests from the Quake software renderer @@ -105,6 +103,8 @@ static void PUM_ComputeNot (Program *p, unsigned int src, unsigned int dst); static void PUM_ReadRow (Program *p, unsigned int row, int dst_reg); static void PUM_Execute (Program *p); static void PUM_StageRow (Program *p, unsigned int row, const byte *src, int n); +static void pum_compute_one_trial (Program *prog, pum_op_t op, unsigned int dstrow); +static void pum_majority_vote (const byte *a, const byte *b, const byte *c, byte *out, int n); int PUM_Init (void) { @@ -413,6 +413,60 @@ static void cpu_not (const byte *a, byte *d, int n) * throughput benefit. */ +/* + * Compute a single PuM trial of `op` into the destination row `dstrow`. + * + * Operands are assumed to have already been staged in T0 (and T1 for binary + * operations). This routine appends the command sequence and a read-back of + * `dstrow` to `prog`. Because in-DRAM Boolean logic is probabilistic, every + * logical output is computed three times (three independent trials into three + * independent destination rows) and the caller majority-votes the results. + */ +static void pum_compute_one_trial (Program *prog, pum_op_t op, + unsigned int dstrow) +{ + if (op == PUM_OP_AND) + { + PUM_RowClone (prog, PUM_ROW_C0, PUM_ROW_T2); + PUM_TripleRowActivate (prog, 1, 1); + PUM_RowClone (prog, PUM_ROW_T0, dstrow); + } + else if (op == PUM_OP_OR) + { + PUM_RowClone (prog, PUM_ROW_C1, PUM_ROW_T2); + PUM_TripleRowActivate (prog, 1, 1); + PUM_RowClone (prog, PUM_ROW_T0, dstrow); + } + else if (op == PUM_OP_XOR) + { + // XOR = (A & ~B) | (~A & B) + PUM_ComputeNot (prog, PUM_ROW_T1, PUM_ROW_T3); // T3 = ~B + PUM_RowClone (prog, PUM_ROW_T0, PUM_ROW_T2); // T2 = A + PUM_RowClone (prog, PUM_ROW_T3, PUM_ROW_T0); // T0 = ~B + PUM_RowClone (prog, PUM_ROW_T2, PUM_ROW_T1); // T1 = A + PUM_RowClone (prog, PUM_ROW_C0, PUM_ROW_T2); // T2 = 0 + PUM_TripleRowActivate (prog, 1, 1); // T0 = ~B & A + PUM_RowClone (prog, PUM_ROW_T0, dstrow); + } + else + { + PUM_ComputeNot (prog, PUM_ROW_T0, dstrow); + } + + PUM_ReadRow (prog, dstrow, 0); +} + +/* + * Majority-vote three byte arrays: out = (a&b) | (a&c) | (b&c). + */ +static void pum_majority_vote (const byte *a, const byte *b, const byte *c, + byte *out, int n) +{ + int i; + for (i = 0; i < n; i++) + out[i] = (a[i] & b[i]) | (a[i] & c[i]) | (b[i] & c[i]); +} + static void pum_stage_and_run (const byte *a, const byte *b, byte *dst, int num_bytes, pum_op_t op) { @@ -429,51 +483,35 @@ static void pum_stage_and_run (const byte *a, const byte *b, byte *dst, if (chunk > PUM_ROW_BYTES) chunk = PUM_ROW_BYTES; + // Stage once, reuse on all trials Program prog; - // Write operand PUM_StageRow (&prog, PUM_ROW_T0, a + offset, chunk); if (op != PUM_OP_NOT) PUM_StageRow (&prog, PUM_ROW_T1, b + offset, chunk); - if (op == PUM_OP_AND) - { - PUM_RowClone (&prog, PUM_ROW_C0, PUM_ROW_T2); - PUM_TripleRowActivate (&prog, 1, 1); - PUM_RowClone (&prog, PUM_ROW_T0, PUM_ROW_DST0); - PUM_ReadRow (&prog, PUM_ROW_DST0, 0); - } - else if (op == PUM_OP_OR) - { - PUM_RowClone (&prog, PUM_ROW_C1, PUM_ROW_T2); - PUM_TripleRowActivate (&prog, 1, 1); - PUM_RowClone (&prog, PUM_ROW_T0, PUM_ROW_DST0); - PUM_ReadRow (&prog, PUM_ROW_DST0, 0); - } - else if (op == PUM_OP_XOR) - { - // XOR = (A & ~B) | (~A & B) - PUM_ComputeNot (&prog, PUM_ROW_T1, PUM_ROW_T3); - PUM_RowClone (&prog, PUM_ROW_T0, PUM_ROW_T2); - PUM_RowClone (&prog, PUM_ROW_T3, PUM_ROW_T0); - PUM_RowClone (&prog, PUM_ROW_T2, PUM_ROW_T1); - PUM_RowClone (&prog, PUM_ROW_C0, PUM_ROW_T2); - PUM_TripleRowActivate (&prog, 1, 1); // T0 & T1 -> T0 - PUM_ReadRow (&prog, PUM_ROW_T0, 0); - } - else - { - PUM_ComputeNot (&prog, PUM_ROW_T0, PUM_ROW_DST0); - PUM_ReadRow (&prog, PUM_ROW_DST0, 0); - } + // TMR + pum_compute_one_trial (&prog, op, PUM_ROW_DST0); + pum_compute_one_trial (&prog, op, PUM_ROW_DST1); + pum_compute_one_trial (&prog, op, PUM_ROW_DST2); PUM_Execute (&prog); - pum_platform->receiveData(dst + offset, chunk); + { + byte r0[PUM_ROW_BYTES]; + byte r1[PUM_ROW_BYTES]; + byte r2[PUM_ROW_BYTES]; + + pum_platform->receiveData(r0, PUM_ROW_BYTES); + pum_platform->receiveData(r1, PUM_ROW_BYTES); + pum_platform->receiveData(r2, PUM_ROW_BYTES); + + pum_majority_vote (r0, r1, r2, dst + offset, chunk); + } offset += chunk; } - // fallback + // CPU fallback if (offset < num_bytes || !pum_active) { switch (op) @@ -564,8 +602,7 @@ void PUM_LightMaskAndTexel (byte *dst, const byte *src, const byte *mask, void PUM_EdgeSpanInit (byte *dst, const byte *clear, int num_bytes) { - /* Initialise span state by clearing: dst = dst & clear (or, for an - all-zero clear, this is a memset). Kept as a PuM op for symmetry. */ + // Init span state pum_stage_and_run(dst, clear, dst, num_bytes, PUM_OP_AND); } |
