NESmaker update

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
NESmaker update
by on (#214118)
Not sure the best place to put this - moderators feel free to move. I just wanted to provide a link to the latest NESmaker update, which shows how we handle input management, and open to custom ASM routines.

If you're interested or curious, check it out here: https://youtu.be/3NMbWhGs-ck

Especially for all of you who have been constantly in the trenches, would love to know your thoughts on if and how this might speed up rapid prototyping for you, even if you're only using it for proof of concepts and whatnot. :-)

You guys rock.
Re: NESmaer update
by on (#214124)
Thanks Joe. I didn't know you worked on Sydney Hunter.

BTW. You can edit the title of a thread by clicking on the EDIT button of the first post of that thread.
Re: NESmaker update
by on (#214127)
Hey friend - didn't work myself on Sydney Hunter at all. Just friends with the Collectorvision guys, and since they just released the SNES Sydney Hunter, and I was doing this video anyway, I asked if they would like the plug as I demonstrated our input manager. :-)
Re: NESmaker update
by on (#214243)
The amount of configurability for input looks impressive, seems like this project is headed the right way!

One thing I found curious though is that the video seems to indicate that a full byte is used for the actor direction. This seems a bit wasteful with the tiny 2kB of RAM the NES has. A common technique is to use a "flags" byte which stores the horizontal direction in the MSB, and use other bits for palette selection and background priority. Perhaps worth considering?

And then, I've also thought about the configurability of NESmaker, and as an advanced user I'd really appreciate if the NMI (and ideally also IRQ) address was configurable. i.e., a common programming pattern is to store the address of the handler in 2 bytes of zeropage RAM, and have the ROM address do an indirect jump with this address.

While you spend 2 bytes and a few cycles of RAM with this method, it allows you to easier change game state completely. So if I were to say have a very specific cut-scene which needs perfect NMI/IRQ timing, I wouldn't have to figure out how to best shoehorn my code into the NESmaker code (which may change between versions). I'd just set my own handlers, and restore them when done (together with other game state pushed on the stack).

And yes, I know I could always do this by hacking the existing NESmaker code. But having to patch the main engine is a bit of a hurdle when collaborating, so it'd be way better if this use-case was natively supported.

A tangential request to the above one would also be to have a clear deifinition of permanent vs temporary game state. For my imagined awesome-scrollery-trick cutscene, I will undoubtly need to use some RAM, and will have to consider what RAM used by NESmaker is the permanent gameplay state I must preserve, and what is data that could be restored by re-initialisation. Examples of the latter would be the spritepage, screen and attribute shadows, music data and so on. Having this clearly defined would be helpful for extending NESmaker.
Re: NESmaker update
by on (#214250)
Bananmos - thanks for the feedback!

We are still working with definable byte structures, effectively making *classes* of objects, so during the main-game cycle, during applicable parts, updates are happening for the bytes being affected for that class. For instance, an enemy projectile - type - class of object doesn't need nearly the object info that a player object does. We're working on making a class system so you might be able to determine bytes - used - by- class based on an individual particular game needs. It's a super complicated beast from a CONCEPTUALLY standpoint, let alone getting good cross talk between the tool and engine. Small things at a time. But sometimes, that's why it's harder to be more efficient with bytes, that may or may not be present. A power up may not need directionality, for instance, but might need the other bits in that byte. You can see the conundrum.

Right now, we have to do a lot of weighting ease against flexibility against conformity. Our animation engine, for instance, is super inefficient compared to what it could be, but it also is super regimented and user friendly and intuitive. So...that's a trade off. Our main demographic here are people who have zero ASM experience (and only limited coding experience), while hopefully providing enough back doors to more easily hack the engine for the needs of those who are much more confident. Essentially, we want to use this tool to take a complete newcomer through that grueling period of self doubt to give them the confidence to WANT to jettison our tool and build from scratch! :-)

Also, generally speaking, we have it broken out into GameState and subGameState, which could allow you to utilize the subGameState to still carry on common game state needs (Drawing whatever, for instance), but also allow you particulars between sub-game-states. That's how Mystic Searches handles it, so we're just sort of porting that concept over. In most things, we're using the experience we gleaned from working with COMPLETELY green folks sitting at the tool, and my years of experience teaching GameMaker and Unity to people who had never seen programming languages before, to make something that's as intuitive as it can be for NES development, even though it may not be the most efficient or best optimized way to do any one particular thing. Does that make sense?

Even still, even if current devs just use this for rapid prototyping or for the level editor or music editor or pixel editor...that's awesome. But yeah, feedback like this is awesome for sure. Any time you see something like that, feel free to point it out in case it's something we haven't thought of (but know that there was probably some trade off reason we did a thing in a particular way). You rock! :-)
Re: NESmaker update
by on (#214329)
Quote:
Does that make sense?


Well, to be honest: Not really... :P

I asked 3 questions and you only answered the least interesting one of them, while leaving the two more important ones out. OTOH, I readily admit it was a very chatty post from my side, so I'll try again and be more focused in what I'm asking about:

Question1) Would you consider optimising the object direction to occupy just 1 bit.
- You've already answered this by saying it's not much of a priority, and that your pseudo-OOP allocation of gameobject RAM might make it a special case only some objects anyway. And that's perfectly fine as micro-optimisations may not be necessary - just keep that option in mind if RAM usage does become an issue.

Question2) Could we please have the NMI in NESmaker consist of a "JMP (NMIaddr)" instruction, so that we can more easily inject our own? (and same for IRQ)

Question3) Will we have some documentation on the RAM usage of NESmaker, so we know what RAM contains crucial gameplay state and what we can trash for our own use?

Oh, and I forgot to throw in another question that I'm curious about:

Question4) Which assembler is NESmaker? Is it CA65, or some other one?
Re: NESmaker update
by on (#214338)
I can tell that there are probably some NES ASM programmers who will take NESmaker and then rewrite certain parts of the code to personalize it in their own specific way.

I could see an expert ASM coder look at the code in NESmaker and say "why did they do this" or "this is not optimized" because different coders have their own style of doing things.

For me, I don't even know how to put graphics or anything up on the screen so I would be adapting to the style of programming that NESmaker offers, but to a master ASM coder NESmaker might be harder to adapt to.
Re: NESmaker update
by on (#214339)
Question2) Could we please have the NMI in NESmaker consist of a "JMP (NMIaddr)" instruction, so that we can more easily inject our own? (and same for IRQ)
Hm - I mean...if anyone knows what they're looking at to this degree, it's not like this would be hard to customize. I'm not sure we'll set it up that way...but I guess I can look at it? There is no IRQ, using Mapper 30. Again though - if someone is to that degree of proficiency, I'm not sure this would be too difficult a problem on the code side even if we don't implement it...I wonder how many things would be truly integral, though, if someone were to write their own NMI. I guess it would depend on what you're really using to tool for. Again, that sort of goes back to our main demographic for use, being people who would never make use of this functionality.

Question3) Will we have some documentation on the RAM usage of NESmaker, so we know what RAM contains crucial gameplay state and what we can trash for our own use?
Sure, and it's relatively easy to track, too. The addresses for various things are pretty clearly lain out as constants at the top of the code (though subject to change). I'll obviously make things as documented as possible, but with all of the variability, I'll likely be more documenting conceptual things, as they may be different from genre module to genre module...advanced coders such as yourself would be able to recognize what they're looking at upon knowing where to look...drag and drop level users would have no use for this info, because they wouldn't even know what to do with it if they found it.

Question4) Which assembler is NESmaker? Is it CA65, or some other one?
ASM6

Thanks for the feedback :-)
Re: NESmaker update
by on (#214340)
JoeGtake2 wrote:
Question2) Could we please have the NMI in NESmaker consist of a "JMP (NMIaddr)" instruction, so that we can more easily inject our own? (and same for IRQ)
[...] There is no IRQ, using Mapper 30.

