Help with fceux again....

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Fiskbit
Site Admin
Posts: 1228
Joined: Sat Nov 18, 2017 9:15 pm

Re: Help with fceux again....

Post by Fiskbit »

I don't know why you can't reproduce any of your crashes in Mesen, because your game crashed for me in Mesen when I tried. But I keep suggesting to please enable all of the developer options in the top half of that Emulation menu. Specifically, set "Default power on state for RAM" to "Random Values" and check every option from "Randomize power-on state for mappers" to "Enable PAL black borders (when running in PAL/Dendy mode)". This will help you find problems. Some of these options are more strict than real hardware, but if your game works with the option enabled, it should work on hardware, too.

Your Mesen build is also 6 months old, so you might want to consider downloading a new build, which should have improvements. Mesen gets frequent updates, so it's worth getting new versions.
v.depatie
Posts: 304
Joined: Sun Nov 03, 2024 4:01 pm
Contact:

Re: Help with fceux again....

Post by v.depatie »

kk thx for the tip
v.depatie
Posts: 304
Joined: Sun Nov 03, 2024 4:01 pm
Contact:

Finally , for you guys, SAFE NMI's :D

Post by v.depatie »

IT did fixed alot of small glitches, I do think its crashing less. Ty all for your insight. Was not Easy to do since I have alot of separated nmi's and jumps oustide and inside back, some RTI as well. I had to restore the registers at different places for all the transitions to work perfectly.

Looks like this now:

Some restore registers are not there, there are somewhere else. Irrelevant to post here. Any how, enjoy this version , should crash much much more lesss. Actually I've just reached ten times in a row the village with fceux without crashing.


Please let me know :D again, thank you all for your insights :beer: :beer:
cart - SAFE NMI's fceux safe safe safe safe^^^^.nes
(256.02 KiB) Downloaded 18 times


Screenshot 2025-04-15 124045.png

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
NMI:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
	   ;; Backup A, X, Y registers
    PHA             ; Push A to the stack
    TXA             ; Transfer X to A
    PHA             ; Push X (now in A) to the stack
    TYA             ; Transfer Y to A
    PHA             ; Push Y (now in A) to the stack


	SwitchBank #%11000111,#11 

	LDA #$01
	STA XNMI_ACTIVE_FLAG
	
	
	;Disable sound IRQ (set the corresponding bit)
    LDA #%11000000    
    STA APU_PAD2 
			

	LDA XNMI_LEVEL
	CMP #$01
	BEQ NMI_LEVEL1
	
	LDA XNMI_LEVEL
	CMP #$02
	BNE :+
	JMP NMI_LEVEL2_RESET	
	:
	
	LDA XNMI_LEVEL
	CMP #$03
	BNE :+
	JMP NMI_VILLAGE_RESET	
	:
	
	LDA XNMI_LEVEL
	CMP #$FF
	BNE :+
	JMP NMI_OVERWORLD_RESET	
	:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
NMI_RESET_LEVEL1:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    INC frame_counter  ; Increment the frame counter
	INC sound_frame_counter     ; Increment the counter every NMI
	INC RANDOM_SEED
	INC MUSIC_COUNTER
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


	JSR DCPM_SAFETY_QUADREAD_P1	
	
	JSR CHECK_CONTROLLER_STARTUP

	
	JSR LEVEL_CHECK_NMI    ; Jump to LEVEL_CHECK_NMI subroutine,
			
	LDA XLEVEL           ; Load the value of XLVL into the accumulator
	CMP #$01               ; Compare XCHAPTER with 1
	BEQ JUMP_LEVEL1_BABY        ; If XCHAPTER == 1, branch to ISSUE_BREAK
		
	;Set up sprite DMA transfer
	 LDA #$02
     STA APU_SPR_DMA
	 
	PLA             ; Pull Y from the stack
    TAY             ; Restore Y
	PLA             ; Pull X from the stack
    TAX             ; Restore X
    PLA             ; Pull A from the stack
  
	RTI	
	
	JUMP_LEVEL1_BABY:

	JMP RESET_LEVEL1

	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
