480p Homebrew Source Code Examples?

slinga

Established Member
Starting a new thread to not hijack the other one,

Anyone have example source code to set 480p mode?

1) Charles MacDonald has a resolution demo here: Progressive hires test demo?. But it doesn't include source code.
2) MacDonald had an entry in the "C4 - 2006 Context" that is described as "A graphic demo in hires interlaced (or VGA output)". Unfortunately I don't even have the binary for that.

Barring source code I will attempt to RE the resolution demo.
 
I'm sorry for "hijacking" your another thread

The following are settings for 480p:
1. set HRESO bits of TVMD register to 4(320) or 5(352) for Exclusive Normal Graphic Mode
2. set HRESO bits of TVMD register to 6(640) or 7(704) for Exclusive Hi-Res Graphic Mode
3. set LSMD bits of TVMD register to 0 (Non-interlace) (But i'm curious what will happen if set to other values?)
4. the VRESO bits will be ignored, it doesn't matter what the settings are.
5. Make sure to call SMPC command CHG352 when using 352/704 HRESO
6. For modes 6(640) or 7(704) Exclusive Hi-Res Graphic Mode(or Special High-Resolution Graphics Mode), please reference p.13 for details.
 
Last edited:

slinga

Established Member
No need to apologize, the discussion on that thread is fantastic. I didn't want to distract from it.
 

slinga

Established Member
I spent some time RE-ing mode.iso. I made some progress but I don't have anything displaying on screen: slinga-homebrew/480P-Mode-Demo.

I left out initializing the SMPC as well as a function I called "printfWrapper()". Will get to them when I have more time. Also possible I RE-ed incorrectly.
 

slinga

Established Member
Spent some more time re-ing, still don't have anything displaying. Not sure what I'm doing wrong. Will go through with a fine tooth comb tomorrow to see what I missed.
 
Hi, I took a look at your source code
1. D0R, D0W, D0C.., those registers are registers of SCU, have nothing to do with VDP2, make sure you referenced the right document.
2. Step by step. Write a demo that works in the normal resolution first, then extend its functionality to support other resolutions.
 

Ponut

Gear Supporter
You also have to keep in mind that SGL constantly performs write-backs on system registers.
If you are going to exact your own modification of them, you need to ensure three things:

1 - The manual does not prohibit the change of these registers when the chip or subsystem is powered on.
2 - The manual describes the state in which the register can be changed or if it can be written to at all.
3 - You must write-back these registers at vblank, basically you're writing back over SGL's write of the register.

The essence of hi-res progressive scan mode is for VDP2.
Instead of vertical stitching of two fields (interlacing), VDP2 performs horizontal stitching of two "fields" ( pixel from A -> pixel from B -> A -> B).
In the hi-res progressive scan mode, the horizontal stitching is of NBG0's pipeline with NBG1's pipeline (they are pointed to the same data as configured by registers).

And as per pg.37 of VDP1's manual, VDP1 is still limited to standard screen sizes in this case (352x240 , 320x240).
 
Last edited:

slinga

Established Member
Thank you for the responses. Just to be clear I didn't read the docs, I grabbed MacDonald's mode.iso and started reversing it in Ghidra. I was hoping this would be relatively easy, I was wrong. Ideally I would of just had the original source code to work with.

1. D0R, D0W, D0C.., those registers are registers of SCU, have nothing to do with VDP2, make sure you referenced the right document.

It's certainly possible the names of the registers are wrong. That being said I used the addresses from mode.iso so the addresses they point to should still be correct and what are used in the demo so that shouldn't be the cause of the errors. I will review them again in case some of the addresses I copied over incorrectly.

2. Step by step. Write a demo that works in the normal resolution first, then extend its functionality to support other resolutions.

I agree with you. I was hoping this method would be easier...

You also have to keep in mind that SGL constantly performs write-backs on system registers.

I'm not using SGL. I'm using Jo Engine for it's compiler but I'm not invoking any SGL libraries. I assume mode.iso wasn't built with SGL either and instead MacDonald wrote his own functions to interact with the system. I have RE-ed and reimplemented most of these functions.

The essence of hi-res progressive scan mode is for VDP2.
Instead of vertical stitching of two fields (interlacing), VDP2 performs horizontal stitching of two "fields" ( pixel from A -> pixel from B -> A -> B).
In the hi-res progressive scan mode, the horizontal stitching is of NBG0's pipeline with NBG1's pipeline (they are pointed to the same data as configured by registers).

I've looked through the code and have found only a few places where the 480P rendering differs from the other resolutions. I can't say I've seen where this vertical stitching is happening but I will spend some more time.
 

slinga

Established Member
Finally beginning to see some output. Still need have lots of bugs in my RE attempt.
 

Attachments

  • progress.png
    progress.png
    16.1 KB · Views: 56

slinga

Established Member
I have horizontal lines, text, and controller input working now. It also looks like it's changing resolutions and even doing the 480p resolutions. I still need to finish the code that handles the vertical bars.
 

Attachments

  • progress.png
    progress.png
    16.7 KB · Views: 54

slinga

Established Member
I have the program working equivalent to the original mode.iso in Yabause. However on real hardware and Mednafen I have a gray screen. I'm not sure what I'm doing wrong. I tried replacing my memsets\memcpys with versions that work on unsigned shorts in case that was the issue. That didn't change anything. Any advice?

The screenshot is literally just a gray screen from Mednafen....
 

Attachments

  • gray.png
    gray.png
    3.6 KB · Views: 44
Last edited:
Insert printf at key steps and output messages on the screen, then you can figure out where it fails.
If this doesn't work, try to simplify the program, make sure it runs on the real hardware, then add settings/functions to the simplified program, then you can figure out what settings/functions fail the program.
Of course, it's better to analyze possible reasons before making tests.
 
Last edited:

slinga

Established Member
I isolated the error to where I adjust the clock speed. The original code derefences a pointer at 0x06000320 that contains a pointer to 0x320. In my code I have the following:

Code:
typedef void (*bios_set_clock_speed_FP)(unsigned int);
bios_set_clock_speed_FP bios_set_clock_speed = (bios_set_clock_speed_FP)(0x320);

bios_set_clock_speed(currRes->flags & 1);

And this falls over. Not sure what I'm doing wrong. I verified that bios_set_clock_speed() is pointing to the correct address. I can't step in with Yabause for some reason. Commenting out this code everything appears to work.
 

slinga

Established Member
Swapping in bios_clock_speed_chg() from Libyaul and everything seems to work. I'll try on real hardware later today.

Edit: Verified working on real hardware equivalent to the original ISO.
 

Attachments

  • screenshot.png
    screenshot.png
    53.7 KB · Views: 58
Last edited:

slinga

Established Member
I figured out why my method of changing the clock speed was causing the Saturn (on Mednafen and real hardware but not on Yabause 0.9.14) to display only a gray screen. I got it to work by swapping out my implementation for the one in libyaul but I was still puzzled regarding what I messed up when it was so simple.

Original disassembly:
060046d8 61 12 mov.l @r1=>DAT_06000320,r1
060046da 54 a2 mov.l @(0x8,local_r10_38),r4
060046dc 41 0b jsr @r1
060046de 24 09 _and r0,r4

Original decompilation:
(**(code **)PTR_DAT_06004820)(local_r10_38->flags & 1);

So nothing weird at all. Deref 0x06000320 which contains a pointer to 0x320. Take the flags field from the structure and And it with 0x1 (happens in the delay slot). I verified all addresses in the debugger. So why deref 0x06000320? Why not jump directly to 0x320? And that's where I messed up...

It turns out 0x06000320 only contains a pointer to to 0x320 when using Yabause's HLE bios. When specifying a real BIOS 0x06000320 points to something else. So super dumb I was jumping to the wrong place because I decided to optimize a single extra deref from MacDonald's code lol. I just got stumped debugging because it worked in Yabause but not Mednafen or real hardware. I eventually figured it out when I ran Yabause with a real BIOS.

Moral of the story: jump to the right address.
 
Top