#pragma once
#include <stdint.h>

#include "metrolib/core/Check.h"
#include "metrolib/core/Utils.h"
#include "GateBoyLib/GateBoyConfig.h"

typedef const uint8_t wire;
struct triwire { wire state; };

/*__attribute__((always_inline))*/ inline wire bit0(uint32_t w) { return wire(w & 1); }
inline wire bit(uint32_t w, int i) { return wire((w >> i) & 1); }
inline wire bit(int w, int i) { return wire((w >> i) & 1); }
inline wire bit(int w) { return wire(w & 1); }

template<typename T>
inline void set_bit(T& t, int c, bool x) {
  t &= ~(1 << c);
  t |=  (x << c);
}

constexpr wire gen_clk(int64_t phase, uint8_t mask) {
  if (phase < 0 || phase >> 7) debugbreak();
  return !!(bit_reverse(mask) & (1 << phase));
}

//-----------------------------------------------------------------------------

struct Adder {
  wire sum;
  wire carry;
};

// ADD01
// ADD02
// ADD03 << CARRY
// ADD04
// ADD05
// ADD06 >> SUM
// ADD07
// ADD08
// ADD09
// ADD10 >> CARRY
// ADD11
// ADD12
// ADD13
// ADD14
// ADD15
// ADD16 << A
// ADD17 << B
// ADD18
// ADD19
// ADD20

inline Adder add3(wire a, wire b, wire c) {
  uint8_t s = bit0(a) + bit0(b) + bit0(c);
  return { bit(s, 0), bit(s, 1) };
}

//-----------------------------------------------------------------------------
// These _must_ be defined for all builds.

const wire BIT_DATA   = 0b00000001;
const wire TRI_DRIVEN = 0b00001000;
const wire BIT_CLOCK  = 0b00000010;

// These are only used for error checking and can be disabled in fast builds.
const wire BIT_PULLED = config_use_flags ? 0b00000100 : 0b00000000;
const wire BIT_DRIVEN = config_use_flags ? 0b00001000 : 0b00000000;
const wire BIT_OLD    = config_use_flags ? 0b00010000 : 0b00000000;
const wire BIT_NEW    = config_use_flags ? 0b00100000 : 0b00000000;
const wire TRI_NEW    = config_use_flags ? 0b00100000 : 0b00000000;

//-----------------------------------------------------------------------------

struct BitBase {
  BitBase() : state(0) {}
  //BitBase(uint8_t _state) : state(_state) {}

  wire qp_old() const { check_old(); return state; }
  wire qn_old() const { check_old(); return ~state; }

  wire qp_mid() const { return state; }
  wire qn_mid() const { return ~state; }

  wire qp_any() const { return state; }
  wire qn_any() const { return ~state; }

  wire qp_new() const { check_new(); return state; }
  wire qn_new() const { check_new(); return ~state; }

  //----------
  // stuff in this section for logic mode only

  //operator bool() const { return get_data(); }
  //BitBase operator~() const { BitBase b; b.state = ~state; return b; }
  //BitBase operator^(const BitBase& b) const { return BitBase(state ^ b.state); }

  void rst() { state &= ~1; }
  void set() { state |= 1; }

  wire get_data() const { return bit0(state); }
  void set_data(wire d) { state = (state & ~1) | bit0(d); }

  wire get_clk() const { return bit(state, 1); }
  void set_clk(wire c) { state = (state & ~2) | (bit0(c) << 1); }

  void dff_pp(wire CLKp, wire Dp) {
    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKp << 1) & BIT_CLOCK;
    wire d1 = (~clk_old & clk_new) ? Dp : state;
    state = bit0(d1) | clk_new | BIT_NEW | BIT_DRIVEN;
  }

  //----------

  void check_old() const {
    if (config_check_flags) {
      CHECK_P(bool(state & BIT_DRIVEN) != bool(state & BIT_PULLED));
      CHECK_P((state & (BIT_OLD | BIT_NEW)) == BIT_OLD);
    }
  }

  void check_new() const {
    if (config_check_flags) {
      CHECK_P(bool(state & BIT_DRIVEN) != bool(state & BIT_PULLED));
      CHECK_P((state & (BIT_OLD | BIT_NEW)) == BIT_NEW);
    }
  }

  void check_invalid() const {
    if (config_check_flags) {
      CHECK_N(state & (BIT_OLD | BIT_NEW));
    }
  }

  uint8_t state;

  // need default = for bit_purge
  //BitBase& operator=(const BitBase&) = delete;
};

