Games need randomness, and CXNN supplies it - a random byte masked by NN. To keep the result exactly testable you feed the machine a random source it can call, so a stubbed source makes the mask assertion deterministic.
Implement CXNN so it sets VX to a random byte ANDed with NN, drawing from an injectable random source.
CXNN sets VX to a random byte ANDed with NN. The mask is what makes it useful: a game wanting a random value in 0..15 uses NN = 0x0F to keep only the low four bits, and NN = 0xFF passes the whole random byte through. The randomness comes from a real generator in normal use, but a real generator is exactly what a spec-first lesson can not assert against.
The fix is to make the random source a replaceable input to the machine rather than a hardwired call - a function the VM holds and invokes. In tests you install a stub that always returns a known byte (here 0xAB), which turns CXNN into a pure, checkable AND: 0xAB & 0x0F is 0x0B, 0xAB & 0xF0 is 0xA0. This is language-neutral - every language can pass in a fixed-value function - and it verifies the one behaviour that is actually the opcode’s own: the masking. In the finished emulator you wire a real seeded generator into that same slot.
type VM struct {// ... existing fields ...rand func() byte // injectable random source; real runs use a RNG}case 0xC000:x, nn := byte(op>>8&0x0F), byte(op&0x00FF)v.V[x] = v.rand() & nn