NMI_LEVEL1:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	

	
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    INC frame_counter  ; Increment the frame counter
	INC sound_frame_counter     ; Increment the counter every NMI
	INC RANDOM_SEED
	INC MUSIC_COUNTER
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


	
	LDA TEXTBOX_CLEAR_FLAG
	CMP #$01
	BNE :+
	JSR WRITE_LINE_CLEAR
	LDA #$00
	STA TEXTBOX_CLEAR_FLAG
	:

	JSR ENNEMY3_ROUTINES		; the main textbox for this guy
	
	
	
	;Set up sprite DMA transfer
	LDA #$02
    STA APU_SPR_DMA

	PHA
		JSR GRASS_N_ROCK_DOOR
	PLA

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
	
	JSR HEARTS_CHECK  ; MUST BE RUN BEFORE textbox in case p1 loose a heart while reading one.
	
	
    LDA TEXTBOX_ACTIVATED
    CMP #1
    BNE :+    ; If TEXTBOX_ACTIVATED ≠ 1, skip execution
	
	JSR LOAD_INSTRUCTION_TEXTBOX 	; the instruction textbox at the begining
	JSR LOAD_SECRET_TEXTBOX	; the secret message
	
	:



	JSR CHECK_GRAVITY_ENNEMY1
	JSR CHECK_GRAVITY_SWORD

	JSR SPRITES_SWITCHBANK_R4
		
	JSR TAKE_FEATHER_P1	;waiting to be picked up , textbox also
	JSR TAKE_SWORD_P1	
		
	
	JSR get_sprite0_attributes
	JSR UPDATE_OAM_SPRITE0
	LDX #00
	STX temp
	JSR OFFSET_BACKGROUND_HORIZONTAL   ; sprite 0 hit.

	JSR SCROLL
	
	JSR GRAVITY

	JSR CHECK_SWORD_DIRECTION

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		JSR ORDER121 ; super jump
		JSR CHECK_RANDOM_MOVE_ENNEMY1
		JSR JUMP_CHECK
		

		JSR DCPM_SAFETY_QUADREAD_P1
		JSR CONTROLLERS
		
		JSR CHECK_USE_BUTTON

		JSR MOVE_ENNEMY3
		
		

		JSR MOVE_ENNEMY2
		JSR SPRITE_ENNEMY2
		


	JSR UPDATE_DELAY_TEXTBOX           


	;metasprites for various objects	
		JSR METASPRITES


	;OAM CLEAR + SLOT SHUFFLE
		JSR OAM

	 
	 
	 
	 	   ;update for the delay between letters and phrases when reading a textbox
	 
	LDA #$00
	STA XNMI_ACTIVE_FLAG
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; Restore A, X, Y registers
    PLA             ; Pull Y from the stack
    TAY             ; Restore Y
	PLA             ; Pull X from the stack
    TAX             ; Restore X
    PLA             ; Pull A from the stack
 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RTI 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
NMI_LEVEL2_RESET:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


	LDA XLEVEL           ; Load the value of XLVL into the accumulator
	CMP #$02               ; Compare XLEVEL
	BEQ NMI_LEVEL2

	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    INC frame_counter  ; Increment the frame counter
	INC sound_frame_counter     ; Increment the counter every NMI
	INC RANDOM_SEED
	INC MUSIC_COUNTER
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	; Set Control Register PPU_MASK, the ppu mask register
	LDA     #%00001110    ; Enable background rendering (Bit 3 set)					  ; ENABLE sprite rendering (Bit 4 cleared)
	STA     PPU_MASK         ; Write to PPU Mask Register PPU_MASK					; Enable full screen (Bits 1 and 2 set)
		


	JSR DCPM_SAFETY_QUADREAD_P1	
	
	JSR CHECK_CONTROLLER_STARTUP

	JSR LEVEL_CHECK_NMI

	LDA XLEVEL           ; Load the value of XLVL into the accumulator
	CMP #$02               ; Compare XLEVEL
	BEQ JUMP_LEVEL2_BABY        ; If XCHAPTER == 1, branch to ISSUE_BREAK
		
	PLA             ; Pull Y from the stack
    TAY             ; Restore Y
	PLA             ; Pull X from the stack
    TAX             ; Restore X
    PLA             ; Pull A from the stack
  
	RTI	
	
	JUMP_LEVEL2_BABY:

	JMP RESET_LEVEL2