static_assert(sizeof(BitBase) == 1, "Bad BitBase size");


inline wire bit(const BitBase& b) { return b.get_data(); }

//-----------------------------------------------------------------------------

struct Gate : public BitBase {
  wire out_any() const { return state; }
  wire out_old() const { check_old(); return state; }
  wire out_mid() const { return state; }
  wire out_new() const { check_new(); return state; }

  void hold() {
    state = BIT_NEW | BIT_DRIVEN | bit0(state);
  }

  void operator <<= (wire D) {
    state = BIT_NEW | BIT_DRIVEN | bit0(D);
  }
};

//-----------------------------------------------------------------------------

struct SigIn : public BitBase {
  wire out_any() const { return state; }
  wire out_old() const { check_old(); return state; }
  wire out_new() const { check_new(); return state; }

  void sig_in(wire D) {
    check_invalid();
    state = BIT_NEW | BIT_DRIVEN | bit0(D);
  }
};

//-----------------------------------------------------------------------------

struct SigOut : public BitBase {
  wire out_old() const { check_old(); return state; }
  wire out_new() const { check_new(); return state; }

  void sig_out(wire D) {
    check_invalid();
    state = BIT_NEW | BIT_DRIVEN | bit0(D);
  }
};

//-----------------------------------------------------------------------------
// Generic DFF

struct DFF : public BitBase {
  void dff_r(wire CLKp, wire RSTn, wire Dp) {
    check_invalid();

    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKp << 1) & BIT_CLOCK;

    wire d1 = (~clk_old & clk_new) ? Dp : state;

    state = bit0(d1 & RSTn) | clk_new | BIT_NEW | BIT_DRIVEN;
  }
};

//-----------------------------------------------------------------------------
// 8-rung register with no reset and dual outputs.
// BGP has to latch on the rising edge of the clock or m3_bgp_change is way off.

// DFF8_01 |o------O | << CLKp
// DFF8_02 |====O====| << Dp
// DFF8_03 |  -----  |
// DFF8_04 |O-------o| << CLKn
// DFF8_05 |  -----  |
// DFF8_06 |==     ==|
// DFF8_07 |xxx-O-xxx| >> Qp
// DFF8_08 |xxx-O-xxx| >> Qn (or this rung can be empty)

struct DFF8 : public BitBase {

  void set_state(uint8_t new_state) { state = new_state ^ 1; }

  void dff8(wire CLKp, wire Dp) {
    check_invalid();

    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKp << 1) & BIT_CLOCK;

    wire d1 = (!clk_old && clk_new) ? Dp : state;

    state = bit0(d1) | clk_new | BIT_NEW | BIT_DRIVEN;
  }
};

//-----------------------------------------------------------------------------
// 9-rung register with async reset and dual outputs.
// Looks like DFF8 with a hat and a belt.

// DFF9_01 | O===--o |
// DFF9_02 |==--O====| << CLKp
// DFF9_03 | ------- | << Dp
// DFF9_04 |o-------O| << CLKn
// DFF9_05 |  -----  |
// DFF9_06 |--xxOxx--| << RSTn
// DFF9_07 |o-------o|
// DFF9_08 |xxx-O-xxx| >> Qp
// DFF9_09 |xxx-O-xxx| >> Qn

struct DFF9 : public BitBase {

  void set_state(uint8_t new_state) { state = new_state; }

  void dff9(wire CLKp, wire RSTn, wire Dp) {
    check_invalid();

    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKp << 1) & BIT_CLOCK;

    wire d1 = (clk_old == 0 && clk_new != 0) ? Dp : state;

    state = bit0(d1 & RSTn) | clk_new | BIT_NEW | BIT_DRIVEN;
  }
};

//-----------------------------------------------------------------------------
// Reg11 is used by the background pixel temp state
// Not sure why it's special.

