Title: Shadow of the Beast
Original company: Psygnosis
Port: RetroNES Software
Console: NES (8 bits)
Mapper: MMC3
Librery: NESlib (Shiru)
Multiscroll engine: Doug Fraker
Music: MovieMovies1, arreglada para que funcione en MMC3
ROM:
Shadow of the Beast (alpha 0.34) [HB].nesYoutube:
https://www.youtube.com/watch?v=PthPqjZslEAhttps://twitter.com/RetroNES_Soft/statu ... 1169505281Many of you have already seen it on my Twitter account, but there it goes:
Shadow of the Beast is a videogame developed by Psygnosis in 1989 for the Amiga computer, and later programmed in many other platforms of 8 and 16 bits ... except NES.
This video game, although it is not remarkable when playing, was very famous at that time due to its artistic and musical section.
Several users of the
EOL forum, after discussing 8-bit and 16-bit video games that attracted attention in the 80s and 90s, talked about this videogame and how rare it was that it did not appear on NES when on most other platforms there was a version, even in Sega Master System.
Many possibilities were considered regarding its possible technical realization in NES and I proposed a demonstration about its viability.
The result is as follows.
NROM
Then I proposed to make a demonstration using the MMC3 for the IRQ interrupts and to be able to make the effect of the clouds.
MMC3
You can still improve, add more animations, etc ... For its realization, as always, I used the CC65 compiler and the NESlib library of Shiru. To make the MMC3 work, I've helped with the @dougeff tutorial
I do not intend to make the whole game, but simply show what NES could be capable of with this videogame.
Until I have a decent ROM I will not share anything
More info:
https://www.elotrolado.net/hilo_homebre ... ca_2282337
I've always had a fond admiration for that game. Best of luck!
Sounds like a great project. Good luck!
- April 28, 2018: we add the fence silhouetted, below.
Do you have any NTSC filtered screenshots? In the pictures, the sky colors are just too far apart to use dithering to make a convincing gradient, imo, so I was wondering if it would look any better with an NTSC filter.
Espozo wrote:
Do you have any NTSC filtered screenshots? In the pictures, the sky colors are just too far apart to use dithering to make a convincing gradient, imo, so I was wondering if it would look any better with an NTSC filter.
I do not have NTSC TV, I'm from Spain and here everything works in PAL.
I have two videos from an LED screen, and soon I will upload one from CRT to see if there is much difference and the color gradient works.
https://www.youtube.com/watch?v=W_TrfDLk6S0
This is a question I've always had: is it just harder to code that many splits in the scrolling or does it have a high cpu cycle cost? What is the most that has ever been done in a gameplay section of a game?
Anyway, I never understood the appeal to this game, but I didn't get to know it until the 16-bit era of consoles. This looks very nice!
nesrocks wrote:
This is a question I've always had: is it just harder to code that many splits in the scrolling or does it have a high cpu cycle cost? What is the most that has ever been done in a gameplay section of a game?
It's say Recca took it as far as it ever went on NES:
https://youtu.be/EE5URFvZfHo?t=5m25sThere are a bunch of others that have a high number of splits. Rad Racer, Tetrastar, etc.
With an IRQ they take up a much smaller cycle cost than without one, 'cause you can keep executing code between the splits. Without the IRQ you have to dedicate the whole CPU to splits until you're done splitting (e.g. this is why half the screen is sky in Rad Racer, time to get the other work done).
And now to work in the forest
Definitely looks better now that the colors are closer together.
Have you ever considered doing something like this to also make the transformation smoother? I didn't bother trying to put it "behind" the trees, even though you'd obviously want to do that.
Ok, @Espozo I'll keep it in mind next time.
@espozo: Actually curved gradients like that can help a lot with making something look more alive and less a pattern... even if you did it to avoid the work around the trees.
Tough to pull off with scrolling though as you don't want that to scroll at all.
Ok?
Diskover wrote:
Several users of the
EOL forum, after discussing 8-bit and 16-bit video games that attracted attention in the 80s and 90s, talked about this videogame and how rare it was that it did not appear on NES when on most other platforms there was a version, even in Sega Master System.
I was about to point out that it's very common that an inherent Amiga game doesn't get an NES port, but looking it up, I'm absolutely baffled how many ports this game actually did get!
I've always seen the game as primarily an Amiga title, and basically a tour de force of showing off what the system can do, with very little care taken into how it actually played.
Your videos are really amazing looking, and I'm very interested in seeing how the demo ends out on the NES, backed by your expertise. Would it be too much to also wish for an attempt at fixing the terrible gameplay, and make it into a fun game to play as well?
Or are you only focusing on recreating the graphical experience?
Sumez wrote:
I was about to point out that it's very common that an inherent Amiga game doesn't get an NES port, but looking it up, I'm absolutely baffled how many ports this game actually did get!
I've always seen the game as primarily an Amiga title, and basically a tour de force of showing off what the system can do, with very little care taken into how it actually played.
Your videos are really amazing looking, and I'm very interested in seeing how the demo ends out on the NES, backed by your expertise. Would it be too much to also wish for an attempt at fixing the terrible gameplay, and make it into a fun game to play as well?
Or are you only focusing on recreating the graphical experience?
This is just a technical / graphic demonstration.
I do not have enough capacity or knowledge to make the whole game.
Having an engine that makes me scroll simply is almost impossible for me. Imagine making an engine that contemplates multi-directional scroll.
I have been playing with the MMC3. I can split the screen into pieces to simulate parallax, I can even play to change CHR banks partially, and little else.
I've been in the scene for years, and I've made an engine capable of 8-directional scrolling. (I cannot give a release date because it is for a client.) But even I shudder at the thought of
making an engine that updates the tilemap for different layers at different speeds, as would be required for having one of the layers be more than 512 pixels in width, and combining that feature with 8-directional scrolling.
For me the hardest part would be getting the large enemies on screen without it being a flicker fest, the game likes everything big.
AVS and NT mini would handle it better of course, even if most'd play it on the NES or on a NES emulator.
Oziphantom wrote:
For me the hardest part would be getting the large enemies on screen without it being a flicker fest, the game likes everything big.
In the Sega Master System version, what they do when they arrive at these meetings is to move to a screen where the background is the boss.
https://youtu.be/BnwOih21rbE?t=8m3sFrankenGraphics wrote:
AVS and NT mini would handle it better of course, even if most'd play it on the NES or on a NES emulator.
What is AVS and NT mini?
Diskover wrote:
What is AVS and NT mini?
Recent clone systems that both (?) have an option to double the sprite limit to 16 instead of 8, if I recall. (Not sure about the NT, but I'll assume yes based on that comment.)
AVS:
http://www.retrousb.com/product_info.php?products_id=78The NT is perpetually unavailable, but there are at least a few out there in the world:
https://www.analogue.co/pages/nt-mini/
rainwarrior wrote:
Diskover wrote:
What is AVS and NT mini?
Recent clone systems that both (?) have an option to double the sprite limit to 16 instead of 8, if I recall. (Not sure about the NT, but I'll assume yes based on that comment.
Overcoming that limit is very interesting, but ... I would like to stick to the real limitations of the NES.
As before, there are solutions, and in Sega Master System became the bosses in part of the background, as happened in many NES games as well.
rainwarrior wrote:
that both (?) have an option to double the sprite limit
Yeah, both have a 16 sprites per scanline mode.
NT mini will likely be unavailable for quite some time due to the unexpected demand of their super famicom clone. Preorders of the second batch of those are estimated to ship this autumn and it seems it's all hands on deck to get those out first before resuming production of the nt mini:
https://support.analogue.co/hc/en-us/ar ... ailabilitythe Super NT is priced to sell, unlike NT/NT mini which are de luxe. I predict they'll come up with a new, cheaper case option for the NT mini following the success of the Super NT eventually.
diskover wrote:
I would like to stick to the real limitations of the NES.
And it's very reasonable to do so. Still, these fpga clones will yield a smoother experience of let's say bubble bobble or castlevania even though these games weren't designed around a higher sprites per scanline tolerance.
First scroll tests.
The engine used for this scroll is the All-direction scrolling (with small modifications), by Doug Fraker.
Its peculiarity lies in that it works under the NES 4-screen format.
I have to solve errors.
https://www.youtube.com/watch?v=FFKp4oZ21F8
I don't know if this is a property of the original game or not, but however dynamic and impressive looking all the parallax is, i think the clouds come off as unnatural when they scroll that fast. They're probably the most distanced objects depicted or at least on an approximate depth level with the mountains, yet they react to camera position like they were hanging in front of everything, which would probably work great for a mist or the like. I'd probably leave clouds scrolling on speed with or slower than the mountains when it's contingent on camera/player movement, but ever so slowly auto-scrolling to indicate movement, wind and depth.
That's what the original game is like. Or well, almost. They are really "low hanging" clouds.
Honestly, I think it's an artistic freedom games should be able to take. I love scrolling clouds like that. Nothing to build a creepy atmosphere like
SOTN-style fast clouds, too.
They don't really scroll that fast in the original:
https://www.youtube.com/watch?v=73JBaFkNZaE&t=12m26s...but I mean, Diskover is just getting the scrolling working at this point. Tweaking the speed is a trivial adjustment.
Myself I'm hoping there's a few sprites left on the scanline for a blimp.
There's a nice facsimile here, though missing the blimp:
http://www.int33h.com/test/shadow/
Put a forest in your life.
inside the tree
In the next few days I will release the rom demo of Shadow of the Beast for NES.
The truth is that it has taken a lot of time away from other projects because I got hooked on making it work despite my limitations and the limitations of the machine. A team of professionals would have polished it without much trouble.
In fact, the rom contains some flaw, much more visible in emulator, but functional in a real NES console through everflash, etc ...
I'm very excited about it, but I want to leave it here to continue with the remodeling of my most important project: The Banketh
ROM:
http://www.retrones.net/sites/default/f ... BHB%5D.nesIt has been developed with support from the NESlib library of Shiru. The multidirectional scroll is a modification of the original engine of Doug Fraker, which has also been adapted to work with the mapper MMC3 (to achieve plane effects). I found the music by chance in a forum dedicated to famitraker, and it was developed by MovieMovies1 for the mapper MMC5. Obviously, I have adapted it to work in the MMC3.
It works perfectly on a real NES using flashcard and other methods.
If you want to use it on PC or smartphone, the VirtuaNES emulator is recommended.
This ROM fails in 5 of the 6 emulators I tried. It worked in JNES 1.1, with a few errors.
It isn't quite working for me on my PowerPak either. Seems playable but some of the graphics are displaying the wrong tiles, and the scroll splits seem broken every second frame? (Seen as interlaced lines in the picture below.)
I dunno what your goals are, but it's probably worth trying to do this in a way that plays nice with most emulators? Unless you're specifically trying to exploit something technical that only the "real thing" can do, you're probably relying on some specific quirk of the implementation of MMC3 used by your flashcart which may or may not be present on an actual MMC3. (Clearly my PowerPak's simulation of an MMC3 differs from the one you used on your flashcart.) If you write code that is more within the boundaries of the well known parts of the MMC3 though, it should run on more emulators too.
Otherwise, I am excited to see this ready for public viewing.
Seems to work fine on my Everdrive. Did not work on FCEUX when I tried immediately after I downloaded.
I recommend using the VirtuaNES emulator or in a real NES using flashcard
http://virtuanes.s1.xrea.com/bin/virtuanes097e.zipI spent a lot of time trying to solve the errors in the other emulators, but it has been impossible for me.
The problem is when I activate the instruction asm ('cli'); for the interruption of the MMC3 to work.
Guide me through the dougeff MMC3 tutorial
https://nesdoug.com/2016/01/15/24-mmc3- ... hing-irqs/
Like rainwarrior said, unless you're intentionally exploiting hardware quirks that emulators are known to have problems with, it's a good idea to look into why it fails on so many setups. Even if it does work on real hardware (although it seems that different MMC3 implementations in flash carts are still disagreeing), and theoretically the original console has the final word, the fact that slight deviations from the real hardware are causing visible problems could mean your code is barely working, and under certain circumstances could still break.
A lot of these emulators are pretty accurate (unlike VirtuaNES, from what I could find online) and can handle all sorts of games just fine, so they should be able to handle your effects without problems too. I think the effort of making this game/demo work well across different emulators is worth it, as you'll end up with a more robust engine overall.
tokumaru wrote:
Like rainwarrior said, unless you're intentionally exploiting hardware quirks that emulators are known to have problems with, it's a good idea to look into why it fails on so many setups. Even if it does work on real hardware (although it seems that different MMC3 implementations in flash carts are still disagreeing), and theoretically the original console has the final word, the fact that slight deviations from the real hardware are causing visible problems could mean your code is barely working, and under certain circumstances could still break.
A lot of these emulators are pretty accurate (unlike VirtuaNES, from what I could find online) and can handle all sorts of games just fine, so they should be able to handle your effects without problems too. I think the effort of making this game/demo work well across different emulators is worth it, as you'll end up with a more robust engine overall.
I have not done anything particularly weird to make the game work. As I mention, when implementing the MMC3, at the moment I activate the instruction asm ('cli'); for interruptions per line to work, in most emulators it stops working. On the other hand, in VirtuaNES and in a real NES it works perfectly.
If I deactivate the instruction asm ('cli'); the game works on all
rainwarrior wrote:
It isn't quite working for me on my PowerPak either. Seems playable but some of the graphics are displaying the wrong tiles, and the scroll splits seem broken every second frame? (Seen as interlaced lines in the picture below.)
I dunno what your goals are, but it's probably worth trying to do this in a way that plays nice with most emulators? Unless you're specifically trying to exploit something technical that only the "real thing" can do, you're probably relying on some specific quirk of the implementation of MMC3 used by your flashcart which may or may not be present on an actual MMC3. (Clearly my PowerPak's simulation of an MMC3 differs from the one you used on your flashcart.) If you write code that is more within the boundaries of the well known parts of the MMC3 though, it should run on more emulators too.
Otherwise, I am excited to see this ready for public viewing.
The sprites work under the 8x16 configuration
From what I see, it seems that your PowerPak has not identified them that way and tries to show them as 8x8
I have an idea: this afternoon, when I leave work, I will put the game on an MMC3 board.
I think I remember that I have PRG and CHR stored in some box. I will flase, weld and try with the MMC3 of RetroStage.-
If you are setting and clearing interrupts 200+ times a frame, this may be the problem.
Other games don't do this, which is why no emulator author has bothered to get the accuracy perfect on such a thing.
MMC3 has a scanline counter system. I would use that. That just requires keeping interrupts ON the whole frame and just resetting a counter value several times a frame.
Also, are you using a PAL NES, diskover? That might be part of the issues that rainwarrior is having.
Quote:
I will put the game on an MMC3 board
You might have issues, if the board doesn't have 4 screen mirroring, like the ROM.
Yes, I am using a PAL NES
I configured this in this way to be able to do 15 screen divisions and in that way make parallax scroll effects.
Code:
irq:
pha
txa
pha
tya
pha
ldy #15 ;wait a little, loop 15 times
: dey ;2 cycles
bne :- ;3 cycles
ldx _Scroll_Index ;each time the irq fires, it fetches a different byte from and array
lda _Scroll, x
sta $2005 ;change the horizontal scroll
lda _scrollY ;#0 originalmente. Controlamos desplazamiento vertical de la pantalla
sta $2005 ;vertical scroll = 0
inc _Scroll_Index
lda #1
sta $e000 ; acknowledge the irq, turn off the counter
lda #14 ; Alto en pixeles de cada linea IRQ. Tenemos 10 trozos a repartir. Hay que probar con 32
sta $c000 ; set up the next irq, 20 scanlines
sta $c001
lda #1
sta $e001 ; turn on the scanline counter
pla
tay
pla
tax
pla
rti
The problem is that you did not disable APU Frame Counter IRQs at power on. These are enabled by default, at least on NTSC consoles (and likely most emulators):
http://wiki.nesdev.com/w/index.php/CPU_power_up_state)
Changing Mesen's code to boot with APU IRQs disabled fixes (almost) everything:
Attachment:
shadow.png [ 25.98 KiB | Viewed 4183 times ]
I say almost because at some very specific character positions, the background (between the clouds & ground) flashes in or out of existence for a few pixels.
This issue reminds me of this problem bananmos had with a PAL rom:
viewtopic.php?p=214822#p214822It's possible that PAL NES might boot with the "disable IRQ" flag turned on for the frame counter, which would explain both issues. (I'm unsure if any of the PAL test roms check this particular behavior)
Sour wrote:
The problem is that you did not disable APU Frame Counter IRQs at power on. These are enabled by default, at least on NTSC consoles (and likely most emulators):
http://wiki.nesdev.com/w/index.php/CPU_power_up_state)
Changing Mesen's code to boot with APU IRQs disabled fixes (almost) everything:
I say almost because at some very specific character positions, the background (between the clouds & ground) flashes in or out of existence for a few pixels.)
Yes, it is a problem that I have not been able to solve and that has to do with the camera that follows the player. For 4 pixels, it is positioned in the previous nametable. I tried many things, such as delaying a few pixels, but this generated other new problems, and I gave up. Also in PAL console this small defect occurs.
It only happens when we work with MMC3 and the IRQs are on. If I deactivate it, it does not happen.
Sour wrote:
This issue reminds me of this problem bananmos had with a PAL rom:
viewtopic.php?p=214822#p214822It's possible that PAL NES might boot with the "disable IRQ" flag turned on for the frame counter, which would explain both issues. (I'm unsure if any of the PAL test roms check this particular behavior)
And what is the solution if the IRQs should always be on to make the parallax scroll effect?
Manually turn it on?
It seems the neslib based source code on my webpage omits this bit
lda #$40
sta $4017
from crt0.s
I believe I borrowed this crt0 from the Alter Ego source code.
$4017 is the APU frame counter. Writing #$40 here disables frame count IRQs. Please add this somewhere near the top of crt0.s. Sorry for the inconvenience.
Quote:
It seems the neslib based source code on my webpage omits this bit
lda #$40
sta $4017
from crt0.s
I believe I borrowed this crt0 from the Alter Ego source code.
$4017 is the APU frame counter. Writing #$40 here disables frame count IRQs. Please add this somewhere near the top of crt0.s. Sorry for the inconvenience.
(I quoted myself because this is the first comment on a new page of comments, and I want to keep the context of the conversation in place).
Once I edited that line in...it works in most emulators. It doesn't work in Nintendulator.
I think the reason is because you put the reset code at $8458 in the swappable bank. reset code should be at $e000-ffff in the fixed bank. And your reset code should explicitly put the correct banks in place before you use them.
I think, if you did those 2 fixes, it would would in nearly all emulators.
Thanks dougeff
It seems that the problem was solved adding those two lines after start: in crt0.s
Here you have the new rom arranged:
Shadow of the Beast (alpha 0.2) [HB].nesHowever, I do not understand that of the bank $8458 ¿?¿?¿?
I have not touched anything there
On MMC3, only the last bank is guaranteed to be mapped to a specific part of PRG ROM at power on.
So if your reset vector is not within the $E000-$FFFF range, there's no guarantee it will work properly on a real cart.
If I turn on the "Randomize mapper state at power on" option in Mesen, the game mostly crashes/freezes instead of booting (because the part of PRG ROM that is mapped to $8000-$9FFF is random, instead of always being bank 0)
Ahh, good to see it working. Yes, my PowerPak test was NTSC, did not realize it was to be PAL until you said so.
BTW you can get some emulators to automatically select PAL with "(E)" in the filename. I think you could also use an iNES 2 header to
specify PAL, but only some newer emulators will use this.
Diskover wrote:
However, I do not understand that of the bank $8458 ¿?¿?¿?
I have not touched anything there
MMC3 powers on with a "random" bank at that address. Only $E000-$FFFF is fixed, so your RESET vector should point there for it to reliably boot on a real cart. (Everdrive and PowerPak do not simulate this, they don't boot a ROM from power-on, so some banks are already set up.)
To do this, you could add a segment to your config file in the last bank with e.g. start=$FF00 and stick a reset stub in that segment. (Whatever you're doing for the vectors segment already, you can do similarly.)
rainwarrior wrote:
Ahh, good to see it working. Yes, my PowerPak test was NTSC, did not realize it was to be PAL until you said so.
BTW you can get some emulators to automatically select PAL with "(E)" in the filename. I think you could also use an iNES 2 header to
specify PAL, but only some newer emulators will use this.
MMC3 powers on with a "random" bank at that address. Only $E000-$FFFF is fixed, so your RESET vector should point there for it to reliably boot on a real cart. (Everdrive and PowerPak do not simulate this, they don't boot a ROM from power-on, so some banks are already set up.)
To do this, you could add a segment to your config file in the last bank with e.g. start=$FF00 and stick a reset stub in that segment. (Whatever you're doing for the vectors segment already, you can do similarly.)
I have not intended it to be PAL. It should work in NTSC and PAL, or at least that's what I want.
When I get home (right now I'm at work) I look at these vectors, but I insist that I have not touched anything that makes them change to something "random". The truth is that I am confused about this. But I will review it.
Random is exactly what happens when you don't touch anything.
It's my experience that almost all issues with certain emulators or real hardware come from failing to initialize everything you need. This includes both clearing RAM, setting hardware states (such as enabling IRQ), and configuring your mapper chip. You have to rely on a static bank with your reset vector in it, and within this bank you add your initialization code to make sure the remaining banks are mapped correctly.
The last similar issue I ran into was a feature I had completely forgotten in the MMC3 - writing to the cartridge RAM is impossible if the write lock is set, and just like everything else, it might "randomly" be so on hardware or certain emulators.
MMC3 banks are not set by default on hardware. I had that issues when I did my first tests 8 years ago on my dev cartridge and all my chr banks where scrambled. The emulators were setting them to a predefined default when it was not the case on the real thing. Once I found that then my code was working fine.
The same is that I explain myself wrongly.
The whole basis with which I made the MMC3 part of this dougeff guide:
https://nesdoug.com/2016/01/15/24-mmc3- ... hing-irqs/The configuration of the CFG is as follows:
Code:
#ROM Addresses:
#they are all at $8000, because I will be swapping them into that bank
PRG0: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG1: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG2: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG3: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG4: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG5: start = $a000, size = $2000, file = %O ,fill = yes, define = yes;
PRG6: start = $c000, size = $2000, file = %O ,fill = yes, define = yes;
PRG7: start = $e000, size = $1ffa, file = %O ,fill = yes, define = yes;
# Hardware Vectors at end of the ROM
VECTORS: start = $fffa, size = $6, file = %O, fill = yes;
Yes, but look down in "segments" in nes.cfg.
Is "startup" mapped to PRG7? It is for the example code. and when I run mine, and pause execution, and hit reset, I see in the debugger that it jumps to $e005.
Let's see.
The rest of the instructions I have them put like this:
Code:
#1 Bank of 8K CHR ROM
CHR: start = $0000, size = $10000, file = %O, fill = yes;
}
SEGMENTS {
HEADER: load = HEADER, type = ro;
CODE0: load = PRG0, type = ro, define = yes;
CODE1: load = PRG1, type = ro, define = yes;
CODE2: load = PRG2, type = ro, define = yes;
CODE3: load = PRG3, type = ro, define = yes;
CODE4: load = PRG4, type = ro, define = yes;
CODE5: load = PRG5, type = ro, define = yes;
CODE6: load = PRG6, type = ro, define = yes;
STARTUP: load = PRG0, type = ro, define = yes;
CODE: load = PRG7, type = ro, define = yes;
VECTORS: load = VECTORS, type = ro;
CHARS: load = CHR, type = rw;
LOWCODE: load = PRG7, type = ro, optional = yes;
INIT: load = PRG7, type = ro, define = yes, optional = yes;
RODATA: load = PRG7, type = ro, define = yes;
DATA: load = PRG1, run = RAM, type = rw, define = yes;
MAP: load = MAP1, type = bss, define = yes;
BSS: load = RAM, type = bss, define = yes;
HEAP: load = RAM, type = bss, optional = yes;
ZEROPAGE: load = ZP, type = zp;
#ONCE: load = PRG, type = ro, define = yes;
}
Now I remember that STARTUP I put in PRG0 because in PRG7 I did not enter anymore. As I saw that it worked, I did not give importance to it.
It's important. So let's try to resolve.
"CODE" is where cc65 puts the C library. That's probably filling up PRG7, and why you can't put more there. Or perhaps you put the music in "CODE" or "STARTUP", filling it.
Try putting "CODE" in PRG6, and "STARTUP" in PRG7.
If that doesn't work, try putting the music in another segment.
Is this correct?
Code:
CODE: load = PRG0, type = ro, define = yes;
STARTUP: load = PRG7, type = ro, define = yes;
Well, I suggested CODE in PRG6.
That would put it in PRG0.
Give it a try, either way. See if it compiles.
Ok, done, but I do not know what I've played now that when I turn on the music, the game does not work correctly: cry:
My assumption is that you're running your music within the NMI.
The reason this is a problem is that NMI implicitly does a SEI (cleared by the RTI popping the processor flags). So if your music update happens in your NMI routine, it will overlap and block your interrupts if it takes too long, which it does on NTSC.
Easy fix: just put a CLI in the NMI routine just before it calls the music playback (assuming it is the last thing that happens in your NMI handler). Otherwise if that's not feasible, you can just move the music playback outside of the NMI. It doesn't really matter too much where it gets called as long as it's once per frame, preferably at a consistent time (which is why NMI is usually convenient).
Edit: Actually, peeking at it in a debugger, it looks like your NMI is missing an RTI at the end? It seems to roll right into the IRQ handler after finishing. So in this case, I'd recommend putting a CLI before the music playback there, and also an RTI before the IRQ handler begins.
Code:
03:E224: A9 00 LDA #$00
03:E226: 85 02 STA $02 = #$03
03:E228: 20 4C E8 JSR $E84C ; music playback? place a CLI right before this line
03:E22B: 68 PLA
03:E22C: A8 TAY
03:E22D: 68 PLA
03:E22E: AA TAX
03:E22F: 68 PLA ; shouldn't an RTI follow this line?
>03:E230: 48 PHA ; IRQ handler starts here
03:E231: 8A TXA
03:E232: 48 PHA
03:E233: 98 TYA
03:E234: 48 PHA
...
03:E260: 40 RTI
Ah, I see the problem. Wasn't quite where I was suggesting, though related:
You set up your first IRQ here in your main thread code. This happens directly after the NMI returns:
Code:
00:9BB8: 20 C0 E3 JSR $E3C0 ; wait for NMI
>00:9BBB: A9 01 LDA #$01 ; setup first interrupt
00:9BBD: 8D 00 E0 STA $E000
00:9BC0: 8D 00 C0 STA $C000
00:9BC3: A9 00 LDA #$00
00:9BC5: 8D 01 C0 STA $C001
00:9BC8: A9 01 LDA #$01
00:9BCA: 8D 01 E0 STA $E001
00:9BCD: A9 00 LDA #$00
00:9BCF: 85 74 STA $74
The problem is that the music routine delays when you will return from NMI. On PAL there is plenty of time for it to execute before rendering begins, but on NTSC it will overlap the beginning of the frame sometimes. If this first IRQ setup doesn't happen before scanline 0, the whole screen is thrown off. (Seems to be about 10-15 scanlines late on every other frame.)
The solution should be to put this inside your NMI handler. See my last suggestion from my previous post, you should still add that CLI and RTI, but right there above the suggested CLI do this first IRQ setup right there, when you know you're still in vblank (i.e. before scanline 0) and you haven't yet run the music routine. This will allow that first IRQ to fire on scanline 0 (which will sometimes be within the music routine, but it is perfectly okay to interrupt that).
Alternative option is to put the music playback call in your main thread just after that STA $74. This will get your NMI handler returning earlier again.
Ideally both of these things should be within the NMI, though. Having the IRQs set off by the NMI will prevent them from failling if your main thread ever runs too long (slowdown), and similar with music having it in the NMI makes it slowdown resitant. However, if you can guarantee the main thread will never run long it doesn't matter either way.
rainwarrior wrote:
My assumption is that you're running your music within the NMI.
The reason this is a problem is that NMI implicitly does a SEI (cleared by the RTI popping the processor flags). So if your music update happens in your NMI routine, it will overlap and block your interrupts if it takes too long, which it does on NTSC.
Easy fix: just put a CLI in the NMI routine just before it calls the music playback (assuming it is the last thing that happens in your NMI handler). Otherwise if that's not feasible, you can just move the music playback outside of the NMI. It doesn't really matter too much where it gets called as long as it's once per frame, preferably at a consistent time (which is why NMI is usually convenient).
Edit: Actually, peeking at it in a debugger, it looks like your NMI is missing an RTI at the end? It seems to roll right into the IRQ handler after finishing. So in this case, I'd recommend putting a CLI before the music playback there, and also an RTI before the IRQ handler begins.
Code:
03:E224: A9 00 LDA #$00
03:E226: 85 02 STA $02 = #$03
03:E228: 20 4C E8 JSR $E84C ; music playback? place a CLI right before this line
03:E22B: 68 PLA
03:E22C: A8 TAY
03:E22D: 68 PLA
03:E22E: AA TAX
03:E22F: 68 PLA ; shouldn't an RTI follow this line?
>03:E230: 48 PHA ; IRQ handler starts here
03:E231: 8A TXA
03:E232: 48 PHA
03:E233: 98 TYA
03:E234: 48 PHA
...
03:E260: 40 RTI
rainwarrior wrote:
Ah, I see the problem. Wasn't quite where I was suggesting, though related:
You set up your first IRQ here in your main thread code. This happens directly after the NMI returns:
Code:
00:9BB8: 20 C0 E3 JSR $E3C0 ; wait for NMI
>00:9BBB: A9 01 LDA #$01 ; setup first interrupt
00:9BBD: 8D 00 E0 STA $E000
00:9BC0: 8D 00 C0 STA $C000
00:9BC3: A9 00 LDA #$00
00:9BC5: 8D 01 C0 STA $C001
00:9BC8: A9 01 LDA #$01
00:9BCA: 8D 01 E0 STA $E001
00:9BCD: A9 00 LDA #$00
00:9BCF: 85 74 STA $74
The problem is that the music routine delays when you will return from NMI. On PAL there is plenty of time for it to execute before rendering begins, but on NTSC it will overlap the beginning of the frame sometimes. If this first IRQ setup doesn't happen before scanline 0, the whole screen is thrown off. (Seems to be about 10-15 scanlines late on every other frame.)
The solution should be to put this inside your NMI handler. See my last suggestion from my previous post, you should still add that CLI and RTI, but right there above the suggested CLI do this first IRQ setup right there, when you know you're still in vblank (i.e. before scanline 0) and you haven't yet run the music routine. This will allow that first IRQ to fire on scanline 0 (which will sometimes be within the music routine, but it is perfectly okay to interrupt that).
Alternative option is to put the music playback call in your main thread just after that STA $74. This will get your NMI handler returning earlier again.
Ideally both of these things should be within the NMI, though. Having the IRQs set off by the NMI will prevent them from failling if your main thread ever runs too long (slowdown), and similar with music having it in the NMI makes it slowdown resitant. However, if you can guarantee the main thread will never run long it doesn't matter either way.
Sorry for taking a long time to answer. Busy.
We'll see. I do not have much idea of assembler, but let's see if I can fix this.
The routine that NMI controls is part of the NESlib library. According to the instructions that you indicate, I should put a CLI control before the JSR FamiToneUpdate line and it would look like this:
Code:
;NMI handler
nmi:
...
...
...
@skipNtsc:
cli
jsr FamiToneUpdate
pla
tay
pla
tax
pla
This is correct?
Well, there are three things:
1. Put the IRQ setup in your NMI handler before jsr FamitomeUpdate so that it is guaranteed to happen before the end of vblank.
2. Right after the IRQ setup, put cli (also before jsr FamitoneUpdate) so that if an IRQ happens during the music routine it won't be blocked.
3. Put rti on the end of your NMI handler (after that ...tax, pla). Without this, the code just keeps running into the IRQ handler directly below.
The main thing I'm not entirely certain of, without looking at much more of the code, is whether it's appropriate to set up the IRQ every NMI or just on screens that need it. Maybe it should have a flag that turns it on and off? (When I say IRQ setup I mean that code including lines $9BBB to $9BCF in that disassembly.)
As an alternative, just as a quick test, you could just take jsr FamitomeUpdate and move it just under the IRQ setup where it is right now. (Just after where it stores a #0 to your IRQ counter variable at $74.) That would also solve the problem you're having that this music update is happening before you've prepared your IRQs to fire. I wouldn't recommend this as a permanent solution, though, because it's usually appropriate to do music in the NMI handler. If it's not in the NMI handler, music will tend to skip during scene transitions, and also you would need to manually call jsr FamitoneUpdate in each main thread frame loop if there are more than one.
Ok, let's see. Right now this is like this:
Code:
;NMI handler
nmi:
...
...
...
@skipNtsc:
LDA #$01 ; turn off MMC3 IRQ
STA $E000
STA $C000 ; count 20 scanlines, then IRQ
LDA #$00
STA $C001
LDA #$01
STA $E001 ;turn on MMC3 IRQ
LDA #$00
STA $74
cli
jsr FamiToneUpdate
pla
tay
pla
tax
pla
rti
irq:
pha
txa
pha
tya
pha
ldy #15
: dey
bne :-
ldx _Scroll_Index
lda _Scroll, x
sta $2005
lda _scrollY
sta $2005
inc _Scroll_Index
lda #1
sta $e000
lda #14
sta $c000
sta $c001
lda #1
sta $e001
pla
tay
pla
tax
pla
rti
I share the rom. It works in NES PAL and in the emulated NEStopia but now it gives problems in FCEUx and VirtuaNES.
I think the problem is right here:
Code:
00:9BB9: 20 D8 E3 JSR $E3D8 ; wait for NMI to finish
00:9BBC: A9 00 LDA #$00
>00:9BBE: 85 74 STA $74 = #$00 ; reset raster split index
00:9BC0: AD C3 04 LDA $04C3 = #$04
You moved the IRQ setup into the NMI (before that CLI) but you left this reset of $74 to 0 in the main loop as soon as it returns from the NMI. I don't know what you call the variable at $74 but it appears to be an index into your table of how many scanlines to skip per split. Leaving this extra $74 = 0 in there causes the splits to start over in the middle of the screen.
Doesn't cause a problem in PAL or without music on NTSC because if NMI finishes before vblank it hasn't run any IRQs yet (resets 0 back to 0). Once you add music in, some IRQs will happen before the music is finished, and this reset ends up mid-screen.
(If I replace that STA $74 with two NOPs it seems to run as correctly as the other modes.)
Edit: Oh, you called $74
_Scroll_Index in your IRQ code, you should use that at
@skipNtsc too just in case the variable ever moves. I was only calling it $74 because I was looking at it through a disassembly.
rainwarrior wrote:
Oh, you called $74 _Scroll_Index in your IRQ code, you should use that at @skipNtsc too just in case the variable ever moves. I was only calling it $74 because I was looking at it through a disassembly.
Ok, now I have understood.
According to the dougeff tutorial everything that corresponds to the IRQ configuration, etc ... is written in C, even the variable Scroll_Index I put it to 0 from there.
https://nesdoug.com/2016/01/15/24-mmc3- ... hing-irqs/When you have indicated the faults that you see from assembler, I have not understood very well, but I let myself be guided by you until I understood it.
Well, what I have done next has been to change those two lines and put them in this way:
Code:
LDA #$00
STA _Scroll_Index ; ponemos Scroll_Index a 0
Now the rom seems to work well in the emulators VirtuaNES, NEStopia, FCEU, etc ...
I just need to know if it works well now in an NTSC NES.
That looks better in terms of scrolling.
One more issue though: you haven't set up 4 of the CHR banking registers. You can see the problem using Mesen, but it appears the same way on my PowerPak (i.e. the character sprite and moon sprite are using the wrong tiles). This isn't NTSC / PAL related, it is only about fully initializing the MMC3 (would look the same on PAL PowerPak/Mesen).
Of the 8 bank settings on the MMC3 (selected through $8000) I see setup for: 0, 1, 6, 7 (PPU first page, and CPU banks). You are missing any setup for 2, 3, 4, 5 (PPU second page, i.e. all your sprites).
Some emulators, and apparently the Everdrive, pre-initialize these with default values, but on the real MMC3 these are "random" when powered on. (You can see what
FCEUX uses instead of randomness, for example. This seems to be a common setup pattern for emulators, Everdrive must have borrowed it.)
Anyhow, really easy to fix, just send 4,5,6,7 to the uninitialized banks 2,3,4,5 in your startup code:
Code:
lda #2
sta $8000
lda #4
sta $8001
lda #3
sta $8000
lda #5
sta $8001
lda #4
sta $8000
lda #6
sta $8001
lda #5
sta $8000
lda #7
sta $8001
The 0, 2, 4, 5, 6, 7, 0, 1 pattern seen in FCEUX
MMC3RegReset() sets up an identity mapping: PPU $0000-$1FFF = CHR ROM $00000-$01FFF. It's also what
my stock MMC3 init code sets up.
rainwarrior wrote:
That looks better in terms of scrolling.
One more issue though: you haven't set up 4 of the CHR banking registers. You can see the problem using Mesen, but it appears the same way on my PowerPak (i.e. the character sprite and moon sprite are using the wrong tiles). This isn't NTSC / PAL related, it is only about fully initializing the MMC3 (would look the same on PAL PowerPak/Mesen).
Of the 8 bank settings on the MMC3 (selected through $8000) I see setup for: 0, 1, 6, 7 (PPU first page, and CPU banks). You are missing any setup for 2, 3, 4, 5 (PPU second page, i.e. all your sprites).
Some emulators, and apparently the Everdrive, pre-initialize these with default values, but on the real MMC3 these are "random" when powered on. (You can see what
FCEUX uses instead of randomness, for example. This seems to be a common setup pattern for emulators, Everdrive must have borrowed it.)
Anyhow, really easy to fix, just send 4,5,6,7 to the uninitialized banks 2,3,4,5 in your startup code:
Code:
lda #2
sta $8000
lda #4
sta $8001
lda #3
sta $8000
lda #5
sta $8001
lda #4
sta $8000
lda #6
sta $8001
lda #5
sta $8000
lda #7
sta $8001
I have not understood what this really does, but I have tried to fix it.
Is it right now?
Yes, this one now works on PowerPak on my (NTSC) NES with music. It also works in Mesen. The only emulator that seems to fail with it now is Nintendulator, but I'm not sure why that is.
There are smaller glitches still, I'm sure you've seen, but the main stuff is working. This is good!!
The problem this Nintendulator is the same kind of issue as with the sprites, just this time with PRG banking. You haven't initialized the bank at $8000-9FFF (banking register 6) before you use it. Apparently almost all emulators initialize this to 0, and even the PowerPak and Everdrive seem to do this too, but again this would be random on the real MMC3 cart.
Your startup code:
Code:
03:E005: A9 40 LDA #$40 ; reset begins here
03:E007: 8D 17 40 STA $4017 = #$00
03:E00A: 78 SEI
03:E00B: A2 FF LDX #$FF
03:E00D: 9A TXS
03:E00E: E8 INX
03:E00F: 8E 01 20 STX $2001 = #$00
03:E012: 8E 10 40 STX $4010 = #$00
03:E015: 8E 00 20 STX $2000 = #$00
03:E018: 2C 02 20 BIT $2002 = #$00
03:E01B: 2C 02 20 BIT $2002 = #$00
03:E01E: 10 FB BPL $E01B
03:E020: 2C 02 20 BIT $2002 = #$00
03:E023: 10 FB BPL $E020
03:E025: A9 3F LDA #$3F
03:E027: 8D 06 20 STA $2006 = #$00
03:E02A: 8E 06 20 STX $2006 = #$00
03:E02D: A9 0F LDA #$0F
03:E02F: A2 20 LDX #$20
03:E031: 8D 07 20 STA $2007 = #$00
03:E034: CA DEX
03:E035: D0 FA BNE $E031
03:E037: 8A TXA
03:E038: A0 20 LDY #$20
03:E03A: 8C 06 20 STY $2006 = #$00
03:E03D: 8D 06 20 STA $2006 = #$00
03:E040: A0 10 LDY #$10
03:E042: 8D 07 20 STA $2007 = #$00
03:E045: E8 INX
03:E046: D0 FA BNE $E042
03:E048: 88 DEY
03:E049: D0 F7 BNE $E042
03:E04B: 8A TXA
03:E04C: 95 00 STA $00,X @ $0000 = #$F7
03:E04E: 9D 00 01 STA $0100,X @ $0100 = #$52
03:E051: 9D 00 02 STA $0200,X @ $0200 = #$B6
03:E054: 9D 00 03 STA $0300,X @ $0300 = #$B6
03:E057: 9D 00 04 STA $0400,X @ $0400 = #$4E
03:E05A: 9D 00 05 STA $0500,X @ $0500 = #$2A
03:E05D: 9D 00 06 STA $0600,X @ $0600 = #$84
03:E060: 9D 00 07 STA $0700,X @ $0700 = #$2A
03:E063: E8 INX
03:E064: D0 E6 BNE $E04C
03:E066: A9 04 LDA #$04
03:E068: 20 0E E3 JSR $E30E
03:E06B: 20 E3 E2 JSR $E2E3
03:E06E: 20 39 E3 JSR $E339
>03:E071: 20 91 9F JSR $9F91 ; crash occurs here!
03:E074: 20 FD 9E JSR $9EFD
You need to initialize banking register 6 before that line is reached. These 4 lines would do it:
Code:
lda #6
sta $8000
lda #0
sta $8001
However, it's probably a good idea to initialize all 8 MMC3 bank registers very early on in your startup code. Like I see that you've added the CHR banking initialization that I suggested but it takes place a long time after this startup routine. Might as well do all 8 in here at once. Tepples posted a suggested initial set of values to load earlier on (it's the same as FCEUX and some other emulators use, probably the same as Everdrive's initialization too).
rainwarrior wrote:
The problem this Nintendulator is the same kind of issue as with the sprites, just this time with PRG banking. You haven't initialized the bank at $8000-9FFF (banking register 6) before you use it. Apparently almost all emulators initialize this to 0, and even the PowerPak and Everdrive seem to do this too, but again this would be random on the real MMC3 cart.
You need to initialize banking register 6 before that line is reached. These 4 lines would do it:
Code:
lda #6
sta $8000
lda #0
sta $8001
However, it's probably a good idea to initialize all 8 MMC3 bank registers very early on in your startup code. Like I see that you've added the CHR banking initialization that I suggested but it takes place a long time after this startup routine. Might as well do all 8 in here at once. Tepples posted a suggested initial set of values to load earlier on (it's the same as FCEUX and some other emulators use, probably the same as Everdrive's initialization too).
Ok, it seems that now it works correctly in Nintendulator.
Yes, this technical demo contains minor errors about the scroll and the nametables.