;;;;;;;;;;;;;;;;;;;
NMI_LEVEL2:
;;;;;;;;;;;;;;;;;

	JSR HEARTS_CHECK  ; MUST BE RUN BEFORE textbox in case p1 loose a heart while reading one.

		
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    INC frame_counter  ; Increment the frame counter
	INC sound_frame_counter     ; Increment the counter every NMI
	INC RANDOM_SEED
	INC MUSIC_COUNTER
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


	;Set up sprite DMA transfer
	
	LDA #$02
	STA APU_SPR_DMA


	 ; kill all ennemy 4 to open door

	JSR SPRITES_SWITCHBANK_R4
	
	
	JSR CHECK_VOLCANO_DOOR
	
	JSR CHECK_GRAVITY_ENNEMY1
	JSR CHECK_GRAVITY_SWORD
	JSR CHECK_USE_BUTTON
	

	PHA
		JSR get_sprite0_attributes
		JSR UPDATE_OAM_SPRITE0
	PLA		
		LDA XCHAPTER
		CMP #$07 ;level 2 cave
		BEQ :+	
		
		LDX SHADOW_8000+1 ;the bank we are currently using in the level at r0
		STX temp
		JSR OFFSET_BACKGROUND_HORIZONTAL   ; sprite 0 hit.
		:
		
		JSR SCROLL
		
			
		JSR GRAVITY
		JSR CHECK_SWORD_DIRECTION
		

		JSR ORDER121 ; super jump
	
		JSR CHECK_RANDOM_MOVE_ENNEMY1
		
		JSR JUMP_CHECK
	

	
	
		JSR DCPM_SAFETY_QUADREAD_P1
		JSR CONTROLLERS
		
		JSR ENNEMY4_ROUTINES
		JSR ROUTINE_TELEPORTER
		JSR ROUTINE_FLAMME_BOSS
		JSR CALL_MOVE_DOWN
			

		
		
		
			
		;metasprites for various objects	
		JSR METASPRITES
	
		;OAM CLEAR + SLOT SHUFFLE
		JSR OAM
	
	
	
		
	LDA #$00
	STA XNMI_ACTIVE_FLAG	
	    ; Restore A, X, Y registers
	PLA     ; Restore Y
    TAY
    PLA     ; Restore X
    TAX
    PLA     ; Restore A
	
	

;;;;;;;;;;;;;
RTI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
NMI_OVERWORLD_RESET:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


	LDA XLEVEL           ; Load the value of XLVL into the accumulator
	CMP #$FF               ; Compare XLEVEL
	BEQ NMI_OVERWORLD

	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    INC frame_counter  ; Increment the frame counter
	INC sound_frame_counter     ; Increment the counter every NMI
	INC RANDOM_SEED
	INC MUSIC_COUNTER
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	; Set Control Register PPU_MASK, the ppu mask register
	LDA     #%00001110    ; Enable background rendering (Bit 3 set)					  ; ENABLE sprite rendering (Bit 4 cleared)
	STA     PPU_MASK         ; Write to PPU Mask Register PPU_MASK					; Enable full screen (Bits 1 and 2 set)
		


	JSR DCPM_SAFETY_QUADREAD_P1	
	
	JSR CHECK_CONTROLLER_STARTUP

	JSR LEVEL_CHECK_NMI

	LDA XLEVEL           ; Load the value of XLVL into the accumulator
	CMP #$FF               ; Compare XLEVEL
	BEQ JUMP_OVERWORLD_BABY        ; If XCHAPTER == 1, branch to ISSUE_BREAK
		
	PLA     ; Restore Y
    TAY
    PLA     ; Restore X
    TAX
    PLA     ; Restore A
	
	 
	RTI	

	JUMP_OVERWORLD_BABY:

	JMP RESET_OVERWORLD
;;;;;;;;;;;;;;;;;;	
NMI_OVERWORLD:
;;;;;;;;;;;;;;;;;;;;;
	


	
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    INC frame_counter  ; Increment the frame counter
	INC sound_frame_counter     ; Increment the counter every NMI
	INC RANDOM_SEED
	INC MUSIC_COUNTER
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	JSR CALL_CHECK_TILE_INDEX ;live fetch the tile indexes around p1
	
	; Set initial scroll to 0 for the static status bar
	LDA #$00
	STA PPU_SCROLL           ; Horizontal scroll
	STA PPU_SCROLL           ; Vertical scroll
	
		

	LDA #$02
	STA APU_SPR_DMA

	JSR SPRITES_SWITCHBANK_R4
	
	JSR CHECK_USE_BUTTON_OVERWORLD


	PHA
		JSR get_sprite0_attributes
		JSR UPDATE_OAM_SPRITE0
	PLA		


	JSR DCPM_SAFETY_QUADREAD_P1
	JSR CONTROLLERS
	

	
	
	JSR METASPRITES
	
	;OAM CLEAR + SLOT SHUFFLE
	JSR OAM
	
	PLA             ; Pull Y
    TAY
    PLA             ; Pull X
    TAX
	PLA