// DFF11_01 nc
// DFF11_02 << RSTp? // FIXME trace this
// DFF11_03 << D
// DFF11_04 nc
// DFF11_05 << CLKp
// DFF11_06 nc
// DFF11_07 nc
// DFF11_08 << CLKn
// DFF11_09 << RSTn
// DFF11_10 nc
// DFF11_11 >> Qp?

struct DFF11 : public BitBase {
  void dff11(wire CLKp, wire RSTn, wire Dp) {
    check_invalid();
    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKp << 1) & BIT_CLOCK;

    wire d1 = (~clk_old & clk_new) ? Dp : state;

    state = bit0(d1 & RSTn) | clk_new | BIT_NEW | BIT_DRIVEN;
  }
};

//-----------------------------------------------------------------------------
// DFF13_01 nc
// DFF13_02 << RSTn
// DFF13_03 << D
// DFF13_04 nc
// DFF13_05 << CLKp
// DFF13_06 nc
// DFF13_07 nc
// DFF13_08 << CLKn
// DFF13_09 << RSTn
// DFF13_10 nc
// DFF13_11 nc
// DFF13_12 >> Qn
// DFF13_13 >> Q

struct DFF13 : public BitBase {
  void dff13(wire CLKp, wire RSTn, wire Dp) {
    check_invalid();
    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKp << 1) & BIT_CLOCK;

    wire d1 = (~clk_old & clk_new) ? Dp : state;

    state = bit0(d1 & RSTn) | clk_new | BIT_NEW | BIT_DRIVEN;
  }
};

//-----------------------------------------------------------------------------
// DFF17_01 SC
// DFF17_02 << CLKp
// DFF17_03 SC
// DFF17_04 --
// DFF17_05 --
// DFF17_06 << RSTn  // must be RSTn, see WUVU/VENA/WOSU
// DFF17_07 << D
// DFF17_08 --
// DFF17_09 SC
// DFF17_10 --
// DFF17_11 --
// DFF17_12 SC
// DFF17_13 << RSTn
// DFF17_14 --
// DFF17_15 --
// DFF17_16 >> QN   _MUST_ be QN - see TERO
// DFF17_17 >> Q    _MUST_ be Q  - see TERO

struct DFF17 : public BitBase {
  void dff(wire CLKp, wire Dp) {
    check_invalid();
    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKp << 1) & BIT_CLOCK;

    wire d1 = (~clk_old & clk_new) ? Dp : state;

    state = bit0(d1) | clk_new | BIT_NEW | BIT_DRIVEN;
  }


  void dff17(wire CLKp, wire RSTn, wire Dp) {
    check_invalid();
    dff17_any(CLKp, RSTn, Dp);
  }

  void dff17_any(wire CLKp, wire RSTn, wire Dp) {
    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKp << 1) & BIT_CLOCK;

    wire d1 = (~clk_old & clk_new) ? Dp : state;

    state = bit0(d1 & RSTn) | clk_new | BIT_NEW | BIT_DRIVEN;
  }


  void dff17_clk(wire CLKp, wire Dp) {
    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKp << 1) & BIT_CLOCK;

    wire d1 = (~clk_old & clk_new) ? Dp : state;

    state = bit0(d1) | clk_new | BIT_NEW | BIT_DRIVEN;
  }

  void dff17_rst(wire RSTn) {
    if (!bit0(RSTn)) {
      state &= ~1;
    }
  }



};



//-----------------------------------------------------------------------------
// 20-rung counter ff with async load. Only used by TIMA and a few audio regs.

// DFF20_01 >> Q
// DFF20_02 nc
// DFF20_03 << D
// DFF20_04 << LOADp
// DFF20_05 nc
// DFF20_06 sc
// DFF20_07 nc
// DFF20_08 nc
// DFF20_09 nc
// DFF20_10 nc
// DFF20_11 sc
// DFF20_12 nc
// DFF20_13 nc
// DFF20_14 << LOADp
// DFF20_15 nc
// DFF20_16 << D
// DFF20_17 >> Qn
// DFF20_18 sc
// DFF20_19 sc
// DFF20_20 << CLKn

struct DFF20 : public BitBase {

