Rewrote the disassembler and `cpu::tick()` for code concision and massive speed improvements.
Turns out, getting the current time takes AGES, so if we don't need it, we don't get it.
- Rewrote the instruction decoder as an enum
- Used imperative_rs to auto-generate the bit twiddling logic
- Implemented Display on that enum, for disassembly
- Rewrote CPU::tick
- Now >10x faster
- Disassembly mode is still 5x slower though
- Implemented time-based benchmarking
- (use option -S to set the number of instructions per epoch)
- Improved test coverage to >80% of lines, functions
- When doctests are included.
- Wrote new unit tests:
- Explicit tests for invalid instructions in the
ranges {`5xyn`, `8xyn`, `9xyn`, `Fxbb`}
- `rand` Tests for 1052671 cycles, to ensure
randomly generated number is < ANDed byte
- `Ex9E` (sek), `ExA1`(snek) will press only the expected key,
then every key except the expected key, for every address
- `Fx0A` (waitk) asserts based on the waveform of a keypress.
After all, an A press is an A press.
- Improved test performance by printing slightly less
- Removed nightly requirement
- (now optional, with feature = "unstable")
- Amended justfile to test with `cargo nextest` (nice)
- Changed release builds to optlevel 3
Chip-8 has no ROM, nor memory management.
- It's much easier to just use contiguous memory.
- Then we can return references to slices of that memory
- ~3x speed increase
Screen exists now, uses 24-bit framebuffer
- We have a 1-bit framebuffer
- I chose colors that look good to me
Controller exists as well, has 16 buttons
- Mapped "0 123 456 789 ab cdef" to (QWERTY) "X 123 QWE ASD zC 4RFV"
- Other chip-8 interpreters may use a different layout
- This is good enough for now.
- F1-F9 map to control functions
- F1, F2: Dump CPU registers/screen contents
- F3, F4: Toggle disassembly/pause
- F5: Single-step the CPU, pausing after
- F6, F7: Set/Unset breakpoint
- F8, F9: Soft/Hard Reset CPU
- Do some basic benchmarking with std::time
- Try writing bus writer based on iterator
- Fail, because that requires mutable iterator
- Begin rewriting bus based on simpler design instead.
- Simpler design uses a unified memory model,
which grows based on the maximum addresses expected in it
- Still uses the "infallible" Read/Write traits from previous
implementation. :( Alas, it's much faster during operation,
even if it takes longer to instantiate.
- Reassessed the syntax for bus macro
- Made CPU tick generic over bus::Read and bus::Write traits