08-08-2026, 06:35 AM
great, even my mistakes help
|
Xenon 2 Megablast Port
|
|
08-08-2026, 06:35 AM
great, even my mistakes help
08-08-2026, 07:45 AM
some roms by mic_ to measure cpu fetch and data bus: http://jiggawatt.org/badc0de/console.htm#ngp
08-08-2026, 08:13 AM
I'll admit to struggling with dealing with Claude, I don't know how you have the patience, but hats off to you
08-08-2026, 08:32 AM
Well, where there's a will, there's a way. And I have to be honest, I kept starting over on so many platforms with small implementations, whether it was Gamebuino, MakeCode Arcade, or Arduino, I always lost motivation pretty quickly since my programming skills are really poor. Then last year I gave it a shot with GPT, but I never got much further than a flying ship, since GPT was pretty rough back then.
Then I built a Dreamcast collection manager for SegaCity.de to manage PAL games, and that went so well that I decided to take another shot at porting Xenon to my favorite handheld, or at least attempting it. I never would have thought I'd get this far, but you learn how to work with an AI that's sometimes pretty dumb, and thanks to your help, you also manage to solve the last remaining problems. Though without Tixul's MCP I probably would've lost it two weeks ago already and threatened to delete Claude and replace it with GPT. Which wouldn't have made things any better anyway, if you threaten one AI with another, it just hallucinates even more trying to deliver an answer no matter what.
@Ahchay & @Napomex
my sprite multiplexing test: https://drive.google.com/file/d/10-HhxP6...sp=sharing (based on one on my sample, it's just a test...) It works on vdmgr & ngpcraft emu & real hw 128 sprites: 64 on each half of the screen, the switch is controlled by hbl sprites def are stored in ram and then sent to sprites bus during vbl for top sprites and hbl for lower sprites [using ldirw (sprites def) and ldir (sprites color)]
08-10-2026, 06:41 AM
Resetting during the vbl is a good call.
I've been struggling to think of uses for this, but vertical scrollers where the ship is always gong to be in the bottom half of the screen is a good example. That's at least four sprites freed up - in the case of xenon2, probably many more
@Napomex, some other idea for small optimizations (to test): https://drive.google.com/file/d/1DcLjQvw...drive_link
mostly function parameter formats to 16bit, inlining either by macro (RECTS_OVERLAP_CACHED) or use of "__inlne" directive for iabs16 + update august 13: some __asm("ldir") added (terr_sec_step & oam_pool_alloc_run)
09-20-2026, 10:21 PM
Claude's reply: I read through it, but I only understand 50% of it.
Thanks anyway for the great support. The hardware confirmation is the real news here — thanks for that. I ran your first demo through the emulator and read the OAM alongside it; the fact that it now holds up on real hardware and on the vdmgr as well turns it from a stunt into a technique. On the multiplexing itself for us it fails on RAM, and only just. I worked the numbers so it doesn't stay a guess. Our free RAM gap (from the .map, not estimated) is 401 bytes; the stack needs 162 of those on the deepest path we've measured, leaving about 190. A full OAM mirror in RAM costs 256 bytes of sprite definitions plus 64 bytes of colour = 320 bytes. Your demo holds two of them, so 640. So we can't fit even one set, never mind two. That's not an objection to your method, that's our project: we've been at the RAM ceiling for weeks, and the last 198 bytes we gained came purely from letting the shop state and the level state share a union. The only memory we'd have left is the sound RAM shared with the Z80 — and that runs straight into something we've already measured. In mic_'s NGP_BUS, for the case where the TLCS is working on the shared RAM, the Z80 shows a throughput figure of 002 against 0FC — it's effectively starved. Our music driver lives there. Two 320-byte block copies per frame through exactly that RAM would tear the music apart; we already mute it across level setup because the bus is hammering there. For us that makes this a technique for static screens (our shop: dealer on top, item grid below, nothing crossing the split) and not for the scrolling level. Two questions I'd genuinely like answered: 1. The one from last time is still open: have you ever measured the block copy against the ordinary path? Not "128 sprites vs 64", but "a full ldirw run vs individual sprite writes" at a realistic 40-60 moving objects. Today we only write the sprites that actually changed — in a quiet frame, very few. Your way pays the bus for all 128, including the 100 that are standing still. The two curves cross somewhere, and I don't know where. 2. Does the second set have to be a complete 64-entry mirror? Or could the HBL handler write back only the entries that differ between the upper and lower half? That would cut both RAM and bus traffic down to what actually changes — and that would fit our situation. On the optimisations — we've already measured three of them. Short version. HW_BENCH pair, same scene, same session, real hardware: ROM VBlanks per 30 frames without the changes 117 with u16 params + __inline + macro 118 One VBlank slower, not faster. We kept it anyway: behaviour is identical over 4000 frames, and the ROM got 146 bytes smaller. Today iabs16 is __inline here and rects_overlap_cached takes u16 — only the macro is switched off (ROC_FCT 0). The reason for that is also why I think your new suggestion is the best of the four. NGP_IQ shows a prefetch queue of length 4 on hardware; our emulator core models none at all. Our working thesis since then: on this silicon, instruction fetch dominates so heavily that compact code wins — which is why the inlining lost despite saving work. It makes the code longer. ldir/ldirw is the only one of your suggestions that goes with that grain instead of against it: one instruction is fetched once, and after that it's pure bus, with no fetch cost per iteration. It ought to win, for exactly the reason the other one lost. On your two spots, after looking at them: - terr_sec_step — there's a loop there that pushes 8 words from ROM into tile memory, for every changed tile, roughly 6 per frame. That's the textbook case for ldirw, and I'm happy to measure it. Honest upper bound: the whole "reloading" block costs us 22 out of 796 scanlines per frame (2.8%), there's no more in there than that. It is at least one of the few blocks where emulator and hardware agree to a factor of 1.00. - oam_pool_alloc_run — here I'm sceptical, and that's after reading the code, not on principle. The expensive part is two nested searches over the free list; the only thing that can be moved as a block is closing the list up by one slot, at most 54 bytes, and the function is only called when spawning metasprites. Our laser beam deliberately doesn't use it — the requirement for contiguous slots used to cost us the beam entirely in 12% of frames. I'll measure it along with the rest, but I expect zero. One thing I don't know and you might: is a long ldirw interruptible? We build our HUD bar with a raster split driven by two MicroDMA channels, and its table is built in the VBlank handler. If a block copy during VBlank can shift the split, that's a visible bug for us, not a measurement question. |
|
« Next Oldest | Next Newest »
|