[ { "id": "shift", "name": "Shift quirk", "description": "On most systems the shift opcodes take `vY` as input and stores the shifted version of `vY` into `vX`. The interpreters for the HP48 took `vX` as both the input and the output, introducing the shift quirk.", "default": false, "ifTrue": "Opcodes `8XY6` and `8XYE` take `vX` as both input and output", "ifFalse": "Opcodes `8XY6` and `8XYE` take `vY` as input and `vX` as output" }, { "id": "memoryIncrementByX", "name": "Load/Store quirk: increment index register by X", "description": "On most systems storing and retrieving data between registers and memory increments the `i` register with `X + 1` (the number of registers read or written). So for each register read or writen, the index register would be incremented. The CHIP-48 interpreter for the HP48 would only increment the `i` register by `X`, introducing the first load/store quirk.", "default": false, "ifTrue": "`FX55` and `FX65` increment the `i` register with `X`", "ifFalse": "`FX55` and `FX65` increment the `i` register with `X + 1`" }, { "id": "memoryLeaveIUnchanged", "name": "Load/Store quirk: leave index register unchanged", "description": "On most systems storing and retrieving data between registers and memory increments the `i` register relative to the number of registers read or written. The Superchip 1.1 interpreter for the HP48 however did not increment the `i` register at all, introducing the second load/store quirk.", "default": false, "ifTrue": "`FX55` and `FX65` leave the `i` register unchanged", "ifFalse": "`FX55` and `FX65` increment the `i` register" }, { "id": "wrap", "name": "Wrap quirk", "description": "Most systems, when drawing sprites to the screen, will clip sprites at the edges of the screen. The Octo interpreter, which spawned the XO-CHIP variant of CHIP-8, instead wraps the sprite around to the other side of the screen. This introduced the wrap quirk.", "default": false, "ifTrue": "The `DXYN` opcode wraps around to the other side of the screen when drawing at the edges", "ifFalse": "The `DXYN` opcode clips when drawing at the edges of the screen" }, { "id": "jump", "name": "Jump quirk", "description": "The jump to `
+ v0` opcode was wronly implemented on all the HP48 interpreters as jump to `
+ vX`, introducing the jump quirk.", "default": false, "ifTrue": "Opcode `BXNN` jumps to address `XNN + vX`", "ifFalse": "Opcode `BNNN` jumps to address `NNN + v0`" }, { "id": "vblank", "name": "vBlank quirk", "description": "The original Cosmac VIP interpreter would wait for vertical blank before each sprite draw. This was done to prevent sprite tearing on the display, but it would also act as an accidental limit on the execution speed of the program. Some programs rely on this speed limit to be playable. Vertical blank happens at 60Hz, and as such its logic be combined with the timers.", "default": false, "ifTrue": "Opcode `DXYN` waits for vertical blank (so max 60 sprites drawn per second)", "ifFalse": "Opcode `DXYN` draws immediately (number of sprites drawn per second only limited to number of CPU cycles per frame)" }, { "id": "logic", "name": "vF reset quirk", "description": "On the original Cosmac VIP interpreter, `vF` would be reset after each opcode that would invoke the maths coprocessor. Later interpreters have not copied this behaviour.", "default": false, "ifTrue": "Opcodes `8XY1`, `8XY2` and `8XY3` (OR, AND and XOR) will set `vF` to zero after execution (even if `vF` is the parameter `X`)", "ifFalse": "Opcodes `8XY1`, `8XY2` and `8XY3` (OR, AND and XOR) will leave `vF` unchanged (unless `vF` is the parameter `X`)" } ]