aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WinQuake/pum_render.c111
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);
}