  void dff20_clk(wire CLKn) {
    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKn << 1) & BIT_CLOCK;
    wire newD = (clk_old & ~clk_new) ? ~state : state;
    state = bit0(newD) | (bit0(CLKn) << 1) | BIT_NEW | BIT_DRIVEN;
  }

  void dff20_async(wire LOADp, wire Dp) {
    if (bit0(LOADp)) {
      state = (state & ~1) | (Dp & 1);
    }
  }

  void dff20_any(wire CLKn, wire LOADp, wire Dp) {
    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKn << 1) & BIT_CLOCK;
    wire newD = bit0(LOADp) ? Dp : (clk_old & ~clk_new) ? ~state : state;
    state = bit0(newD) | (bit0(CLKn) << 1) | BIT_NEW | BIT_DRIVEN;
  }

  void dff20(wire CLKn, wire LOADp, wire newD) {
    check_invalid();
    dff20_any(CLKn, LOADp, newD);
  }
};

//-----------------------------------------------------------------------------
// DFF with async set/reset. Used by pixel pipes, serial data register.

// SETn/RSTn are correct and not swapped, see serial + ALUR_RSTn

// DFF22_01 sc
// DFF22_02 nc
// DFF22_03 nc
// DFF22_04 nc
// DFF22_05 sc
// DFF22_06 sc
// DFF22_07 << D
// DFF22_08 nc
// DFF22_09 sc
// DFF22_10 nc
// DFF22_11 sc
// DFF22_12 nc
// DFF22_13 nc
// DFF22_14 << SETn _MUST_ be SETn, see serial
// DFF22_15 >> Qn
// DFF22_16 >> Q
// DFF22_17 << RSTn _MUST_ be RSTn, see serial
// DFF22_18 nc
// DFF22_19 sc
// DFF22_20 sc
// DFF22_21 sc
// DFF22_22 << CLKp

struct DFF22 : public BitBase {
  void dff22_any(wire CLKp, wire SETn, wire RSTn, wire Dp) {
    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKp << 1) & BIT_CLOCK;

    wire d1 = (~clk_old & clk_new) ? Dp : state;

    state = bit0((d1 | (~SETn)) & RSTn) | clk_new | BIT_NEW | BIT_DRIVEN;
  }

  void dff22(wire CLKp, wire SETn, wire RSTn, wire Dp) {
    check_invalid();
    dff22_any(CLKp, SETn, RSTn, Dp);
  }

  void dff22_sync(wire CLKp, wire Dp) {
    check_invalid();
    wire clk_old = state & BIT_CLOCK;
    wire clk_new = (CLKp << 1) & BIT_CLOCK;

    wire d1 = (~clk_old & clk_new) ? Dp : state;

    state = bit0(d1) | clk_new | BIT_DRIVEN;
  }

  void dff22_async(wire SETn, wire RSTn) {
    check_invalid();
    wire clk_new = state & BIT_CLOCK;
    state = bit0((state | (~SETn)) & RSTn) | clk_new | BIT_NEW | BIT_DRIVEN;
  }
};

//-----------------------------------------------------------------------------
// Bus with pull-up

// TYGO_01 << BUS_CPU_D2p
// TYGO_02 nc
// TYGO_03 nc
// TYGO_04 nc
// TYGO_05 << RAHU_04
// TYGO_06 << BUS_CPU_D2p
// TYGO_07 nc
// TYGO_08 nc
// TYGO_09 >> BUS_VRAM_D2p
// TYGO_10 nc

// tri6_nn : top rung tadpole _not_ facing second rung dot.
// tri6_pn : top rung tadpole facing second rung dot.

// TRI6NN_01 :
// TRI6NN_02 : NC
// TRI6NN_03 : NC
// TRI6NN_04 :
// TRI6NN_05 : NC
// TRI6NN_06 :

inline triwire tri_pp(wire OEp, wire Dp) {
  return { wire(bit0(OEp) ? TRI_NEW | TRI_DRIVEN | bit0(Dp) : TRI_NEW) };
}

inline triwire tri6_nn(wire OEn, wire Dn) {
  return { wire(bit0(OEn) ? TRI_NEW : TRI_NEW | TRI_DRIVEN | bit0(~Dn)) };
}

inline triwire tri6_pn(wire OEp, wire Dn) {
  return { wire(bit0(OEp) ? TRI_NEW | TRI_DRIVEN | bit0(~Dn) : TRI_NEW) };
}

