mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-18 14:05:57 +00:00
0876d85626
It wasn't copying the frame data from the sources to the output frame correctly, and there was a small period of zeros at the start of the frame. I also converted to using a vec of tuples for the two channels to make it easier to reason about, since some of the issues were related to the differences sizes calculated from the clock based on the sample rate
357 lines
21 KiB
Plaintext
357 lines
21 KiB
Plaintext
|
|
- 2021-09-28: started the project, computie monitor working after a week
|
|
- 2021-10-08: I think the Computie OS could boot by this point
|
|
- 2021-10-14: I think I started working on the genesis at this point, or maybe a bit before
|
|
- 2021-10-20: added frontend refactoring
|
|
- 2021-10-25: added Sega Genesis peripherals for the first time, even though I think I had been
|
|
working on it for at least a couple weeks by that point
|
|
- 2021-10-27: added minifb frontend
|
|
- 2021-11-01 to 2021-11-11: worked on the Z80/TRS-80
|
|
- 2021-11-13: was working on Mac (and Genesis a bit)
|
|
- 2021-11-28: took up the Genesis again after posting first article
|
|
|
|
|
|
Genesis
|
|
=======
|
|
|
|
(pieced together after the fact)
|
|
|
|
before 2021-10-25
|
|
- controllers and coproc controls aren't an issue as dummies until much later
|
|
- implement dma
|
|
- try implementing the scrolls and get nothing
|
|
- try printing just the patterns and get nothing
|
|
- cram is 0s, fight and find a few dma/transfer bugs
|
|
- cram is then sorta working, getting 0xeee and 0xee0 colours, but showing as pink
|
|
- turns out to be index issue into cram, fixing makes colours ok, but still nothing on screen
|
|
|
|
|
|
2021-10-25
|
|
- still nothing on the screen.
|
|
- maybe it's not working because I haven't implemented the h/v blanking bits at all, so I add
|
|
them and it makes something appear instead of blackness. At least for Sonic 2, it waits
|
|
for the vblank bit to be set
|
|
|
|
2021-10-26
|
|
- what caused those pink screens I was initialling getting?!? there was an issue with the cram
|
|
not being correct, and I remember fighting a ton with that...
|
|
- it was caused by the cram being byte-wise, but the index into the array when fetching the
|
|
colour was not multiplied by 2, so the colours were wrong. It was fixed in commit 109ae4d
|
|
|
|
- add the BusPort thing to fix issues with how data is written. Some writes can bet 4 bytes, or
|
|
2 bytes, and they could be to the same address or the adjacent address, so adding BusPort,
|
|
which breaks up the reads into all 2 bytes reads as the real hardware would see simplifies
|
|
the number of cases to deal with when accepting data on the VDP ports
|
|
|
|
2021-10-27
|
|
- oct. 27, commit 109ae4d doesn't seem to work and it seems to be related to the interrupts not,
|
|
which I got working in the immediately following commit. It actually does work but is super
|
|
slow to display anything, which was fixed later, as in minutes before the screen goes white
|
|
to display the sega logo. The interrupt print log is very slow, only a few interrupts in a
|
|
minute
|
|
|
|
2021-10-29
|
|
- the next commit 250c0 speeds things up by making the step function occur less often for the vdp
|
|
Also this commit adds code to change the interrupt mask, but only if a hardware interrupt occurs
|
|
I think this was causing problems with the computie binaries. There's still an int bug
|
|
|
|
- commit 93c080e: finally fix interrupts properly. The code I was using before didn't properly
|
|
reset the interrupt signal, so it couldn't reoccur. The CPU now checks the interrupt controller
|
|
each cycle for a pending interrupt, rather than relying on a callback and the Interruptable trait
|
|
which I partially removed.
|
|
- it now actually runs and shows the screens at a reasonable speed
|
|
|
|
- I recall there was an issue with the pattern indexing using the wrong formula to calculate, and
|
|
that caused some of the issues
|
|
|
|
|
|
-----
|
|
|
|
2021-10-31
|
|
- at this point I had finally gotten the scrolls to work enough to print the SEGA logo at the start
|
|
|
|
2021-11-01
|
|
- started working on the Z80 and TRS-80 implementations, as well as debugging the Mac stuff, which
|
|
I think I was doing for most of November (instead of working on the Genesis impl)
|
|
|
|
|
|
2021-11-30
|
|
- after getting things working somewhat with the scrolls, but not the sprites, I finally found
|
|
ComradeOj's demo, which I'm now using to test with, and I've also got BlastEm setup so that I
|
|
can compile the code and modify it to print out all of vram so that I can verify against mine
|
|
|
|
- there is a difference in VRAM in the patterns section with non-zero data starting at VRAM:0020
|
|
the first differing byte is VRAM:0046 which is 0x1111 in my VDP but 0x0000 in blastem's VDP
|
|
- checked what data was actually being transferred to VRAM, the source data is in ram at 0xff2000
|
|
(ie. 0xff2000 is copied to VRAM:0020 for some number of bytes, maybe 256 or so)
|
|
- ram copy of data is incorrect so the problem is not the VDP code specifically, but the code
|
|
that loads the ram.
|
|
- traced it further to the decompress function called at 0x00c0, this function definitely loads
|
|
the source ram and it's definitely incorrect long before the actual VRAM is loaded
|
|
|
|
- so I set a breakpoint at c0 in blastem, and then at that point set 266 and continued until the
|
|
first different byte was loaded, and inspected all the CPU registers at that point. The only
|
|
one differing is %d6 which holds a copy of the flags, which is somehow/somewhere restored after
|
|
being saved. It's 0x2700 in blastem but 0x2710 in moa...
|
|
- so far I'm suspecting that the Extend flag is not being correctly simulated somewhere, and
|
|
that's causing problems. The code uses roxd instructions which use the Extend flag... sus
|
|
- the two places where %d6 is set in the decompress function are just after LSR instructions.
|
|
I didn't have tests for LSR or LSL, so adding some caught the issue where Extend is not cleared
|
|
by the instruction nor by the logic flags code (since most logic instructions don't affect extend)
|
|
- fixing this made the text of the demo appear correctly, along with colour changing of the text,
|
|
but the background is not rendering at all
|
|
|
|
- switching gears now, trying GenTestV3. A write to read only memory occurs at 0x2976 because %a4
|
|
is 0 when it should be the VDP data register (0xC00000)
|
|
- tracing back, there is some code run at 0x2572 which causes the registers to be cleared, but
|
|
checking in BlastEm's debugger with a breakpoint there shows it's not executing there, so this
|
|
is a problem in moa and it's caused an erroneous processor state...
|
|
- there's a comparison at 0x255e which jumps to the code that shouldn't run, checking in BlastEm
|
|
shows that the previous comparison should not be equal (flags are 0x2700), but in moa it's 0x2704
|
|
- the comparison is correct, but the value in %d7/%d3 should be 0xff instead of 0xef
|
|
- at 0x2a78 the values are read from the controller inputs 0xa10003, and this is what's not correct
|
|
the data read is 0 but should be something else I think (start of code is 0x2a4a)
|
|
- it appears that the controller inputs should be 1s instead of 0s when not pressed?? or when all
|
|
bits are 0?
|
|
- changing to that behaviour makes it work until the ram test is invoked, but it seems that BlastEm
|
|
also does write to address 0 when the RAM test is run...
|
|
- the writing to address 0 might be an unintentional bug in the rom, which doesn't otherwise affect
|
|
anything because removing read_only makes it work enough to run
|
|
|
|
- next issue is controllers, it turns out the button logic is inverted, so the rom expects to read
|
|
all 1s (0xfff) for the button states, and a bit will drop to 0 when it's pressed.
|
|
- now there's an issue with the 'a' button to go to the info screen where it sometimes seems to run
|
|
the memory test instead, or otherwise behave inconsistently, and it's probably that 1.5ms delay
|
|
that resets the cycle to avoid the extra 3 buttons. This rom probably only reads the first 3 and
|
|
expects the counter to reset
|
|
- turned out that i actually need to reset the th counter after the ctrl port is written to, and the
|
|
count/next_byte logic was broken, so the buttons were incorrectly mapped
|
|
|
|
- now the test works, memory tests work, and so far looking at the info pages, the sprites are almost
|
|
correct, but sonic is busted. It might be something to do with the sprite being reversed
|
|
|
|
2021-12-04
|
|
- colour bleed test: 0x230a
|
|
- there are two of the four bars of colours with the rest black except some garbage at the bottom.
|
|
- I was able to modify the pattern printing to put a white dot in the upper corner so I could count
|
|
the cells to figure out where in memory the garbage pixels were appearing. The garbage starts on
|
|
a ways into line 23 and continues on lines 24/25/26, where the scroll is 64 cells across, and the
|
|
start of scroll a is 0xE000, which makes 0xEB80 about the start of the garbled line.
|
|
- the cells in the table look correct here, each line contains increasing pattern numbers (0x0518 at
|
|
the garbled cells), so the problem isn't here
|
|
- looking at the pattern for 0x518, which corresponds to address 0xA300 in video memory, the data is
|
|
not at all like the regular patterns at the start of VRAM. Comparing it to blastem shows the VRAM
|
|
is correctly regular (0x1111 or 0x5151 and other regular repeating patterns), so it looks like
|
|
a problem with loading VRAM
|
|
- look at the included source, the start of the colour bleed test is 0x2056, the DMA transfer is set
|
|
up at 0x207a which then writes to the control port to start the transfer
|
|
- I started suspecting the transfer count might be the number of read/write cycles as opposed to the
|
|
number of bytes, and only half the data is transferred, which would explain why the bottom half of
|
|
all the screens was broken but the top half looked fine
|
|
- sure enough, checking in blastem it even prints $4600 words, but moa was subtracting 2 from the
|
|
count. Changing to 1 pretty much fix all the remaining glitches, and sonic 2 now displays pretty
|
|
well
|
|
|
|
- started implementing scrolling. It seems the horizontal and vertical values work opposite to each
|
|
other. The horizontal value needs to be subtracted. I might also need to convert them to signed?
|
|
- initial problem was caused by getting the mask wrong (0x3F instead of 0x3FF), but the mask is
|
|
required because technically games can use the extra bits for whatever they want =(
|
|
- the background was still glitching and it turned out to be because for scroll b, I was reading
|
|
the scrolling data 1 byte over instead of 2 bytes over (because they are words). That fixed
|
|
the glitching
|
|
|
|
|
|
2021-12-15
|
|
- started trying to make horizontal line scrolling work. Turns out to not be too hard except that
|
|
there's a few glitches
|
|
- one turned out to just be that i was multiplying by 2 instead of 4 for the hscroll addr
|
|
- the other is that it's drawing the lines for scroll a and scroll b at the same time, and they
|
|
overlap incorrectly when the per-pixel column offset is different between the layers
|
|
|
|
2021-12-20
|
|
- looking into the hscroll and vscroll issue, I realized I wasn't adding the (vscroll % 8) value to the
|
|
pixel offset, which is now being added, which causes some glitches at the bottom/left of the screen,
|
|
but it now scrolls more smoothly in the vertical
|
|
- there is still an issue with the hscroll, particularly when the offsets are very different, no idea
|
|
|
|
- after spending the day looking into the slowdown issue, I found the issue. I started by looking at
|
|
the sonic 2 disassembly looking for code that reads the controllers (ReadJoypads) and then looking
|
|
for where that is called from, and found the Vint_Level function which after setting some breakpoints
|
|
is definitely only called during gameplay but is called each frame and reads the input before updating
|
|
the screen.
|
|
- looking at the code, and tracing the first few instructions where the ReadJoypads function is called
|
|
showed that it sometimes skipped over the various timer checks every other time it's called
|
|
- I added the system clock time to the debug output, which showed that it was indeed ~33_200_000 ns
|
|
between each call to Vint_Level
|
|
- so I turned on a debug message for the hardware interrupts and it showed the interrupt occurring
|
|
twice for every time the Vint_Level function is called. After the first vint, it takes ~14ms until
|
|
the Vint_Level function runs... looking at what runs by tracing that period between the int and call
|
|
shows that it's looping while checking the status bit of the VDP, which corresponds to the vblank
|
|
bit, of which there is a bad implementation that just turns the bit on after 14ms ... so it is
|
|
definitely a problem with the vertical interrupt and vertical blanking bit timing in the VDP step
|
|
- I had hackishly made some code to turn the blanking bit on at ~14ms, and then turn it off just before
|
|
the vint was triggered. It would have worked had the frame been drawn at the 14ms mark, and then the
|
|
blanking bit reset at 16.6ms. I've now changed it to be proper, in that the blanking bit is set at
|
|
15ms, the count is reset at 16.6ms, and the blank bit is cleared at 1.2ms
|
|
|
|
2021-12-23
|
|
- looking into the coprocessor not working. I tried Mortal Kombat 2 and apart from something weird
|
|
going on during the character select screen, everything worked until combat started and then it
|
|
crashed due to an invalid memory access to address 0x0068eebb, which occurs at PC: 0xffff0245,
|
|
so something is causing it to execute ram, which is probably not what's supposed to happen
|
|
- It looks like it's swapping stacks, and that's making it hard to trace. At some point, it swaps
|
|
the stack and then does a rts, but the stack return value is invalid and that causes it to mess up.
|
|
It almost looks like it does put a valid return on the stack but then unintentionally overwrites it
|
|
due to overlapping memory areas (I could just be tracing this wrong). I'll come back to this later
|
|
|
|
2021-12-26
|
|
- looking into the scroll black bits, I checked the scroll table for Sonic2 in BlastEm and the values
|
|
are clearly different for Scroll B. The values in BlastEm are close to 0xffff but the ones in Moa
|
|
are 0x10f2, 0x11f2, etc. And it's wrong in the source ram (0xffe000 which is copied to 0xfc00 in VRAM)
|
|
- I added watcher debug commands to watch for modifications to a given memory location, and used that
|
|
to watch 0xffe322, which is an scroll value for Scroll B in an area near the end of the hscroll table
|
|
where the scroll value is different from BlastEm.
|
|
- breakpoint occurs at 0xc670 where that value is written to. The function starts at 0xC57E and
|
|
calculates scroll values.
|
|
- so far I'm suspecting the DIV followed by the EXTW at 0xc62a might be doing something incorrect,
|
|
and then when it adds the result in %d0 to %d3 before using that as the scroll value, it's adding
|
|
too large a value (that should have been cut off to a word)
|
|
- there was indeed a problem with the div. It's a signed div but the division was unsigned. Now
|
|
the scroll values look about right, but the black glitches are still there
|
|
- turns out it was that the scroll values were inverted. The hscroll values are supposed to be the
|
|
offset *per line*, so you use the same hscroll value for every line. It's the vscroll value that
|
|
has to be looked up for ever column, so swapping the vscroll and hscroll between the inner and
|
|
outer loops fixed the issue perfectly. Kind of odd that it wasn't more broken when inverted
|
|
|
|
- now I've noticed there's a scroll problem in Ren & Stimpy. Every other cell's hscroll is 0
|
|
- looks like address 0x264 is the start of the transfer to the hscroll table in vram
|
|
0x83e2 is the function that calls 0x244. 244 sets up the transfer and 83e2 sends the data
|
|
- the auto-increment is set to 0x20 which leaves that 0 in between, but after thinking about it more,
|
|
I realized that's correct, and that it's actually 32 bytes (16 words) between each scroll value,
|
|
The bug was in the hscroll function which I didn't actually fix properly. I modified it to
|
|
multiply the line by 4 instead of 2, but I also needed to shift to the hcell value by 5 instead
|
|
of 4 (multiply by 32 instead of 16) to get the proper base scroll
|
|
Now, Ren & Stimpy works, and Sonic 2's Scroll B actually looks right
|
|
|
|
|
|
2021-12-30
|
|
- rewrote the main drawing functions to go pixel by pixel through the whole image and determine what
|
|
colour that pixel should be. It's a lot slower, but it's more accurate, and makes it possible
|
|
to more properly implement the priority shadow/highlight modes
|
|
|
|
|
|
Audio
|
|
-----
|
|
|
|
2021-12-12
|
|
- this is when I committed the audio support, but I'm not sure when I started. It was a little earlier
|
|
- cpal uses a callback to get the next buffer of data, so the buffer needs to be assembled outside of
|
|
the callback, with each device creating a Source with a buffer, that the mixer/output can draw upon
|
|
- initially I had it give an iterator to load the buffer, but that doesn't work for ym2612 generation
|
|
because it itself needs to mix a bunch of sources together to get the output buffer
|
|
- I made it use a circular buffer so that unused data can be skipped to keep the simulation in sync
|
|
- from various glitches I was able to get it to playback tones smoothly, with only the occasional pop
|
|
|
|
|
|
2022-01-17
|
|
- finally have done more, added the various register locations to set the frequency of the operators,
|
|
and added a way to combine the samples according to the algorithm of ops to get sound
|
|
- had to add `.reset()` to start from the beginning when a note is played, in order to prevent clicks
|
|
from the waveform all of a sudden jumping in level when the note starts
|
|
- started adding a binary to control just the ym2612 for testing, so I can isolate issues, and a lot
|
|
of minor issues have turned up
|
|
|
|
2022-01-18
|
|
- some kind of buffer problem causing clicking, where the waveform resets, possibly related to circular buf
|
|
- a quick attempt at fixing it shows that the audio source buffer is only copied to the mixer buffer
|
|
when it's written to the buffer (and overfills). Attempt to not write to the buffer means audio stops
|
|
when the source buffer is full
|
|
|
|
2022-01-24
|
|
- finally took another look and the glitching turned out to be an issue with the buffer size where the
|
|
check before the audio devices write only account for one channel of audio instead of two, so the
|
|
buffer was over filling. Dividing the available buffer size by 2 fixed it
|
|
|
|
2022-10-08
|
|
- I replaced the circular buffer with queues of audio frames, which might be less able to handle time
|
|
dialation, but which uses fewer locks for less time, which seems to improve the occasional dropout
|
|
glitches. The next frame is also assembled by whichever sim audio source that pushes data sees
|
|
the queue is empty (audio frame taken by the output callback), so it then assembles the next frame
|
|
and pushes it to the queue. It definitely works better, but there are still some timing issues
|
|
- the PCM data in ym2612, looking at the recording of the waveform, shows it's offset by a bias, which
|
|
probably shouldn't be. The other audio sounds distorted but still sort of sounds like what it should,
|
|
so I don't think it's too far off
|
|
|
|
|
|
|
|
---------------------------------------------------------------------------------------------------
|
|
|
|
Macintosh
|
|
=========
|
|
|
|
- ram self test is run by jumping to 0x400694, which returns by jumping to %a6 which contains 0x4000f0
|
|
if it returns with eq set, it will jump to the system initialization at 0x40026c
|
|
it doesn't have eq set, so it ends up in an infinite loop.
|
|
- turns out MOVEM was broken such that it was incrementing instead of decrementing address (found by
|
|
inspecting the first byte of memory when trying to get 0x5555AAAA to cancel itself out
|
|
|
|
2021-11-19
|
|
- still not working, calling 0x4000f0 to fail. Turns out this is where the dead mac is supposed to
|
|
be printed, but it's not (found that from another blog post)
|
|
|
|
2021-11-23
|
|
- finally got dead mac screen showing with 0F0003 as the error. It wasn't showing because the 0 colour
|
|
used by the genesis, which is a mask colour, causes nothing to appear
|
|
- then the issue was the indexing of the memory page (x * 2) * y instead of (x * 2) + (y * 512/8)
|
|
|
|
- so the 0F0003 dead mac was caused by the first trap instruction in the ROM, appearing at 4002adc
|
|
It causes an illegal instruction, which then jumps to the exception entry points start at 4001aa
|
|
in rom which all jump to the same function at 4001d2, which then ends up in the failure
|
|
- trying to find why, i traced the program to find where the trap table was being set up, which
|
|
turned out to be around 400448 which is where I'd been debugging the last issue. It sets location
|
|
0x28 to 401018 which is the trap handler...
|
|
- 0x28 is not the illegal instruction handler, it's the 1010 line emulator exception... 1010 as it A
|
|
as in the A line traps... So the m68k is specifically not handling the a000 instructions correctly
|
|
|
|
- it's now getting past the dead mac, but instead it causes two writes to read only memory when it
|
|
tries to set some bits indirectly to an address in rom (0x4034ae), which is something do with the
|
|
drivers. The Sound and Disk drivers are opened and it's during each of the open functions that the
|
|
write occurs
|
|
- it's possible to continue (which might be in broken state) and it then attempts to write to
|
|
sequential addresses in upper ram which eventually spills over into 0x100000 which isn't mapped...
|
|
No idea if this is just because of something going wrong earlier, or if this is also an emulator bug
|
|
|
|
- the writes to rom issues happens during InitIO (0x400614), when initializing the first two drivers,
|
|
the Sound and Disk (I think). There is a pointer to a pointer to a value that contains 0x4034ae,
|
|
which seems to be calculated from a jump table, presumably pointing to something in rom that contains
|
|
the driver, but for some reason the code is bit setting that value. I'm not sure if the data is wrong
|
|
and it should normally see a 0 instead of the rom addr, or if there's a branch that shouldn't/should
|
|
happen that leads it to that code when it shouldn't
|
|
- c4c and c7c seem to be driver descriptors of some kind, each with a rom addr and what seems to be some
|
|
flags after that. They also have 0xfffb and 0xfffc. That said, if there's a bug in the code that
|
|
creates that data, it would likely be broken for both
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|