Custom Macro: DebugPrint for observing values.

jorotroid

Member
Hey. If you're anything like me, then you too have also not quite figured out how to make use of FCEUX's debugger, but sometimes you just want to know what the value of something was at a given moment. Just put this code either in the Marco.asm file or create your own file of macros and include it. Then set up a hud element that displays a number with a max value of 8. When you want a value printed to the screen just call DebugPrint -name of value- and it will print the value to the hud element in binary. I went with binary because it seem easier to implement and most of what I want to know is whether or not my ANDs, ORs, or CMPs are getting the values I'm expecting. Just be careful when you call it so you don't interrupt the same process you are trying to observe. I am relative inexperienced with this assembly stuff, so I welcome anyone who has an idea on how to do this more efficiently, or why this might be a bad idea in general. Before you finish your game, you'll want probably to remove this code. (Edited post with much leaner code)

UPDATE: If this is relevant to you, check out Kasumi's posts. Kasumi provided both an alternative to observing values in FCEUX, and wrote a much more impressive version of the macro.

Code:
;;;;; Note: Somewhere else define a DebugPrintMask variable. Don't put it in the UserVariables.asm file! 
;;;;; That file gets rewritten every time you export, so it will erase that variable. For me, I just created
;;;;; a MyVariables.asm file and included it after the UserVariables.asm include at the end of ZP_and_vars.asm.

MACRO DebugPrint arg0
	PHA			; Save A and X on the stack
	TXA
	PHA	

	LDX #$0			; initialize x for iteration
	LDA #%00000001		
	STA DebugPrintMask	; set up mask for comparison
	
DebugPrintLoop:
	LDA arg0
	AND DebugPrintMask
	BNE DebugPrintSet	; break if bit at x is 1
	LDA #$0			; otherwise, were going to get ready to set digit x to 0
	JMP DebugPrintNext
	
DebugPrintSet:
	LDA #$1			; getting ready to set digit x to 1
	
DebugPrintNext:	
	STA Debug_0,X		; setting digit x
	INX
	CPX #$08
	BEQ DebugPrintEnd	; branch if we've gone through the whole
	ASL DebugPrintMask	; shift the mask for next digit to test
	JMP DebugPrintLoop	; loop
	
DebugPrintEnd:
	LDA DrawHudBytes	; Refresh hud
    	ORA #HUD_Debug_0
    	STA DrawHudBytes
	

	PLA 			; Restore original A and X values
	TAX
	PLA
	ENDM




FIwBOxU.png


You don't have to name the variable Debug_0 like I did, just make sure that the name matches in the User Variables and in the code.

Lastly, here is an example screenshot. I have it DebugPrint gamepad in any of the scripts I have where you press a button. In this image, I am jumping and moving to the right, and the DebugPrint is showing that the bits for the Right and A buttons are set to 1.
t7S4g4r.png

I guess that image is a pseudo update on my game, but this past week has ended up being more about learning NESMaker and 6502 assembly than making show-able progress.
 

jorotroid

Member
Ok. So I ran into an issue, but it's ok. So as I understand these macros, they are essentially copying and pasting snippets of code to where ever you call them. This can wreak havock because JMP and Branching Opcodes have a 127 address limit on how far they can jump in either direction. In other words, using a macro can increase the distance from where you make a JMP or Break to the desired location and thus previously working code will no longer compile. In some instances this isn't an issues, but it can be very easy to come up against this problem. There is probably no perfect solution, but I did make an effort to make the macro more lean. In the interest of those who might be interested in learning, I am going to put my original code in this post and edit replace the code in the original post for ease of access.