A raster split (ab)using the DMC is possible. See DPCM Letterbox.
Re: NESmaker update
by on (#214345)
Quote:
if someone is to that degree of proficiency, I'm not sure this would be too difficult a problem on the code side even if we don't implement it...


Yes, but as I said earlier in this thread the reasons why I'd prefer native support are:
Quote:
...I wouldn't have to figure out how to best shoehorn my code into the NESmaker code (which may change between versions).
[...]
And yes, I know I could always do this by hacking the existing NESmaker code. But having to patch the main engine is a bit of a hurdle when collaborating, so it'd be way better if this use-case was natively supported.


So if I am collaborating with someone less technical that uses NESmaker, then without a settable IRQ-address I would have to first find some free zeropage bytes (which in worst case may not even be available), and then I would either need to:
1) Ask my fellow NESmaker user to manually modify their output code according to my instructions - tedious and error-prone.
2) Write a program that tries to do the patching of the output code automatically - likely to break with NESmaker version changes.

None of those options seem very appealing TBH.

In contrast, if there was native support for a configurable NMI/IRQ address, I'd just ask the NESmaker user to INCBIN my precompiled 16kB binary in one of the PRG banks, then do a JSR $8000 to give control to my code for doing the cool screen transition/cutscene I've provided for them.
(and perhaps even adding the INCBIN/JSR $8000 wouldn't be necessary, if NESmaker would allow a feature for inserting "plugin code" like this)

Quote:
There is no IRQ, using Mapper 30


Tepples's DMC IRQ was indeed what I was having in mind. The forum thread linked to is quite long though, so I think the wiki about the DMC summarizes it better if you're short on time.

An even simpler variant of this that I've used successfully is to combine a coarse DMC IRQ which waits for a sprite#0 hit. That way you make sure the DMC will interrupt code that takes a variables amount of cycles, while still relying on the sprite#0 hit to get the finer timing needed for PPU register writes.

Both methods are obviously a lot more cumbersome than a proper scanline IRQ like the MMC3 has, but do enable screen-effects that would otherwise be very difficult to do on mapper's that have no IRQ support.

There's also other neat uses of the DMC IRQ, such as [url=Blargg's DMC saw wave]http://www.slack.net/~ant/misc/nes-saw/[/url]