RTI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
NMI_VILLAGE_RESET:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	

	LDA XLEVEL           ; Load the value of XLVL into the accumulator
	CMP #$03               ; Compare XLEVEL
	BEQ NMI_VILLAGE
	
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    INC frame_counter  ; Increment the frame counter
	INC sound_frame_counter     ; Increment the counter every NMI
	INC RANDOM_SEED
	INC MUSIC_COUNTER
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	; Set Control Register PPU_MASK, the ppu mask register
	LDA     #%00001110    ; Enable background rendering (Bit 3 set)					  ; ENABLE sprite rendering (Bit 4 cleared)
	STA     PPU_MASK         ; Write to PPU Mask Register PPU_MASK					; Enable full screen (Bits 1 and 2 set)
		


	JSR DCPM_SAFETY_QUADREAD_P1	
	
	JSR CHECK_CONTROLLER_STARTUP

	JSR LEVEL_CHECK_NMI

	LDA XLEVEL           ; Load the value of XLVL into the accumulator
	CMP #03               ; Compare XLEVEL
	BEQ JUMP_VILLAGE_BABY        ; If XCHAPTER == 1, branch to ISSUE_BREAK
	
	PLA             ; Pull Y
    TAY
    PLA             ; Pull X
    TAX
	PLA

  	RTI	

	JUMP_VILLAGE_BABY:

	JMP RESET_VILLAGE
;;;;;;;;;;;;;;;;;;	
NMI_VILLAGE:
;;;;;;;;;;;;;;;;;;;;;
	
	
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    INC frame_counter  ; Increment the frame counter
	INC sound_frame_counter     ; Increment the counter every NMI
	INC RANDOM_SEED
	INC MUSIC_COUNTER
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	JSR CALL_CHECK_TILE_INDEX ;live fetch the tile indexes around p1
	
	; Set initial scroll to 0 for the static status bar
	LDA #$00
	STA PPU_SCROLL           ; Horizontal scroll
	STA PPU_SCROLL           ; Vertical scroll
	
	
	

	LDA #$02
	STA APU_SPR_DMA

	JSR SPRITES_SWITCHBANK_R4
	
	JSR CHECK_USE_BUTTON_OVERWORLD

	PHA
		JSR get_sprite0_attributes
		JSR UPDATE_OAM_SPRITE0
	PLA		

	
	JSR DCPM_SAFETY_QUADREAD_P1
	JSR CONTROLLERS
	
	
	JSR routines_TOWNER
	
	JSR METASPRITES
	
	;OAM CLEAR + SLOT SHUFFLE
	JSR OAM
	PLA             ; Pull Y
    TAY
    PLA             ; Pull X
    TAX
	PLA

RTI
;;;;;;;;;;;;;;;;;;;;
IRQ:
;;;;;;;;;;;;;;;;;;;;


  ; Save registers
    PHA
    TXA
    PHA
    TYA
    PHA
	
	JSR RANDOM_GENERATOR	
	
	
	LDA XLEVEL           ; Load the value of XLVL into the accumulator
	CMP #$01               ; Compare XCHAPTER with 1
	BEQ IRQ_LEVEL1
	CMP #$02
	BEQ IRQ_LEVEL2
	CMP #$03
	BEQ IRQ_LEVEL3
	CMP #$FF
	BEQ IRQ_LEVEL3

	JMP IRQ_END
	
	IRQ_LEVEL1:
	IRQ_LEVEL2:
	IRQ_LEVEL3:
	
	
				
		
		JSR CalculatePPUAddress	
		
		JSR CHECK_BORDER_COLLISION_P1
	
		JSR COL_detector_bottom
		JSR COL_detector_top
		JSR COL_detector_left
		JSR COL_detector_right	
	INC variable_X

		

		
		
		
	IRQ_END:
    ; Handle the IRQ logic here (e.g., scroll split, sprite updates)
    lda #$80
    sta $E000          ; Acknowledge IRQ
    lda #$80
    sta $E001          ; Re-enable IRQs
    ; Restore registers
   
    PLA
    TAY
    PLA
    TAX
    PLA

 RTI