Code:
MACRO DebugPrint arg0
	
	;; Resetting all the digits.
	LDA #$0
	STA Debug_0
	STA Debug_0+1
	STA Debug_0+2
	STA Debug_0+3
	STA Debug_0+4
	STA Debug_0+5
	STA Debug_0+6
	STA Debug_0+7
	
	LDA arg0
	AND #%00000001		;;; Check if first bit is 1 or 0
	STA Debug_0			;;; Set right-most digit
	
	;; Set next bit
	LDA arg0
	AND #%00000010		;;; Check if second bit is 1 or 0
	LSR A				;;; Bit shift to the right to move result to 1's position
	STA Debug_0+1
	
	LDA arg0
	AND #%00000100
	LSR A
	LSR A
	STA Debug_0+2
	
	LDA arg0
	AND #%00001000
	LSR A
	LSR A
	LSR A
	STA Debug_0+3
	
	LDA arg0
	AND #%00010000
	LSR A
	LSR A
	LSR A
	LSR A
	STA Debug_0+4
	
	LDA arg0
	AND #%00100000
	LSR A
	LSR A
	LSR A
	LSR A
	LSR A
	STA Debug_0+5
	
	LDA arg0
	AND #%01000000
	LSR A
	LSR A
	LSR A
	LSR A
	LSR A
	LSR A
	STA Debug_0+6
	
	LDA arg0
	AND #%10000000
	LSR A
	LSR A
	LSR A
	LSR A
	LSR A
	LSR A
	LSR A
	STA Debug_0+7
	
	;;; Refresh the Hud Element
	LDA DrawHudBytes
    	ORA #HUD_Debug_0
    	STA DrawHudBytes
	
	ENDM
 

Kasumi

New member
FCEUX has Lua support, so you can display values in RAM without changing the code in your game itself.
DVz62Re.gif

Code:
SCRIPT_TITLE	= "Debug"
SCRIPT_VERSION	= "N/A"

while(true) do
 	FCEU.frameadvance()

		
	textbuffer = string.format("uVals: %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
		memory.readbyte(0xF4),
		memory.readbyte(0xF5),
		memory.readbyte(0xF6),
		memory.readbyte(0xF7),
		memory.readbyte(0xF8),
		memory.readbyte(0xF9),
		memory.readbyte(0xFA),
		memory.readbyte(0xFB),
		memory.readbyte(0xFC),
		memory.readbyte(0xFD),
		memory.readbyte(0xFE),
		memory.readbyte(0xFf)
	)
	
	gui.text(0,24, textbuffer)
end
That will display the RAM at $F4-$FF. (In FCEUX Lua scripting, 0x designates hexadecimal, the way that $ designates hexadecimal in 6502.)

If you use this as a generic solution, you do still have to change your code slightly. You store the value you want to debug to any of those $FX addresses. For instance:
Code:
LDA TheRamYouWantDisplayed
STA $F4
But you could read them directly from the script without changing your code. (Requires some legwork, though, so I'll skip writing about that for now.)
To use a Lua script in FCEUX, File, Lua, New Script Window, Browse (select the file), Run.

Edit: Not that this makes what you're doing bad. It can allow you to see values on real hardware, which FCEUX Lua can't. I'll make another post with a leaner assembly langauge version, though. You can make it way smaller (less likely to mess up branches, but also slower) with loops.
 

Kasumi

New member
This should get an equivalent result. Let me know if you have any questions!
Code:
MACRO DebugPrint arg0
	pha;keep the current value in A, and X safely on the stack
	txa;
	pha
	
	lda #%10000000;This will be the last position to be written to
	sta Debug_0;So we can safely store which bit we're displaying here.
	;It will be overwritten right at the end
	
	;Note that I will start at #%10000000 and Debug_0+7 instead of #%00000001 and Debug_0.
	;This makes the loop slightly faster.
	
	ldx #7;When you do lda Debug_0,x you'll read from the variable that is X places away from Debug_0.
	;So if X is 7, lda Debug_0,x will read the same value as Debug_0+7.

loop:
	lda arg0
	and Debug_0
	beq store;If the bit was not set, zero is in the accumulator. So this branch will just store zero
	lda #1;If the bit was set, we always want one, no need to do any shifting
store:
	lsr Debug_0;Shift the bit we're working with. This will make the AND intruction use the correct bit next time this loops
	sta Debug_0,x
	dex
	bpl loop;If X is greater than 0 (signed) loop again.
	
	;;; Refresh the Hud Element
	LDA DrawHudBytes
    ORA #HUD_Debug_0
    STA DrawHudBytes
	
	pla;Get the value of X and A before we started back in X and A.
	tax
	pla
	
	ENDM
 

jorotroid

Member
Thanks Kasumi! Your more efficient implementation works like a charm.

Also thank for telling me about the Lua scripting in FCEUX. I'll definitely use it at some point. Though one think I like about having a macro instead is that I don't have to figure go into the demo.txt to find the the address of the value I want to observe.
 

chronosv2

New member
That debug code is excellent! Thanks for sharing!
I'm using it to do a little engine dissection so I can make more interesting things in code. :D
 
Top Bottom