NES C programming

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Doogie wrote:How do I tell the NES (In asm) to store a value at an address that is held in a variable
The registers on the NES are all 8-bit, so they can't represent absolute addresses (and the CPU doesn't combine them in any way to form a 16-bit value), so the only way to do this is using indirect indexed addressing.

To do this, the address in question must be stored in a zero page location (not in a register, like in your example). Unfortunately, the 6502 will always add the Y register to this address, so if you don't plan on using indexes, you have to set it to 0.

Code: Select all

	;set the destination address
	lda #$3F
	sta $00
	lda #$04
	sta $01
	ldy #$00

	;write the value
	lda #$55
	sta ($00), y
The code above will store value $55 in memory location $043F. Alternatively, you can keep the low byte of the pointer as zero and have Y hold the lower byte of the address. The following code will do the same as the above:

Code: Select all

	;set the destination address
	lda #$00
	sta $00
	lda #$04
	sta $01
	ldy #$3F

	;write the value
	lda #$55
	sta ($00), y
Doogie
Posts: 22
Joined: Mon Oct 26, 2009 4:21 am

Post by Doogie »

Thank you very much, I literally just found out then you have to bracket it for pointers, but you probably saved me a lot of debugging with your in-depth description.

Thank you very much :)

EDIT:

Variable Label:

Code: Select all

_sTemp:
	.res	2,$00
ASM Snippet:

Code: Select all

	ldy     #$00
	lda     #$01
	sta     (_sTemp)
	lda     #$00
	sta     (_sTemp)
Any reason why its throwing errors here for the compiler?

(I tried with the ',y' and it throws RANGE ERRORS. With the code above I get an ILLEGAL ADDRESS MODE)
User avatar
Memblers
Site Admin
Posts: 3902
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers »

_sTemp needs to be in zeropage, if not that would cause the range error. And all indirect addressing modes have to be indexed with the Y register.
Doogie
Posts: 22
Joined: Mon Oct 26, 2009 4:21 am

Post by Doogie »

Memblers wrote:_sTemp needs to be in zeropage, if not that would cause the range error. And all indirect addressing modes have to be indexed with the Y register.
Yeah, figured that out before hand, and same with the indirect addressing procedure.

I just need to fix up the zeropage handling so I can actually use it now as the register handling doesn't work for the C compiler.
Doogie
Posts: 22
Joined: Mon Oct 26, 2009 4:21 am

Post by Doogie »

Alright!

I've successfully worked out how to use the zeropage for pointers and such, this is fantastic, thanks heaps for all your help :D

The current joystick code:

Code: Select all

unsigned char NES_ProcessInput_real(unsigned short joypad)
{
	sTemp = joypad;

	// Get Lowbyte
	asm("lda %v",sTemp);
	asm("sta %v",cTemp);

	// Get Highbyte
	asm("lda %v+1",sTemp);
	asm("sta %v",cTemp2);

	// Load the Address of STemp (joypad) into the pointer
	asm("lda %v",cTemp);
	asm("sta regbank");
	asm("lda %v",cTemp2);
	asm("sta regbank+1");

	// Reset Y Register for indirect memory addressing.
	asm("ldy #$00");

	// Reset Strobes for address.

	asm("lda #$01");
	asm("sta (regbank), y");
	asm("lda #$00");
	asm("sta (regbank), y");

	// Read Keys

	// Read A
	asm("lda (regbank), y");
	asm("and #1");
	asm("sta %v",cTemp);
	return cTemp;
}
A Hybrid C/Asm function that uses a mere 24 lines in asm. I just need to work out on how to store all the key bits in one byte.

When outputted to Asm:

Code: Select all

.segment	"CODE"

.proc	_NES_ProcessInput_real: near

.segment	"CODE"

	ldy     #$01
	jsr     ldaxysp
	sta     _sTemp
	stx     _sTemp+1
	lda     _sTemp
	sta     _cTemp
	lda     _sTemp+1
	sta     _cTemp2
	lda     _cTemp
	sta     regbank
	lda     _cTemp2
	sta     regbank+1
	ldy     #$00
	lda     #$01
	sta     (regbank),y
	lda     #$00
	sta     (regbank),y
	lda     (regbank),y
	and     #1
	sta     _cTemp
	ldx     #$00
	lda     _cTemp
	jmp     L0021
L0021:	jsr     incsp2
	rts

.endproc
Doogie
Posts: 22
Joined: Mon Oct 26, 2009 4:21 am

Post by Doogie »

Alright guys, I need a bit of help accessing the DMA. In C, Im not exactly sure on how to store the location of the byte data. (X,Y positions, attributes and tile number). Since this uses a linker, I can't really specify a specific address with .org or else other bits of the program might stuff up.

Also with the ".segment CHARS", does this mean that when I DMA the sprite data, it will automatically know to use the data in the CHR Page?

UPDATE: Found out that my palette's weren't loading properly, now fixed. Im currently working out how to store the DMA data as effectively and effeciently as possible ;)
Doogie
Posts: 22
Joined: Mon Oct 26, 2009 4:21 am

Post by Doogie »

Hello again guys, I've googled a bit but I can't seem to find any documentation on the NES Character format (.chr). I need to see some documentation so I can display CHR files in my Win32 application.
User avatar
thefox
Posts: 3139
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Post by thefox »

Doogie wrote:Hello again guys, I've googled a bit but I can't seem to find any documentation on the NES Character format (.chr). I need to see some documentation so I can display CHR files in my Win32 application.
16 bytes per tile. The first 8 bytes contain the first bit and the next 8 bytes contain the second bit (tiles are 2bpp). The first byte contains data for the first line of pixels in the tile and so on.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
Doogie
Posts: 22
Joined: Mon Oct 26, 2009 4:21 am

Post by Doogie »

Alright, so let me get this straight.

~ 16 bytes per Tile
~ The tile is cut in half vertically (or is it horizontally), LEFT side is byte 1, and right side is byte 2, to represent ONE straight line.

Byte 1 - First four pixels from the left
Byte 2 - First four pixels from the right.
User avatar
thefox
Posts: 3139
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Post by thefox »

Nope:

Byte 1 - First 8 pixel row, bit #0
Byte 2 - Second 8 pixel row, bit #0
...
Byte 8 - Last (8th) 8 pixel row, bit #0
Byte 9 - First 8 pixel row, bit #1
Byte 10 - Second 8 pixel row, bit #1
...
Byte 16 - Last (8th) 8 pixel row, bit #1

Each pixel is two bits.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
Doogie
Posts: 22
Joined: Mon Oct 26, 2009 4:21 am

Post by Doogie »

Ok so its more like.

psuedo-code:

Code: Select all

// ReadPixel(), read the bits of both byte1 and byte2 and merge them together to get the color (0-3)

colorvalue[1] = ReadPixel(byte1,byte2,0) // 0 is the bit (0-7)
colorvalue[2] = ReadPixel(byte1,byte2,1) // 0 is the bit (0-7)
...etc...
colorvalue[8] = ReadPixel(byte1,byte2,7) // 0 is the bit (0-7)
So the color value array 1-8 would be the first line.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

There's a test case for your pattern table reading code on the wiki:
http://wiki.nesdev.com/w/index.php/PPU_pattern_tables
Doogie
Posts: 22
Joined: Mon Oct 26, 2009 4:21 am

Post by Doogie »

Thanks for your help guys, My CHR-Loader works perfectly :)

Unfortunately with the application I use (GameMaker) load times are about 4-5 seconds, but once its done, it runs fine as I save the image on screen as a sprite. :D

Image
You may notice that the palette used is simply the first four in the SMB1 palette.
Post Reply