inline triwire tri10_np(wire OEn, wire Dp) {
  return { wire(bit0(OEn) ? TRI_NEW : TRI_NEW | TRI_DRIVEN | bit0(Dp)) };
}

struct Bus : public BitBase {
  wire out_old() const { check_old(); return state; }
  wire out_any() const { return state; }
  wire out_mid() const { return state; }
  wire out_new() const { check_new(); return state; }

  void tri_bus(triwire t) {
    check_new();

    // if both the new and old state are both driven, that's a bus collision.
    CHECK_N((t.state & TRI_DRIVEN) && (state & BIT_DRIVEN));

    if (t.state & TRI_DRIVEN) state = t.state;
  }
};

//-----------------------------------------------------------------------------
// Pin structs store the bit as it apperas INSIDE the chip. Bits are inverted
// when traveling across the chip boundary.

struct PinBase : public BitBase {
  PinBase(uint8_t _state) {
    state = _state;
  }

  wire qp_int_old() const { return qp_old(); }
  wire qp_int_any() const { return qp_any(); }
  wire qp_int_new() const { return qp_new(); }

  wire qp_ext_old() const { return qn_old(); }
  wire qp_ext_new() const { return qn_new(); }
  wire qn_ext_new() const { return qp_new(); }
};

struct PinIO : public PinBase {
  PinIO() : PinBase(0) {}
  void pin_io(wire int_PUn, wire int_HI, wire int_LO, wire ext_OEp, wire ext_Dp) {
    check_invalid();
    pin_io_any(int_PUn, int_HI, int_LO, ext_OEp, ext_Dp);
  }

  void pin_io_any(wire int_PUn, wire int_HI, wire int_LO, wire ext_OEp, wire ext_Dp) {
    (void)int_PUn;

    if (bit0(int_HI) == bit0(int_LO)) {
      state = BIT_NEW | BIT_DRIVEN | bit0(int_LO);
    }
    else {
      if (bit0(int_LO)) {
        // shootthrough, this is bad
        CHECK_P(false);
      }
      else {
        // hi-z, can be driven externally
        CHECK_N(bit0(int_PUn)); // must not be floating

        // this is the _internal_ bit, so if this is pulled high externally it should read 0 internally.
        // i think...
        state = BIT_NEW | BIT_PULLED | 0;

        //state = BIT_NEW | BIT_PULLED | 1;
      }
    }

    if (bit0(ext_OEp)) {
      CHECK_N(state & BIT_DRIVEN);
      // External bit is inverted when crossing the pin
      state = BIT_NEW | BIT_DRIVEN | bit0(~ext_Dp);
    }

    CHECK_P(bool(state & BIT_DRIVEN) != bool(state & BIT_PULLED));
    CHECK_P(bool(state & BIT_NEW));
  }
};

//-----------------------------------------------------------------------------

struct PinIn : public PinBase {
  PinIn() : PinBase(0) {};
  PinIn(uint8_t _state) : PinBase(_state) {}

  void pin_in(wire ext_Dp) {
    check_invalid();
    state = ((~ext_Dp) & BIT_DATA) | BIT_DRIVEN | BIT_NEW;
  }
};

//-----------------------------------------------------------------------------

struct PinOut : public PinBase {
  PinOut() : PinBase(0) {}
  void pin_out(wire int_HI, wire int_LO) {
    check_invalid();

    if (!bit0(int_HI) && !bit0(int_LO)) {
      // internal bit 0, external bit 1
      state = BIT_NEW | BIT_DRIVEN | 0;
    }
    else if (bit0(int_HI) && bit0(int_LO)) {
      // internal bit 1, external bit 0
      state = BIT_NEW | BIT_DRIVEN | 1;
    }
    else if (bit0(int_HI) && !bit0(int_LO)) {
      state = BIT_NEW;
    }
    else if (!bit0(int_HI) && bit0(int_LO)) {
      // shootthrough, this is bad
      debugbreak();
    }
  }
};

//-----------------------------------------------------------------------------

struct PinClock {
  wire clkgood_old() const { return CLKGOOD.qp_int_old(); }
  wire clk_old()     const { return CLK.qp_int_old(); }