Quote:
Our main demographic here are people who have zero ASM experience (and only limited coding experience), while hopefully providing enough back doors to more easily hack the engine for the needs of those who are much more confident.


Yeah, that's fair enough. But my hope was that this tool would also allow easy collaboration between people with less programming knowledge (who can use the NESmaker tool without touching the asm output) and those with more programming knowledge (who'd like to add more bells&whistles to the NESmaker-made game, but would prefer using their own tools/assembler). And having to do loads of error-prone patching to glue these things together sounds like not a lot of fun. And seems unnecessary, as it can be avoided with just a little bit of foresight... :)
Re: NESmaker update
by on (#214346)
I don't see why interrupt pointers need to be in zeropage? JMP indirect always takes a 16-bit address, so all you're doing is saving like two cycles when updating the address at the cost of precious zeropage memory.
Re: NESmaker update
by on (#214348)
Quote:
Post subject: Re: NESmaker update Reply with quote
I don't see why interrupt pointers need to be in zeropage? JMP indirect always takes a 16-bit address, so all you're doing is saving like two cycles when updating the address at the cost of precious zeropage memory.


Heh, that just shows I'm getting old and don't know my 6502 instructions as well as I used to! ;)

That means it's even less of a cost then, as you wouldn't be wasting zeropage RAM. So yeah, 2*2 = 4 bytes of RAM to make NESmaker a lot easier to extend with 16kB "plugins".
Re: NESmaker update
by on (#214356)
Forgive me for being dense on this point...I admit, I completely am not sure the benefit, still.

If there is an
Code:
.include "Routines\NMIroutines\NMIcode.asm"
, and that NMIcode.asm is exposed in the tool...what functional benefit would be gained from determining its address or making that address changeable again? If the question is about including custom NMI code...you could just put that in that code, no? I'm not sure variable NMI address makes that any easier.

Maybe I'm completely missing the use here. Sorry for being dense on this point! haha
Re: NESmaker update
by on (#214358)
If you had a game that had minigames, it might make sense to have multiple NMI routines, to handle the different PPU update needs of each mini-game.

Or perhaps if had designed a Title screen (or Ninja Gaiden style cutscene) that involved a highly optimized PPU loading system...for fast changing animations...it might have different NMI needs than the in-game one.

But, for a general purpose game maker, I wouldn't. Options will just confuse newer / less skilled users.
Re: NESmaker update
by on (#214360)
Interesting. Yeah, I can see that.

I mean, you'd lose a few NMI cycles, but you could likely do a quick table read in custom NMI code to achieve the same results, no? Rather than variable NMIs, variable places to jump within an NMI?
Re: NESmaker update
by on (#214363)
Quote:
Forgive me for being dense on this point...I admit, I completely am not sure the benefit, still.

If there is an
Code:
.include "Routines\NMIroutines\NMIcode.asm"
, and that NMIcode.asm is exposed in the tool...what functional benefit would be gained from determining its address or making that address changeable again? If the question is about including custom NMI code...you could just put that in that code, no? I'm not sure variable NMI address makes that any easier.

Maybe I'm completely missing the use here. Sorry for being dense on this point! haha


The benefits would be that the NMI address solution gives me complete freedom to define my own NMI/IRQ during a cut-scene/screen transition without messing around with your source code (which may change from version to version). And I really don't want to re-write your source code to get my code to do it's thing, or have to maintain a changing source patch set for your code generation. It's an extra hurdle to go through, and gets even worse if I have to explain a source-hacking process to one of your future users, who may not be tech-savvy at all.

Again, you seem to be coming from the viewpoint that there would be one type of user of your tool who would start out with no programming knowledge and use your tool to gain confidence, hack around and gain more programming experience by slowly extending the code produced by your tool. And that's a great use-case, as you've said.

But another use-case I would like to see is collaboration between the users who use the NESmaker tool and users who write their own asm from scratch, in the assembler of their choice. And that's why I'd like to see this process be smooth both parties. And frankly I'm a bit surprised that you don't seem to be at all keen on this?

Quote:
Interesting. Yeah, I can see that.

I mean, you'd lose a few NMI cycles, but you could likely do a quick table read in custom NMI code to achieve the same results, no? Rather than variable NMIs, variable places to jump within an NMI?


Yes, a jump table with an index could do most of the same trick to trade CPU cycles for RAM usage. Though I am curious why those 2*2 bytes of RAM are suddenly so vital not to waste, given that you previously said storing the object's direction was an unnecessary optimisation? ;)

Also, the thing I like less about the jump table idea is that combined with mapper30's limitations, it means that any "plugin" code I'd write would be more sensitive to changes in your NMI code. An NMI/IRQ that always starts with a "JMP (addr)" means I know exactly how many cycles the NMI/IRQ has already spent, and code that is sensitive to timing won't have to be re-written if you choose to re-structure your NMI code.

So yeah, if you can give us guarantees that the jump table you envision will be pretty much set in stone and not move around, but always be the first part in the code *and will take a constant number of cycles*, then it would be functionally the same as the indirect jump. But otherwise I still feel it's making extending NESmaker a lot harder than it needs to be.
Re: NESmaker update
by on (#214364)
All these are great things to keep in mind. By the way, I'm not trying to be confrontational at all - just trying to clarify and see if there are other particular reasons for the need. It's a great hope that people start bending and breaking this tool to do all sorts of things we didn't anticipate!

As for why not do it that way - well...that's just not the way it's currently set up, and using table reads is much more in line with how the tool handles most variable things of this nature. I'm not adverse to any solutions, but I think first order of business is to punch through the working beta on course, and get some feedback to see if what's there can meet these needs. So let's absolutely, 100% put a pin in that idea and see if it makes sense once people are using this in ways we didn't anticipate. :-)
Re: NESmaker update
by on (#214374)
Quote:
As for why not do it that way - well...that's just not the way it's currently set up, and using table reads is much more in line with how the tool handles most variable things of this nature


Well, of course it's not how it's currently setup. If you're only making one type of game (Mystic Searches), then an easier-integration-with-other-code-feature is not high on the priority list to get your game shipped. ;)

But when you're now making a gamemaker for 2.5k users, it suddenly makes sense to spend a bit time of yours, to make the users spend less time repeating the same hacks around your solution. Simple economies of scale. :)

Table reads could work, but would be a bit slower. And you still haven't said whether this would guarantee that the NMI/IRQ would be a fixed and constant amount of cycles between versions?

And how would this solution deal with bank-switching? Also by reading from a table that is indexed by the game-state? And you'd do the same for the IRQ?
That could work I guess... not a terrible solution by any means. Even if I'd prefer the variable address for the reasons I've mentioned. (mainly that I can always trust your code to do nothing but that indirect jump instruction, and won't have to count all the cycles your code takes to do the table lookup and indirect jump)
Re: NESmaker update
by on (#214751)
I know my comments would be discarded or unlistened, but NESMaker needs to get a communites, even from big-brain people's, helps if the software wished to recieved love and attentions. There may need to be people who should've helped out with the coding to make NESMaker bigger than we all think of, like Shiru's C coding adaptations, and DahrkDaiz's special programs that pushed Super Mario Bros. 3 hack over the limits. The idea / opportunities for NESMaker is really big to be made just by small people.