I have been trying really hard on my own, to create a custom irq engine with my Zelda hack, which at the time was using MMC3. I scrapped the idea back when i figured out how to manipulate the Sprite 0 irq setup within Zelda 1. But the original Sprite 0 irq within Zelda 1, will not allow me to do certain things which require the use of sprites.
So a few days ago, i went back to my old MMC3 version, to see if i could get my irq engine to work again. The issue that i've always had, is that i cant get the scanline to go past 3C or 3D. 01 obviously is the top of the screen. I'm able to adjust the value for the scanline from 01-3C, but, if i goto about 3D and onward, i will get severe flickering, and the game will eventually crash. Also, this seems to happen when i move Link around on the screen too, BUT ONLY WHEN THE SCANLINE IS CLOSE TO THE POINT OF SCREWING UP.
I original based my attempts of the irq engine within Megaman 4. But then i started wondering if it has to do with the fact the Zelda 1 runs on 8x16 sprites, since Megaman 4 runs on 8x8 sprites.
So i tried messing around with the irq engine within Super Mario Bros 3, since i'm pretty sure that game runs on 8x16 sprites. I tried inserting certain things from that irq setup, into my rom hack, but i kept getting errors.
What i do have inserted into my rom, works to an extent, I just cant get the scanline to go any further.
Whats even more bizzare, is that this scanline screws up just before it passes the bottom of the HUD (Link's map, hearts, item count, etc) But this shouldnt be a problem, since the Sprite 0 is only activated when a screen scroll is initiated, that's when $200-$203 gets changed to setup the Sprite 0 irq engine.
I am not an expert at this stuff, i just try to see what goes on, and see if i can manipulate it into my game. I'd like to share my work for everyone, and see if there is something that i'm either missing, or have coded incorrectly.
The purpose of all of this, is that i am trying to keep the HUD to stay at the top of the screen, while i can freely move the screen below the HUD. Down the road i'm going to try to create massive moving BG bosses in my game, but without an irq engine, that is impossible.
So before i share my stuff, my game runs on 8x16 sprites, my sprite ppu is located at PPU $0-$FFF, and my bg ppu is located at PPU $1000-$1FFF. By bankswap routine is based off of Super Mario Bros 2. And, i apologize to those who write in text with 6502, i only know how to write via hex mode, that's how i've always coded for 8 years.
Custom Zelda Bankswap Routine
-----------------------------------------
0A 48 A906 8D0080 68 8D0180 0901 48 A907 8D0080 68 8D0180 60
Custom Zelda IRQ Engine
-------------------------------
$8000E-$8000F = 04F9
$7F914 = 08 48 8A 48 98 48 8D00E0 8D01E0 6C1201 ($112-$113 contains low/high byte of current irq)
$8000A-$8000B = E0F8
$7F8F0 = 58 AD1401 8D00C0 8D01C0 AE1001 9D00E0 F00F AE1101 (BD25F9_low byte address of irq asm) 8D1201 (BD27F9_high byte address of irq asm) 8D1301 (4C80FF_the rest of my game)
Now, my 1st irq, isnt an irq, it just points to 8D00E0 68 A8 68 AA 68 28 40
The 2nd irq, is the one i'm trying to use, but i cant get the scanline past 3C or 3D without it flickering all to hell then crashing, and sometimes when i move link around, it'll start to glitch as well. So here is the 2nd irq asm.
$7F943 = AD0220 AC1501 0D1601 A9F4 8D0620 8D0620 A5FF 8D0020 AD1701 8D0520 8D0520 (4C29F9_jmp's to 8D00E0 68 A8 68 AA 68 28 40)
If you're using an MMC3, and are also using 8x16 sprites, you need to do special things. Sprites must use the right pattern table and backgrounds must use the left pattern table, otherwise it won't work correctly. So for Zelda 1, you'll need to hack the code that loads graphics to put it into the correct place, then hack where it selects which pattern tables to display for backgrounds, then change the sprite indexes to use the right pattern table.
If you can't do all that, try another mapper that uses cycle-based IRQs instead of PPU A12 changes.
Does mmc5 do that, cause thats the current mapper im at.
Where are you hooking your code? I remember having a similar problem when I hooked the code into the loop that waits to be interrupted by the NMI. The IRQ flag (I) wasn't being set correctly when the game starting missing frames.The solution I used was to leave IRQs enabled from start up, but just point the handler to an RTS when no raster effects were in use.
I've got it working for FME-7 if you'd like the code. I used it to draw text boxes on the unused nametable and swap in a full font.
Are you sure there's not a frame IRQ? If the game doesn't disable them already, you would need to (with the $4017 register).
I honestly dont know if it does. but that might be the case. What would I write into $4017 to disable that?
@ never-obsolete, sure id like to see what you did for a custom irq.
infidelity wrote:
I'm able to adjust the value for the scanline from 01-3C, but, if i goto about 3D and onward, i will get severe flickering, and the game will eventually crash. Also, this seems to happen when i move Link around on the screen too, BUT ONLY WHEN THE SCANLINE IS CLOSE TO THE POINT OF SCREWING UP.
Is the split by any chance delaying the start of the frame logic? I mean, when a game uses a sprite 0 hit to create a status bar at the top of the screen, it will usually only start the actual game logic calculations after it's done with the status bar. If the same is happening with your MMC3 IRQ and no frame calculations are being performed until the IRQ fires, it makes sense that you can't go past a certain point, since from that point on there's not enough time to finish the frame calculations in time for VBlank. It also explains the screwing up when Link is moving, because there are more calculations the engine has to do when the player is moving, so things screw up earlier.
I really dont know, again I really dont understand how it works and the terminology surrounding it. Im not experienced in the fundementals of doing this from scratch, ive messed with values for irqs in games, but trying to put it in a game that doesnt use it, I have no idea, but I have been, and dtill am trying.
infidelity wrote:
I really dont know, again I really dont understand how it works and the terminology surrounding it.
You should know, you hacked it! If you don't know what the code you're injecting is doing, the chances of this working are pretty slim, I must say.
Anyway, games that use sprite 0 hits usually wait for the hit in a loop. This loop doesn't do anything to process game logic, it just waits for the sprite hit in order to create a screen split and only then the program moves on to process game logic. If you hack maintains this loop and it waits for the IRQ, you won't be able to split the screen far from the top of the screen, otherwise too much time will be spent waiting and too little will be available for game logic.
What you need to do is allow the logic to start as soon as possible, because it will be interrupted when the IRQ happens. Then, in the IRQ handler, you take care of the split and return to the game logic. This will guarantee that most of the frame time will be available to the actual game, so you won't ever run out of time.
The reason im here is because I dont know what to do. Im trying to do something from the ground up, something ive never messed with majorly, so yes, its not working correctly, and yes, I hacked it, but here is what I knoe.
With sprite 0 in zelda, its only initiated by initiating a screen scroll. $200-$203 gets changed to insert a bomb sprite to aopear underneath the bg blue sprite under the hud. Once the screen scroll has ended, $200-$203 shuts off, meaning its disabled.
What I dont understand, is why the custom irq im using is failing at a certain point, I dont understand.
I pasted at the very start of this thread, exactly where I inserted my code, what the pointers are at the end of the hw bank.
I dont understand your terminology, I just want to know if my code is correct or not, and if someone could give me tge answer, not to be told I should know what im doing before I do ir. I tried many times on my oen to get this workong, and I dont know what to do.
Have you tried disabling the sprite 0 code altogether and seeing how it affects your IRQ hack? Or substituting IRQ-based code for the sprite 0 code? That would at least help you determine if they're interfering with eachother.
infidelity wrote:
I just want to know if my code is correct or not
Could you show us some actual source code to look at then? What you gave us is just a bunch of hex values, I doubt anyone is willing to go through the trouble of disassembling them by hand.
Knowing infidelity, I'm guessing that is the source code.
Ouch!
The frame IRQ is D6 of the $4017 register. If the game writes $40 or $C0 to $4017, a mapper IRQ should work fine. I doubt it's the problem in this case, but it's definitely easy to check (the game only needs to write that register once).
6502 in hex isn't too hard once you use it enough, I did hand asm/disasm plenty when I was ripping NSFs.
OK, last night I took a look at the actual irq used in Zelda 1, and i tweaked it to
use specific registers instead of hard coded values. This irq allows me to actualy
go past the HUD, i can get the irq down to about the middle of the screen, but if I
try to make it lower, and theres say about 4 of those jumping spiders, and Link shooting
his sword, i'll get bad flickering. If it's just Link on the screen, and i try to
bring the irq even further down, the irq will begin to shake as well. I'm assuming
this irq was designed with the intention that this would not be used with coexisting
sprites, since this irq is loaded when it's only Link on the playing field.
Anyway, this is the code that zelda 1 uses. And, would i be able to get this irq to
stop flickering? This code here is the absolute best one i got going on with my irq
engine.
Tweaked Zelda 1 IRQ
AD0220 :LDA $2002
AC1401 ;LDX $114 - part of Y scroll (set to 1A)
AE1501 ;LDY $115 - part of Y scroll (this is what i'm using for adjustable height, starts at 18, just below the HUD)
CA ;DEX
10FD ;BPL to DEX
88 ;DEY
10F7 ;BPL to LDY $115
A05E ;LDY #$5E - part of Y scroll
EA ;NOP
88 ;DEY
10FC ;BPL to NOP
AD0220 ;LDA $2002
A558 ;LDA $58 - Nametable High Byte Address (20/24/28/2C)
A4E2 ;LDY $E2 - Nametable Y Adjust (01-03)
8D0620 ;STA $2006
8C0620 ;STY $2006
AD0720 ;LDA $2007
AD0720 ;LDA $2007
AD1601 ;LDA $116 - X scroll
8D0520 ;STA $2005
8D0520 ;STA $2005
4C#### ;JMP to end of irq engine/then rest of game.
Also, I checked out $4017. It is written to once at the beginning of the reset vector, with the value of 40. But within the sound engine, a value of FF is constantly written to $4017, I tried changing that to 40, but I get the same irq shaking, I also tried C0 as the values, same end result.
infidelity wrote:
Tweaked Zelda 1 IRQ
AD0220 :LDA $2002
AC1401 ;LDX $114 - part of Y scroll (set to 1A)
AE1501 ;LDY $115 - part of Y scroll (this is what i'm using for adjustable height, starts at 18, just below the HUD)
CA ;DEX
10FD ;BPL to DEX
88 ;DEY
10F7 ;BPL to LDY $115
A05E ;LDY #$5E - part of Y scroll
EA ;NOP
88 ;DEY
10FC ;BPL to NOP
AD0220 ;LDA $2002
A558 ;LDA $58 - Nametable High Byte Address (20/24/28/2C)
A4E2 ;LDY $E2 - Nametable Y Adjust (01-03)
8D0620 ;STA $2006
8C0620 ;STY $2006
AD0720 ;LDA $2007
AD0720 ;LDA $2007
AD1601 ;LDA $116 - X scroll
8D0520 ;STA $2005
8D0520 ;STA $2005
4C#### ;JMP to end of irq engine/then rest of game.
There's no IRQ going on here at all, this is just a wait loop. Just think about it: this code is doing nothing but waiting and then changing the scroll. All the time spent waiting is stolen from the game engine, so if you try to split the screen too far down there will simply not be enough time for the game engine to do it's thing, specially when there's more action. If you ask me, even closer to the top of the screen this kind of code is dangerous, because you're never sure how much time the game engine will need to finish a frame, and even though it looks safe most of the time there might still be a particular location where things screw up.
If you really want to split the screen farther down the screen you will need an actual IRQ (i.e. tell the MMC3 to fire an IRQ at scanline X), so that you can let the game engine do it's thing instead of delaying it and stealing all its time.
Also, your way of changing the scroll is kinda weird, with the reads to $2007 and all.
Here's an efficient and safe sequence of writes to modify the scroll mid-frame. If you don't need fine Y scrolling (i.e. the vertical scroll is always a multiple of 8) you can simplify it a lot.
Quote:
Also, your way of changing the scroll is kinda weird, with the reads to $2007 and all
This is not his way, but Nintendo's.
Bregalad wrote:
This is not his way, but Nintendo's.
Still, it's pretty weird, and we know that the developers of the earlier games didn't have a very good understanding of the platform yet. Well, if this is indeed the original code then it's probably better to keep it.
But now you have me worried on the "dangerousness" of the above "loop" What should the actual irq engine look like? Im so close, but sprites have to be involved if im making a hg boss, plus I need to alter the irqs xy position, to give the appeatance of motion. The link you showed me, I understand what the operations are, I jusy dont know what yo define the ldas or stas, I dont know how to write text asm, im assuminh things need to be definrd?
EDIT
This is the IRQ engine i have, it's whats pasted at the beginning of this thread, but i'm spelling it out here.
1st Part
$8000A-$8000B
-------------
E0F8 ;point to $7F8E0
END
2nd Part
$7F8F0 (what is pointed to from $8000A-$8000B)
----------------------------------------------
58 ;CLI
AD1401 ;LDA $114
8D00C0 ;STA $C000
8D01C0 ;STA $C001
AE1001 ;LDX $110
9D00E0 ;STA,X $E000
F00F ;BEQ to 4C13F9
AE1101 ;LDX $111
BD25F9 ;LDA,X $F925 (low byte address for current irq loop)
8D1201 ;STA $112
BD27F9 ;LDA,X $F927 (high byte address for current irq loop)
8D1301 ;STA $113
4C13F9 ;JMP $F913
this is what i have the jmp goto, i have it check $110, and if it's equal, to wipe out all the registers used with the irq (basicly shut it down), then after that, i branch to the regular game code.
AD1001 ;LDA $110
D00A ;BNE to 4C80FF
A207 ;LDX #$07
A900 ;LDA #$00
9D1001 ;STA,X $110
CA ;DEX
D0F8 ;BNE to A900
4C80FF ;JMP $FF80 (rest of game)
END
3rd Pard
$8000E-$8000F
-------------
04F9 ;point to $7F904
END
4th Part
$7F914 (what is pointed to from $8000E-$8000F
---------------------------------------------
08 ;PHP
48 ;PHA
8A ;TXA
48 ;PHA
98 ;TYA
48 ;PHA
8D00E0 ;STA $E000
8D01E0 ;STA $E001
6C1201 ;JMP ($112) (currently loaded irq loop address in $112-$113)
END
5th Part
$7F929 (first irq loop i have, basicly off)
-------------------------------------------
8D00E0 ;STA $E000
68 ;PLA
A8 ;TAY
68 ;PLA
AA ;TAX
68 ;PLA
28 ;PLP
40 ;RTI
END
That's all i have.
Ok, i have given up on any kind of mapper based irq. I've had no luck getting it going. It also seems Zelda lacks any kind of usage for $FFFE-$FFFF, cause that interupt was never being activated. I've noticed the MMC3 Megaman games, have some sort of "Thread" (i'm going by what i read in Matrixz notes on Megaman 4) that does things to the stack, and loads up the High/Low byte irq, and jams it into the stack so that it can be read.
Anyway, i have given up on that, and i have now went back to figuring out the Sprite 0 split. Games like Zelda II, and Duck Tales, are able to have a split screen using Sprite 0, while having multiple sprite actions going on.
I'm at the point now, where i have the split below the hud not shaking, but it will start to when more than 2 sprites are on the screen. I'm assuming this is because of those "loops" i was told about.
Before everything was based on an irq mapper. So what i would like to know please, is how do i manualy write the Y position of a split scroll to $2005/$2006?
I tried reading the skinny on splitting, on nesdev wiki, but im not an expertise in this field, plus alot of it was text based code, and i don't understand that (to a degree).
This is what i have, and i know it has to do with these "loops" which is causing the shaking. This is the best so far that i've tinkered with, and i'm very close to getting this to work.
Also, i'm only able to adjust the Y position about every 8 pixels it seems, not just a pixel at a time (which i would love) I have to adjust the Nametable Address in order to mess with the Y positioning.
So please, can someone give me the proper code on writing to $2005/$2006 for a split screen, without these "loops"? I'm so close!
AD0220 ;LDA $2002
A018 ;LDY #$18 Puts Y split just below the HUD
A230 ;LDX #$30 Fine tune Y split just below the HUD
CA ;DEX
10FD ;BPL to DEX
88 ;DEY
10F8 ;BPL to LDX #$30
A04E ;LDY #$4E Puts Y split just below the HUD
EA ;NOP
88 ;DEY
10FC ;BPL to NOP
AD0220 ;LDA $2002
A558 ;LDA $58 High Address Nametable (20,24,28,2C)
A4E2 ;LDY $E2 Low Address Nametable
8D0620 ;STA $2006
8C0620 ;STY $2006
AD0720 ;LDA $2007
AD0720 ;LDA $2007
60 ;RTS
infidelity: You seem to be missing a lot of, or have serious holes in, the fundamental understanding of how the NES and how game logic works.
Sprite 0 doesn't generate an IRQ (like with some other systems). So the game logic must sit there and poll a status register until the sprite is shown on screen. The poll loop eats up cpu cycles/resource. There are only so many cpu cycles in a single frame (be it 1/60 or 1/50) and all of the game logic needs to fit in there. When you extend that loop (by moving the sprite further down the screen), you are basically removing cycles to what the original developers allocated for game logic to run on (remember, this is an old machine. Timings can be very tight and resources very restricted).
What an IRQ does, is allow a game to continue on with the game logic and when the IRQ conditions trigger, it temporarily jumps to a different (and hopefully short/small routine if during active display or such) to make whatever changes. *You* need to setup the IRQ hardware and you need to write the IRQ interrupt handler code. That's the simple side of the explanation, because there are a lot more variables that needs to be take into consideration (which is usually how this effects the game logic side of things; how it effects timings, etc).
I don't know what community you come from, but if it's the romhacking community - then you have a big uphill battle (I don't recognize you from RHDN). Romhackers always jump into such things and learn things the hard way and out of order on top of that. If you having a hard time figuring this out, I suggest taking some time to get to know the NES better. Try to understand the hardware better. I.e. try to write your own code from scratch for the NES to see how it works. Without a real understanding of how any of this works, you're just taking the hard road without the prerequisites. Of course, that's just my opinion (become a coder first, then a hacker). But.. if you're a true romhacker (like the elites) - you'll persevere.