  wire clkgood_new() const { return CLKGOOD.qp_int_new(); }
  wire clk_new()     const { return CLK.qp_int_new(); }

  void pin_clk(wire clk, wire clkgood) {
    CLK.pin_in(clk);
    CLKGOOD.pin_in(clkgood);
  }

  PinIn CLK;
  PinIn CLKGOOD;
};

//-----------------------------------------------------------------------------
// 6-rung cell, "arms" on ground side

// NORLATCH_01 << SET
// NORLATCH_02 nc
// NORLATCH_03 >> QN
// NORLATCH_04 >> Q
// NORLATCH_05 nc
// NORLATCH_06 << RST

struct NorLatch : public BitBase {
  void rst() {
    state = BIT_DRIVEN | BIT_NEW | 0;
  }

  void nor_latch(wire SETp, wire RSTp) {
    check_invalid();
    state |= SETp;
    state &= ~RSTp;

    state = (state & BIT_DATA) | BIT_DRIVEN | BIT_NEW;
  }
};

//-----------------------------------------------------------------------------
// 6-rung cell, "arms" on VCC side. Only TAKA/LONY seem to use this cell

// NANDLATCH_01 << SETn
// NANDLATCH_02 nc
// NANDLATCH_03 >> Q
// NANDLATCH_04 >> QN
// NANDLATCH_05 nc
// NANDLATCH_06 << RSTn

struct NandLatch : public BitBase {
  void nand_latch(wire SETn, wire RSTn) {
    check_invalid();
    state |= ~SETn;
    state &= RSTn;

    state = (state & BIT_DATA) | BIT_DRIVEN | BIT_NEW;
  }
};

//-----------------------------------------------------------------------------
// Yellow 10-rung cells on die. Transparent latch, probably.

// TPLATCH_01 << HOLDn
// TPLATCH_02 nc
// TPLATCH_03 << D
// TPLATCH_04 nc
// TPLATCH_05 nc
// TPLATCH_06 nc
// TPLATCH_07 nc
// TPLATCH_08 >> Q
// TPLATCH_09 nc
// TPLATCH_10 >> Qn

// Output 08 must _not_ be inverting, see pin EXT_A14p
// Output 10 _must_ be inverting...?

// FIXME - why do we have latchN and latchP?

struct TpLatch : public BitBase {
  void tp_latchn(wire HOLDn, wire Dp) {
    check_invalid();
    wire SETp = HOLDn & Dp;
    wire RSTp = HOLDn & ~Dp;

    state |= SETp;
    state &= ~RSTp;

    state = (state & BIT_DATA) | BIT_DRIVEN | BIT_NEW;
  }

  void tp_latchp(wire HOLDp, wire Dp) {
    check_invalid();
    wire SETp = (~HOLDp) & Dp;
    wire RSTp = (~HOLDp) & ~Dp;

    state |= SETp;
    state &= ~RSTp;

    state = (state & BIT_DATA) | BIT_DRIVEN | BIT_NEW;
  }
};

//-----------------------------------------------------------------------------

template<typename T>
void commit_regs(T& t) {
  if (!config_check_flags && !config_use_flags) return;

  uint8_t* cursor = (uint8_t*)&t;
  bool bad_bits = false;
  for (size_t i = 0; i < sizeof(T); i++) {
    uint8_t s = *cursor;
    if (config_check_flags) {
      auto drive_flags = s & (BIT_DRIVEN | BIT_PULLED);

      bool bad_bit = false;

      if (drive_flags == (BIT_DRIVEN | BIT_PULLED)) {
        LOG_Y("Bit %d both driven and pulled up! ", i);
        bad_bit = true;
      }

      if (drive_flags == 0) {
        LOG_Y("Bit %d floating! ", i);
        bad_bit = true;
      }

      auto oldnew_flags = s & (BIT_OLD | BIT_NEW);

      if (oldnew_flags != BIT_NEW) {
        LOG_Y("Bit %d not dirty after sim pass! ", i);
        bad_bit = true;
      }

      if (bad_bit) {
        printf("\n");
      }

      bad_bits |= bad_bit;
    }

    *cursor++ = (s & 0b00001111) | BIT_OLD;
  }
  CHECK_N(bad_bits);
}

//-----------------------------------------------------------------------------
