jc-SpaceXp / cNES

NES emulator written in C and targeted for Linux.
zlib License
6 stars 4 forks source link

Add support for a nametable viewer #4

Closed jc-SpaceXp closed 1 year ago

jc-SpaceXp commented 1 year ago

A good debugging request, can provide useful information that could only be accessed through a debugger like GDB, e.g. is the nametable mirroring correct, is the scrolling correct etc.

jc-SpaceXp commented 1 year ago

One of the main reasons why I created the unit test branch was for this feature. Requires a lot of refactoring and thought unit testing the current behaviour would be benfical.

jc-SpaceXp commented 1 year ago

Test plan was as follows:

  1. Reading and writing to vram (required by most rendering functions)
  2. Fetch nametbale byte
  3. Fetch attribute table byte
  4. Correct pattern table address (either 0x0000 or 0x1000)
  5. Fetching the correct pattern table bitmaps (lo and hi)
  6. Filling the attribute shift registers

Note: These background rendering functions needed to become more generic to avoid any side effects which could break the rendering of the main output screen (idea was to have the nametable viewer and main emulation side by side).

Figured I could use a for loop and loop through coarse x and coarse y values (x/y tile offsets), while starting at a base nametable address (0x2000, 0x2400 etc.). When coarse x and coarse y went into an adjacent nametable, we switch the base nametable to the new value and add the tile offset to that address.

The initial idea was to loop from 0x2000's top far left tile to 0x2400's top right tile, then increment coarse y and repeating.

This means adding some additional functions / tests:

  1. Nametable offsets for coarse x and coarse y values
jc-SpaceXp commented 1 year ago

During this process I figured I could refactor the background rendering member variables into their own struct. With each function taking a pointer to this new struct. This change would allow the nametable viewer and the main output to co-exist, as the nametable viewer could just create the struct before entering the for loop.

jc-SpaceXp commented 1 year ago

Tests: Vram writes: 4ec724ad50fac0e066188b7b707187a3ee9633d2 Vram reads (no nametable mirroring checks): 4ec724ad50fac0e066188b7b707187a3ee9633d2 Vram nametable mirroring: 41b2ccdd1a3c07a3358e567f2ba50a219bab0dda

Fetching nametable byte: 0f21a6de1893342f7ecfc382df81d86880402a16

jc-SpaceXp commented 1 year ago

Realised my future tests would be easier to write if I could have a function which took coarse x and coarse y to output a valid vram address. see: 1dbfaaa96a761ee2b9719f400c8757805de64a81

jc-SpaceXp commented 1 year ago

Refactor nametable fetching unit tests to use this new test helper function: 84954d1467934f8aa72acfef7de72fabca19c3a7

jc-SpaceXp commented 1 year ago

A similar change would be made for generating a valid attribute addresses from coarse x and coarse y values: 6effda9352d1485044a82d9481f5857f1b35a595

Note: Both test helper functions had a name change as I thought they could be a bit clearer: 71194ff1d91e8b8f979b52c48ffdc49d74fe65bf

jc-SpaceXp commented 1 year ago

Unit tests for attribute fetching: c8d5aa1b99a5d4edd95342310cf43704fad9933e

Updated some nametable fetch test cases to use the attribute address helper function: 01301e52e5d3073360c6314ac139b8797126d879

jc-SpaceXp commented 1 year ago

The pattern table fetch functions both use the reverse bits LUT array, need to test this directly or indirectly. As any issues in these functions could be down to:

  1. reverse bits lut
  2. incorrect base pattern table address
  3. incorrect pattern table offset
jc-SpaceXp commented 1 year ago

Went with the option of keeping the reverse bits LUT private/static and instead having a unit test double which performs the same function.

If the pattern table offset and the base address are correct we can just query the reverse bits function matches the output of the pattern table latches

jc-SpaceXp commented 1 year ago

Reverse bits test double: bd660c085845d1a26c8462472b5a0394a78c6c82

jc-SpaceXp commented 1 year ago

Testing the correct base pattern table address: 04077b69c945b795b37264765cc75bd8cc3c5d88

jc-SpaceXp commented 1 year ago

Everything is in place to test the pattern table functions now!

Lo bitmap tests: f902c7ee3520edbd1cdecc65a26637b0e21e1a78 Hi bitmap tests: f072d0b9be9736db1ab276ce5f35ae0eaa74f577

jc-SpaceXp commented 1 year ago

Attribute shift registers unit tests: 08f6870ac4e6d672a235c62b3fbcdd8f308f6e10

Can now move on to refactoring the background rendering functions.

jc-SpaceXp commented 1 year ago

Refactor of background rendering functions: ad0f8e9ff62b46a413ce474edd8a8cd977688912

(The change is that those functions which modified member variables have been moved into their own struct which is part of the function call now.)

jc-SpaceXp commented 1 year ago

To be able to store all namtable pixels in the buffer I wanted a function to write to the correct index of that buffer.

see: 2c4e2cc23b9519838fb24c7e2f5d3433bfe09462

jc-SpaceXp commented 1 year ago

Now that everything necessary has been unit tested it is time to write the nametable viewer

jc-SpaceXp commented 1 year ago

Commit 51e20d7c94ec1837b08052a52cb17c7ba5f6ae2c completes this issue.

Note: The ability to show all 4 nametables is in cNES however it hasn't been properly integrated as it requires supporting multiple windows in SDL2 (coming in a future change).

jc-SpaceXp commented 1 year ago

Commit: 12457aa82e7c7cfaec1e9fe5eb821935270a05a0

Adds support for multiple windows and debug builds now display two windows, the main cNES emulation and the nametable viewer