Deleted
Deleted Member
Posts: 0
|
Post by Deleted on Jul 9, 2018 5:24:40 GMT
What does this black box actually do every frame? The manual barely explains how the BIOS operates and how to work with it...
You're forced to have the BIOS mapped into $E000~$FFFF to do call its functions, which makes sense, but being at the CPU's last bank means that the IRQ vectors are fixed. I want a VBlank and RCR handler, and here comes EX_SETVEC to the rescue...
...except that it sucks. It automatically separates VBlank calls from RCR ones to two addresses you can set up, but the RCR "pseudovector" is never called if you don't run EX_RCRON, and if you do, the BIOS will ALWAYS set up X/Y scroll to a value determined in EX_SETRCR when the RCR interrupt triggers before handing over control for you. Or at least that's what I could gather with my tests, because the manual doesn't explain a goddamn thing.
Sigh I wish the CDROM bios was better documented. This is more of a rant than anything really.
|
|
Deleted
Deleted Member
Posts: 0
|
Post by Deleted on Jul 9, 2018 6:13:09 GMT
Oh for crying out loud if this is caused by some hidden BIOS functionality... I do the following: Set up RCR register for interrupt in a given scanline then reset the X/Y of the screen during vblank. In the RCR handler I change the Y position of the screen to the position of my mountaintop backdrop. That's it. I'm expecting the screen to be normal up to the RCR scanline, then the image changes its Y position after that line. Instead, what happens is that the mountains appear on top of the screen (on the very first scanline) then the thing also appears again at the set up scanline. Why is this happening? It's as if the game is generating a RCR register interrupt at line 1. The manual does state that the flags are cleared when read so I don't think that a dirty flag is carrying itself over to the next frame. (...) ;Checks if the IRQ generated is from RCR LDA $0000 AND #%0000_0100 BEQ .VBlank .RCR JSR RCR_Int JMP .end (...)
|
|
|
Post by theoldman on Jul 9, 2018 6:37:17 GMT
um.....yeah.
The vdc will generate HSync irqs (the rcr irq you mention) during the Vsync period.
Vsync is just a specific number of 'blank' lines. So you do get Hsync irqs during Vsync.
What I *think* you want to do is set the scanline interrupt value to 63; that should be the first line displayed, unless you have messed with the screen control registers. Then when the rcr fires off, you change the scanline to where you want it to display +63.
Nope, the manual doesn't explain that, I don't think. Yes, you can set up multiple areas if you keep an array of offsets and pump them out in order.
|
|
touko
Punkic Cyborg
Posts: 106
|
Post by touko on Jul 9, 2018 10:26:02 GMT
Hum, have you added #64 to your RCR line to reach ?? As theoldman said the first line of the screen is not 1 but 64,and you need to fire your IRQ to your: desired_line - 1 because the VDC registers are buffered(not all registers, but those for scrolling are) ,and if you change them,the changes would be taken in account the next line . For your problem, it seems that the RCR irq occurs too early,maybe because you have not added 64 at the line where you want the IRQ..
|
|
|
Post by elmer on Jul 9, 2018 16:32:25 GMT
Hum, have you added #64 to your RCR line to reach ?? As theoldman said the first line of the screen is not 1 but 64,and you need to fire your IRQ to your: desired_line - 1 because the VDC registers are buffered(not all registers, but those for scrolling are) ,and if you change them,the changes would be taken in account the next line . This sound very plausible. Sigh I wish the CDROM bios was better documented. This is more of a rant than anything really. Welcome to the early days of videogame system documentation! I personally find that figuring out what is going on in the BIOS is easiest to do by comparing Hudson's official docs (linked to in my sticky), with the disassembly of the main System Card BIOS banks on zeograd's site Documentation download.
|
|
Deleted
Deleted Member
Posts: 0
|
Post by Deleted on Jul 9, 2018 19:07:52 GMT
Nah, I did make sure that RCR was greater than 64 at all times. I solved the problem but I still don't get why I have to add 2 to the new Y value to align my independent strip properly with the regular background, instead of just 1. And I can guarantee that the code is taking less than a scanline because I trigger it multiple times in a frame yet the scroll is always off by one.
I'll post some code when I arrive home. Thanks for the help, guys. Guess I'll make this thread a general Q&A as to not pollute this subforum.
|
|
|
Post by theoldman on Jul 9, 2018 20:07:27 GMT
Punch:
Can you test it with values > 256 for the screen width? IIRC, around 320 pixels, the VDC clock changes. And somewhere else (420?), it changes again.
I had to adjust the scanline based on the screen width, but I'd like independant confirmation of where the adjustments need to occur. Thx.
|
|
Deleted
Deleted Member
Posts: 0
|
Post by Deleted on Jul 9, 2018 20:35:17 GMT
Punch: Can you test it with values > 256 for the screen width? IIRC, around 320 pixels, the VDC clock changes. And somewhere else (420?), it changes again. I had to adjust the scanline based on the screen width, but I'd like independant confirmation of where the adjustments need to occur. Thx. Are you saying that changing the clock to 7/10 mHz may mess with the Raster Counter interrupt? I'll test it soon when I get home. Do you need testing in a real console too?
|
|
|
Post by theoldman on Jul 9, 2018 21:02:17 GMT
"Are you saying that changing the clock to 7/10 mHz may mess with the Raster Counter interrupt?"
I don't think it messes with the interrupt itself. I think the timing mismatch affects when the pce sees the interrupt. I'm -think- widths <= 256 use a 5Mhz clock on the vdc, and since 5 and 7 are relatively prime, the pce doesn't see the interrupt until active display starts. Which implies to me that any changes to the VDC registers won't be latched until the -next- scanline.
" Do you need testing in a real console too?" Not necessarily. I'm just interested in whether you are seeing the same effect as me. Specifically, if it goes away with an increase in screen width.
.......................................................................................................................
This all started with Rover asking me about some screen corruption when scrolling in something. He wondered how I had fixed it for something else, and I told him I'd moved some code around and it went away, but I had no idea why. So I started looking into it.
And FWIW, I'm not entirely sure that the emulators get this 100% correct. I've run the same code (from the same build) on Mednafen, ootake, and a real console. And I get different results. Even between re-boots, surprisingly.
Mednafen seems to be off by 1 scanline about 99% of the time. Ootake varies; sometimes it is off, sometimes it isn't. The PCE seems stable. It's not something I've exhaustively tested though. I'm also using some older versions of the emulator, so it might just be that.
|
|
Deleted
Deleted Member
Posts: 0
|
Post by Deleted on Jul 10, 2018 0:39:54 GMT
"Are you saying that changing the clock to 7/10 mHz may mess with the Raster Counter interrupt?" I don't think it messes with the interrupt itself. I think the timing mismatch affects when the pce sees the interrupt. I'm -think- widths <= 256 use a 5Mhz clock on the vdc, and since 5 and 7 are relatively prime, the pce doesn't see the interrupt until active display starts. Which implies to me that any changes to the VDC registers won't be latched until the -next- scanline. I think you're 100% right about that. If I understood you correctly, you're saying that the CPU gets warned about the interrupt too late to be able to do anything for the current line, scroll wise, right? (when the 6280 finally runs anything, HBlank of the RCR'ed scanline is already over).
I didn't mess with resolutions yet but the default one (the lowres-y config done by the Super System Card on boot) seems to trigger scanline IRQs with correct timing. I'm using this image as the PC Engine's video nametable (64x32): The objective of my program is to put line 24 (the green line) immediately below line 127 (the red line). Logically the steps are: 1. Load RCR with the value 127 + 64. (Values 0~63 never trigger so screen starts at "64") 2. In RCR, perform ST0 #8; ST1 #24; ST2 #0; to set up the next scanline (128) to have the green line at line 24. The result of doing exactly that? BYR value off by +1, Interrupt position off by -1. It is known that the value you set for BYR is ignored during the current scanline, so what I think this is doing is that we insert "24" into BXR at our current scanline, then when the next scanline starts the VDC simply increases BYR by one as part of its normal operation, then uses that value to draw the next scanline. It makes sense that we need to write "23" so that the next scanline has Y scroll set to 24.
The -1 offset (the green line being positioned exactly on top of the red line instead of being immediately below it) is probably explained by how my program isn't rendering the first line (another solid green line) on the screenshot. Emulation? Default System Card 3 screen config doesn't render the first line? I don't know but I'm pretty sure I'm setting BXR/BYR with (0,0) at start of each vblank. I'm probably going to test the "screen config" hypothesis later when I finally learn how the hell to work with those rendering registers on the VDC, but I think it's safe to assume that's the reason for the off by (-1) error in my case (which is probably unrelated to yours).
I think it's pretty safe to assume that yes, you need to subtract -1 from the new BYR value when doing a raster effect since when the VDC actually applies your value next scanline it will automatically increase it by one.
(sorry if I missed the point of your messages and misinterpreted what you meant to say, I'm pretty tired mentally right now ). " Do you need testing in a real console too?" Not necessarily. I'm just interested in whether you are seeing the same effect as me. Specifically, if it goes away with an increase in screen width.
....................................................................................................................... This all started with Rover asking me about some screen corruption when scrolling in something. He wondered how I had fixed it for something else, and I told him I'd moved some code around and it went away, but I had no idea why. So I started looking into it. And FWIW, I'm not entirely sure that the emulators get this 100% correct. I've run the same code (from the same build) on Mednafen, ootake, and a real console. And I get different results. Even between re-boots, surprisingly. Mednafen seems to be off by 1 scanline about 99% of the time. Ootake varies; sometimes it is off, sometimes it isn't. The PCE seems stable. It's not something I've exhaustively tested though. I'm also using some older versions of the emulator, so it might just be that.
I'll try different resolutions once I get the hang of the VDC configuration registers later. It will be interesting to see if my correct timing will be messed up with a larger horizontal resolution. I also hope that Mednafen and Bizhawk are drawing stuff correctly because if they aren't that probably means the rest of this text was a waste of time.
|
|
|
Post by theoldman on Jul 10, 2018 4:05:31 GMT
" If I understood you correctly, you're saying that the CPU gets warned about the interrupt too late to be able to do anything for the current line, scroll wise, right? (when the 6280 finally runs anything, HBlank of the RCR'ed scanline is already over)."
I'm not sure exactly. The CPU -could- be getting warned about the interrupt in time to handle it correctly if you leave BIOS out of it. The thing is, BIOS does de-multiplexing of the interrupts; afaict, they all come across as IRQ1 (maybe IRQ0, i'd have to check), and the IRQ1 routine decides who gets handled. By the time the actual HSync/VSync routine gets called, there may not be enough time at the slow VDC rate to update the VDC registers before active display starts, leaving them to be updated on the next scanline.
That could -possibly- explain the screen corruption Rover was seeing. (assuming the registers were updating as the VDC was starting to draw)
I can think of a few other scenarios that -might- cause the scanline irqs to be off by 1, as well. None of them explain why setting the screen width to values > 320 cause the problem to disappear, though.
I haven't really looked into it much beyond "Okay, doing this works". I'm -not- a EET, so I only vaguely understand the screen stuff anyway. What I would like to know is what order the VDC does things in. Does it check the RCR first, before it latches new values? Or does it latch the values first, and then check? And how would we be able to prove either order?
That level of assembler is -w-a-y- beyond me. As is the machine setup to do it.
And fwiw, check out / play with EX_SCRMOD in BIOS. It should allow you to see if changing the VDC clock really does affect anything.
|
|
touko
Punkic Cyborg
Posts: 106
|
Post by touko on Jul 10, 2018 9:12:39 GMT
yeah, it's possible mainly if you change only the dotclock, without changing the screen parameters it result in a lost of synchro . This bad synchro is not visible because it occurs in vblank and can have an incidence if you cannot restore the good timings before the end of vblank ,i already experienced this behavior,and for me this is only produced on the real hardware and was good on emulator. For changing the Y/X scroll registers you have the entire previous scanline, so 455 cycles, i think it's more than enough and hard to miss ,except if your code/irq handler is really too slow,or wrong .
|
|
|
Post by elmer on Jul 12, 2018 20:28:10 GMT
I'm not sure exactly. The CPU -could- be getting warned about the interrupt in time to handle it correctly if you leave BIOS out of it. That could well be the case. Hudson's documentation for the system makes the intended usage seem pretty darned clear (at least to me) ... by the time that you respond to the RCR interrupt, the scroll register settings for the next line have already been read, and the values that you set are to be used for the line afterwards. Any other interrupt design would leave the PCE far, far too susceptible to small timing variations, and make it dangerous to use the Txx transfer instructions (which block interrupts during execution). Systems (such as the SNES) that can change the scroll values for the next line during the hsync before the line, tend to do so under DMA control, and not CPU control, just to avoid such an instability. Now, according to the mednafen's source code (which I tend to trust), it looks like there's an interesting edge-case in the PCE's hardware design. The RCR counter seems to be incremented, and the RCR interrupt triggered, at the end of the previous line's HDW period. Then comes the HDE period, followed by the HSW period, and then the HDS period at the start of the next scanline. According to mednafen's source code, it looks like the BXR and BYR registers aren't shadowed (i.e. locked for that line) until near to the end of the HDS period when the VDC starts to read the pixel data for the line. So different values of the HDE, HSW and HDS settings would give more-or-less time for the CPU to respond to the RCR interrupt and still (usually unwanted) change the BXR and BYR registers before they have been shadowed for the next line. I don't have real PCE hardware in front of me right now, but the easiest way to test that would be to create a weird screen with just a narrow vertical strip of background characters in the middle, and then see if you could change the scroll registers quickly-enough. Something like ... cla ldx #10 ldy #28 jsr ex_scrmod Anyway ... I guess that might explain why the System Card BIOS adds a couple of otherwise-pointless BSR/RTS delays before writing the bgx2 and bgy2 values to the VDC's scroll registers in its RCR IRQ handler.
|
|
|
Post by elmer on Jul 18, 2018 2:47:21 GMT
You're forced to have the BIOS mapped into $E000~$FFFF to do call its functions, which makes sense, but being at the CPU's last bank means that the IRQ vectors are fixed. I want a VBlank and RCR handler, and here comes EX_SETVEC to the rescue... ...except that it sucks. It automatically separates VBlank calls from RCR ones to two addresses you can set up, but the RCR "pseudovector" is never called if you don't run EX_RCRON, and if you do, the BIOS will ALWAYS set up X/Y scroll to a value determined in EX_SETRCR when the RCR interrupt triggers before handing over control for you. Have you found out how to stop the BIOS from setting the scroll registers yet? It's really quite simple. Anyway ... I guess that might explain why the System Card BIOS adds a couple of otherwise-pointless BSR/RTS delays before writing the bgx2 and bgy2 values to the VDC's scroll registers in its RCR IRQ handler. According to my reading of mednafen's source the delay from the RCR IRQ being fired to both BYR & BXR being locked is approximately (hde + hsw + hds + 1) * 8 VDC cycles. That's the same as the number of CPU cycles if you're running the VDC at 7MHz (320/336 pixel width), but you need to multiply that by 4/3 to get the CPU cycles if you're running the VDC at 5MHz (240/256 pixel width). From that, it looks like the System Card's standard 256-wide timings (hds=2 hsw=2 hde=4 hdw=31) gives a delay of 96 CPU cycles. Which nicely matches the System Card's RCR IRQ handler, which takes pretty-much-exactly 96 CPU cycles before the BXR value is written to the VDC. So, yep, I'd have to say that the 2 strange-looking BSR/RTS calls in the System Card's RCR IRQ handler are there deliberately in order to make the timings work. But note ... that only works for the System Card's 5MHz, 32-column screen mode. Other screen sizes and resolutions would need longer delays before it is safe to set the BXR and BYR registers, and so are probably going to need a custom RCR IRQ handler (which all of the games that I've looked at seem to use).
|
|
touko
Punkic Cyborg
Posts: 106
|
Post by touko on Jul 18, 2018 7:49:40 GMT
punch : If you want using your own vsync/hsync handler you have a system included in the CDROM handler one to do that. You can use it like that: Init_User_Irq() { #asm sei ; // Disable interrupts stw #User_Vsync_Irq , vsync_hook ; // User vsync handler smb #4 , <irq_m stw #User_Hsync_Irq , hsync_hook ; // User hsync handler smb #6 , <irq_m jsr _rcr_on cli ; // Enable interrupts #endasm }
Restaure_Default_IRQ() { #asm sei ; // Disable interrupts stw #vsync_user , vsync_hook ; // Default vsync handler smb #4 , <irq_m stw #hsync_user , hsync_hook ; // Default hsync handler smb #6 , <irq_m cli ; // Enable interrupts #endasm }
|
|