Implementing the FILL DMAgic command got rid of the @'s but the colour bars were still missing.
So I set about implementing the COPY functions of the DMAgic in case that was the reason, which as I suspected was fairly easy to do, and was verified by seeing that the screen scrolled, since the C65 uses the DMAgic chip to scroll the screen.
I wasn't confident that this would fix the problem, but it made sense to implement this DMA function at the time, anyway. And indeed the colour bars remained missing.
Some digging through the C65 ROM tracked down the code that sets and clears reverse character mode. This is done by setting bit 7 in $F4. On the C64 or C128 this would require an LDA / ORA / STA or LDA / AND / STA instruction sequence, requiring six bytes and a dozen or so cycles.
The C65's 4510 on the other hand has instructions for setting and clearing bits in bytes directly. SMB0 through SMB7 set the corresponding bit in a zero-page memory location, and RMB0 through RMB7 clear the bit. As a result the C65's reverse-on routine is simply SMB7 $F4 followed by an RTS. Three bytes instead of six, and just four cycles for the memory modification, and no registers or flags modified in the process. Those new instructions really do help to write faster and more compact bit-fiddling code.
As I discovered this I had the sudden realisation that I had never got around to implementing those instructions. Oops.
A quick bit of VHDL coding to add them in, followed by the usual slow synthesis process (about 90 minutes at present), the C65 startup display finally shows correctly, as can be seen below in the screen grab which was taken without any hand tweaking of the display, instead only with the CPU paused after drawing the complete display.
All I did was pause the CPU at the right point, since it still loops continuously redrawing the display for reasons I have yet to discover. I will probably need to disassemble the C65 ROM a bit more, and use the serial monitor interface I built to better understand what is going on here.
Nonetheless, it is a nice milestone that the CPU is compatible enough now to actually draw the display correctly.
There is also an issue where the colour memory doesn't scroll with the text, which I think is because the DMA command used to scroll colour memory operates on the memory at $001F800 - $001FFFF, rather than the IO-mapped access at $D800-$DFFF. I'll have to think about a solution for this, because this is a difference with the C65GS where to save display cycles, and also have enough colour RAM for large text displays (up to 240x150 characters is possible), I have colour RAM in a separate 64KB RAM. I might have to implement a C65 compatibility mode where accesses to $001F800 - $001FFFF map to that RAM instead of to the chip RAM.