User avatar
Dwedit
Posts: 5156
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Finally , for you guys, SAFE NMI's :D

Post by Dwedit »

Code: Select all

	;Disable sound IRQ (set the corresponding bit)
    LDA #%11000000    
    STA APU_PAD2 
This should be run once at bootup, not every NMI.

Code: Select all

	LDA XNMI_LEVEL
	CMP #$01
	BEQ NMI_LEVEL1
	
	LDA XNMI_LEVEL
	CMP #$02
	BNE :+
	JMP NMI_LEVEL2_RESET	
	:
	
	LDA XNMI_LEVEL
	CMP #$03
	BNE :+
	JMP NMI_VILLAGE_RESET	
	:
	
	LDA XNMI_LEVEL
	CMP #$FF
	BNE :+
	JMP NMI_OVERWORLD_RESET	
The A register already contains XNMI_LEVEL after the first read, you don't need to reread it every time.

An indirect jump (like JMP (xxxx)) would be faster than doing many comparisons, but if an indirect jump is done improperly or done with corrupted memory, it can crash the program.

All tasks that involve the PPU (including sprite DMA and scrolling) should happen before any controller or sound code is run. PPU tasks are subject to a strict time limit, and controller and sound code is not.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Quietust
Posts: 1992
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Finally , for you guys, SAFE NMI's :D

Post by Quietust »

Dwedit wrote: Tue Apr 15, 2025 11:53 am An indirect jump (like JMP (xxxx)) would be faster than doing many comparisons, but if an indirect jump is done improperly or done with corrupted memory, it can crash the program.
If you're just blindly jumping into a pointer, things could certainly go poorly if you forget to initialize it, but if you initialize it on-demand from a table then it should be safer. There's also the option of (ab)using the stack (i.e. pushing the desired adjusted NMI address onto the stack and then performing RTS). Either way should also be faster than checking them sequentially, and since NMI time is extremely precious, you don't want to waste it by performing a linear "if level 1, elseif level 2, elseif level 3, elseif level 4, etc." (since the last level will end up getting less time).
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
v.depatie
Posts: 304
Joined: Sun Nov 03, 2024 4:01 pm
Contact:

Re: Finally , for you guys, SAFE NMI's :D

Post by v.depatie »

kk will sleep on that . ty again .

you can feel the difference in stability thou ?
v.depatie
Posts: 304
Joined: Sun Nov 03, 2024 4:01 pm
Contact:

Re: Finally , for you guys, SAFE NMI's :D

Post by v.depatie »

i like youre idea of (absuing) the stack and going straight to the desired level .

i would need to tell the stack how ? and when , like at the end of every nmi ?
Fiskbit
Site Admin
Posts: 1228
Joined: Sat Nov 18, 2017 9:15 pm

Re: Help with fceux again....

Post by Fiskbit »

We got requests to merge some of these threads together, so I've done so. I apologize for the inconvenience, but keeping very similar or same-topic discussion in fewer threads is really preferred. (For what it's worth, people said that they appreciate your enthusiasm. :) )

I'm glad the code is more stable now; it certainly looks like it should be more reliable now with the changes you've made.
v.depatie
Posts: 304
Joined: Sun Nov 03, 2024 4:01 pm
Contact:

Finally a safe NMI !

Post by v.depatie »

dont wory be happy. will probably be the last . Fceux looks safe now. The whole thing was my OMA and the way i was doing my register. Now it looks sharp.
User avatar
Dwedit
Posts: 5156
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Finally , for you guys, SAFE NMI's :D

Post by Dwedit »

v.depatie wrote: Tue Apr 15, 2025 1:49 pm i like youre idea of (absuing) the stack and going straight to the desired level .

i would need to tell the stack how ? and when , like at the end of every nmi ?
Would not recommend using stack for an indirect jump, it takes more instructions than just a single indirect jump.

Code would look something like this:

ldx index
lda jumpTableLow,X ;address stored in the jump table must have 1 subtracted to use an RTS trick
pha
lda jumpTableHigh,X
pha
rts
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Bregalad
Posts: 8147
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Finally , for you guys, SAFE NMI's :D

Post by Bregalad »

Dwedit wrote: Wed Apr 16, 2025 2:40 pm Would not recommend using stack for an indirect jump, it takes more instructions than just a single indirect jump.

Code would look something like this:

ldx index
lda jumpTableLow,X ;address stored in the jump table must have 1 subtracted to use an RTS trick
pha
lda jumpTableHigh,X
pha
rts
Not only it does take the same # of instructions, but it is shorter, and has the advantage to not require temporary memory locations as they are automatically allocated on the stack.

"Standard" solution, assuming the Temp variable is in ZP.

Code: Select all

                         ; SIZE    TIME
  ldx index              ; 2       3
  lda jumpTableLow, X    ; 3       4+
  sta Temp               ; 2       3
  lda JumpTableHigh, X   ; 3       4+
  sta Temp+1             ; 2       3
  jmp [Temp]             ; 3       5
                 ; TOTAL  15      26+
"Abusing RTS" solution

Code: Select all

                         ; SIZE    TIME
  ldx index              ; 2       3
  lda jumpTableLow, X    ; 3       4+
  pha                    ; 1       3
  lda JumpTableHigh, X   ; 3       4+
  pha                    ; 1       3
  rts                    ; 1       6
                 ; TOTAL  11      27+
The only advantage of indirect JMP is that it is 1 cycle faster if your temporary variables are in ZP, which is hardly significant IMHO.
We got requests to merge some of these threads together, so I've done so. I apologize for the inconvenience, but keeping very similar or same-topic discussion in fewer threads is really preferred. (For what it's worth, people said that they appreciate your enthusiasm. :) )
Totally agree, it's better to have the various topics about the development of "The Huns" merged, and I absolutely love the OP's enthusiasm, while mine went off along the years... :roll:
Last edited by Bregalad on Thu Apr 17, 2025 1:56 am, edited 1 time in total.
Useless, lumbering half-wits don't scare us.
User avatar
Dwedit
Posts: 5156
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Help with fceux again....

Post by Dwedit »

I was referring to an single indirect jump instruction to an address that was already calculated, not one that's being generated during NMI time.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Bregalad
Posts: 8147
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Help with fceux again....

Post by Bregalad »

Dwedit wrote: Thu Apr 17, 2025 1:52 am I was referring to an single indirect jump instruction to an address that was already calculated, not one that's being generated during NMI time.
OK, I get it, no point to fetch the pointer every frame.
You can also have three RAM slots with "$4C $xx $xx" and modify the adress directly, then JSR there. This should be even more straightforward than an in direct JMP.
Useless, lumbering half-wits don't scare us.
v.depatie
Posts: 304
Joined: Sun Nov 03, 2024 4:01 pm
Contact:

Re: Help with fceux again....

Post by v.depatie »

So instead of using straight comparison like I do at the begnining of the nmi,


I use a table containing the adresses of the needed nmi ? The way im building thing , im gunna go from nmi to nmi, depending which location in the game I am. I think I will have no choice to when I have to much nmi. I'm almost there ( 128 i believe is the distance for the way im doing it ).

Now Its hard to calculate the address. I usually use jmp. Except for the ram, its easy to know what address. But for a specific point in my nmi, eeeew.

thats gunna be hard.
User avatar
tokumaru
Posts: 12633
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Help with fceux again....

Post by tokumaru »

I don't know why you need so many different NMI handlers, most games are able to function with a unified handler.

But if you really feel like multiple NMIs is the way to go, you can just have a 16-bit variable in RAM hold the address of the current NMI handler, and then at the very beginning of the NMI you do an indirect jump to that address: jmp (NMIHandler)

You can change that address whenever you reach an area that requires a new handler (there's no need to set the address every frame if nothing is overwriting it):

Code: Select all

lda #<NMIHandler87
sta NmiHandler+0
lda #>NMIHandler87
sta NMIHandler+1
Just be careful to not let an NMI fire between updating the lower byte and the upper byte, because the address will be invalid and the program will most likely crash. You can guarantee that no NMI will fire either by disabling NMIs altogether while changing the address, or changing it shortly after an NMI fires.
Post Reply