The Background Saga

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

Moderator: Moderators

Post Reply
User avatar
nathanpc
Posts: 35
Joined: Fri Mar 12, 2010 4:55 pm
Location: Brazil
Contact:

The Background Saga

Post by nathanpc »

Hello,
I was the entire day on the IRC with people helping me to improve my code(adding DMA, NMI..., special thanks for jero32 and jsr), but now I want to have a background(thing that is very important to a game), then I've got a code like this:

Code: Select all

	.inesprg 1   ; 1 bank of code
	.ineschr 1   ; 1 bank of spr/bkg data
	.inesmir 1   ; something always 1
	.inesmap 0   ; we use mapper 0

	.bank 0   ; bank 0 - our place for code.
	.org $0000
Sprite1_X   .db 50       ; a X position for our sprite, start at 20
Sprite1_Y   .db 20       ; a Y position for our sprite, start at 20
Sprite2_X   .db 50       ; a X position for our sprite, start at 20
Sprite2_Y   .db 20       ; a Y position for our sprite, start at 20
	.org $8000  ; code starts at $8000
	
Start:  
	lda #%10001000  ; do the setup of PPU
	sta $2000       ; that we

	ldx #$00    ; clear X

	lda #$3F    ; have $2006 tell
	sta $2006   ; $2007 to start
	lda #$00    ; at $3F00 (pallete).
	sta $2006

loadpal:                ; this is a freaky loop
	lda tilepal, x  ; that gives 32 numbers
	sta $2007       ; to $2007, ending when
	inx             ; X is 32, meaning we
	cpx #32         ; are done.
	bne loadpal     ; if X isn't =32, goto "loadpal:" line.

	lda #$20
	sta $2006 ; give $2006 both parts of address $2020.
	sta $2006 
	ldx #$00

	loadNames:
	lda ourMap, X ; load A with a byte from address (ourMap + X)
	inx
	sta $2007
	cpx #64 ; map in previous section 64 bytes long
	bne loadNames ; if not all 64 done, loop and do some more

waitblank1:         
	lda $2002  ; these 3 lines wait for VBlank, this loop will actually miss VBlank
	bpl waitblank1 ; alot, in a later Day, I'll give a better way
	txa 
clrmem: 
	sta $000,x 
	sta $100,x 
	sta $200,x 
	sta $300,x 
	sta $400,x 
	sta $500,x 
	sta $600,x 
	sta $700,x  ; Remove this if you're storing reset-persistent data 
	inx 
	bne clrmem
	
waitblank2:         
	lda $2002  ; these 3 lines wait for VBlank, this loop will actually miss VBlank
	bpl waitblank2 ; alot, in a later Day, I'll give a better way
	lda #%00011110
	sta $2001
	
loop:
	jmp loop
	
infinite:  ; a label to start our infinite loop
nmi:

	; Load Sprite1
	lda Sprite1_Y
	sta $0300
	lda #$11
	sta $0301
	lda #$00
	sta $0302
	lda Sprite1_X
	sta $0303
	
	; Load Sprite2
	lda Sprite2_Y
	sta $0304
	lda #$12
	sta $0305
	lda #$00
	sta $0306
	lda Sprite2_X
	sta $0307
	
	lda #$01   ; these
	sta $4016  ; lines
	lda #$00   ; setup/strobe the 
	sta $4016  ; keypad.

	lda $4016  ; load Abutton Status ; note that whatever we ain't interested
	lda $4016  ; load Bbutton Status ; in we just load so it'll go to the next one.
	lda $4016  ; load Select button status
	lda $4016  ; load Start button status
	lda $4016  ; load UP button status
	and #1     ; AND status with #1
	bne UPKEYdown  ; for some reason (not gonna reveal yet), need to use NotEquals
	;with ANDs. So it'll jump (branch) if key was down.
	
	lda $4016  ; load DOWN button status
	and #1     ; AND status with #1
	bne DOWNKEYdown

	lda $4016  ; load LEFT button status
	and #1     ; AND status with #1
	bne LEFTKEYdown

	lda $4016  ; load RIGHT button status
	and #1     ; AND status with #1
	bne RIGHTKEYdown
	jmp NOTHINGdown  ; if nothing was down, we just jump (no check for conditions)
	; down past the rest of everything.

UPKEYdown:
	lda Sprite1_Y ; load A with Y position
	sbc #1  ; subtract 1 from A. Only can do math on A register. SBC (Subtract with Borrow)
	sta Sprite1_Y ; store back to memory
	lda Sprite2_Y ; load A with Y position
	sbc #1  ; subtract 1 from A. Only can do math on A register. SBC (Subtract with Borrow)
	sta Sprite2_Y ; store back to memory
	jmp NOTHINGdown  ; jump over the rest of the handling code.

DOWNKEYdown:
	lda Sprite1_Y 
	adc #1  ; add 1 to A. ADC (Add with Carry)((to A register))
	sta Sprite1_Y
	jmp NOTHINGdown ; jump over the rest of handling code.

LEFTKEYdown:
	lda Sprite1_X
	sbc #1  
	sta Sprite1_X
	jmp NOTHINGdown 
;the left and right handling code does the same as UP and Down except.. well.. with
; left and right. :)

RIGHTKEYdown:
	lda Sprite1_X
	adc #1
	sta Sprite1_X
	; don't need to jump to NOTHINGdown, it's right below. Saved several bytes of
	; PRG-Bank space! :)
	
NOTHINGdown:
	lda #$03
	sta $4014
	rti

tilepal:
	.incbin "our.pal" ; include and label our pallete
	
ourMap:
	.incbin "our.map" ; assuming our.map is the binary map file.
	.bank 1   ; following goes in bank 1
	.org $FFFA  ; start at $FFFA
	.dw nmi    ; dw stands for Define Word and we give 0 as address for NMI routine
	.dw Start ; give address of start of our code for execution on reset of NES.
	.dw 0   ; give 0 for address of VBlank interrupt handler, we tell PPU not to
	; make an interrupt for VBlank.
	
	.bank 2   ; switch to bank 2
	.org $0000  ; start at $0000
	.incbin "our.bkg"  ; empty background first
	.incbin "our.spr"  ; our sprite pic data
And here are all the files used: But when I emulate this I got a monochome background(because I don't have a pallete for it):
Image

Then I want to know some simple things:
  • What is the simplest way to define a pallete for the background?
  • How can I arrange the background to have a smile(of 4 tiles) that isn't tiled(repeated line by line)?
Best Regards,
Nathan Paulino Campos
MIPS, x86 and ARM Assembly Developer

Learning 6502 ;)
Denine
Posts: 397
Joined: Wed Feb 17, 2010 5:42 pm

Post by Denine »

You're missing "ourMap.map" attached,but it's fine.(I used my own map)
What is the simplest way to define a pallete for the background?
If I understand you correctly,You need to load Atribute table.You have to load it after map into 2007.If I'm not wrong then Atribute table should be 40 bytes long.
1 Byte is numer of palete used for 2x2 square.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

The attribute table is 64 bytes long ($40 is 64 in hex, so that could be why you said 40 - in the future, please be careful to indicate the base of the values). Each byte covers a 32x32-pixel area, and each 2 bits inside that byte selects palettes %00 (0) through %11 (3) for each 16x16-pixel area.

If you want the whole background to use the same palette it's easy, but if you want to configure each 16x16 block individually it's better to use a specific software, such as this, because doing it by hand can be very tedious.
Denine
Posts: 397
Joined: Wed Feb 17, 2010 5:42 pm

Post by Denine »

tokumaru wrote:The attribute table is 64 bytes long ($40 is 64 in hex, so that could be why you said 40 - in the future, please be careful to indicate the base of the values).
Ok..,forgot to say it's in HEX :oops:
Hmm,nathanpc,in order to use Name.exe you need to create batch file.
You need to specify 3 thing:
-chr file
-Palete file
-And map file.
Example:

Code: Select all

name our.chr our.pal our.map
Note that "neme" must be first.
("our.chr" is name for background,so in your case it's should be"our.bkg")
User avatar
nathanpc
Posts: 35
Joined: Fri Mar 12, 2010 4:55 pm
Location: Brazil
Contact:

Post by nathanpc »

I've done all correct, used name with my map file(chr one) and the pallete file(bkg.pal).

Now when I emulate, I got all organized(as I've done in name, but it's still monochrome(background only).

Remember that I haven't changed anything on the code, just compiled it with the new files
MIPS, x86 and ARM Assembly Developer

Learning 6502 ;)
Denine
Posts: 397
Joined: Wed Feb 17, 2010 5:42 pm

Post by Denine »

Um,if you really dodn't changed a thing,then you still didn't loaded Atribute table.You need to load more than 64 bytes from map file.Also first palette for backgorund is in monochrome,that's why.
And if that won't work then please upload your map file.
User avatar
nathanpc
Posts: 35
Joined: Fri Mar 12, 2010 4:55 pm
Location: Brazil
Contact:

Post by nathanpc »

I can't understand what you're saying, but here are the files: Best Regards.
MIPS, x86 and ARM Assembly Developer

Learning 6502 ;)
Denine
Posts: 397
Joined: Wed Feb 17, 2010 5:42 pm

Post by Denine »

My english is really soo poor? :(
Uh...anyway...It's just like I said,you didn't loaded whole file.When you're creating a map file with "name.exe",then map file will have 3C0 bytes to load(HEX)as actual name table.The rest(40 bytes in HEX) is atributes.
You need to delete this

Code: Select all

   loadNames:
   lda ourMap, X ; load A with a byte from address (ourMap + X)
   inx
   sta $2007
   cpx #64 ; map in previous section 64 bytes long
   bne loadNames ; if not all 64 done, loop and do some more 
And insert This instead:

Code: Select all

Map_Load:
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA #$20
  STA $2006             ; write the high byte of $2000 address
  LDA #$00
  STA $2006             ; write the low byte of $2000 address
  lda #low(ourMap)
  sta addrLO
  Lda #high(ourMap)              ; start out at 0
  sta addrHI

  ldx #4
  ldy #0

Map_Load_loop:
  LDA [addrLO], y     ; load data from address (background + the value in x)
  STA $2007             ; write to PPU
  INy                   ; X = X + 1
  BNE Map_Load_loop  ; Branch to LoadBackgroundLoop if compare was Not Equal to zero
  inc addrHI
  dex
  bne Map_Load_loop
Don't forget to make make variable's for indirect addressing:
addrLO and addrHI.
User avatar
nathanpc
Posts: 35
Joined: Fri Mar 12, 2010 4:55 pm
Location: Brazil
Contact:

Post by nathanpc »

Ok, but what will be the addrLO and addrHI .db values?
MIPS, x86 and ARM Assembly Developer

Learning 6502 ;)
Denine
Posts: 397
Joined: Wed Feb 17, 2010 5:42 pm

Post by Denine »

Umm,Values is automatically appended to these variables.
you don't have to do anything manually.
User avatar
nathanpc
Posts: 35
Joined: Fri Mar 12, 2010 4:55 pm
Location: Brazil
Contact:

Post by nathanpc »

Hmm, but I still got this:

Code: Select all

NES Assembler (v2.0)

#[1]   OUR.ASM
   44  00:8035                    sta addrLO
       Undefined symbol in operand field!
   46  00:803A                    sta addrHI
       Undefined symbol in operand field!
   52  00:8041                    LDA [addrLO], y     ; load data from address (
background + the value in x)
       Undefined symbol in operand field!
   56  00:8049                    inc addrHI
       Undefined symbol in operand field!
# 4 ERROR(s)
MIPS, x86 and ARM Assembly Developer

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

Post by tokumaru »

Did you declare these variables? The assembler won't know what "addrLO" and "addrHI" mean unless you tell it. You can put in the beginning of your file something like this:

Code: Select all

addrLO = $10
addrHI = $11
Make sure to not use addresses that are already in use by other variables.
User avatar
nathanpc
Posts: 35
Joined: Fri Mar 12, 2010 4:55 pm
Location: Brazil
Contact:

Post by nathanpc »

Muito obrigado amigo. ;)
E é muito bom ver que há outros brasileros na área. :D

PS: Sou do Espirito Santo
MIPS, x86 and ARM Assembly Developer

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

Post by tokumaru »

Hehe, OK! =)

É bom mesmo ver outros brasileiros interessados nessa área. Tentarei ajudar sempre que puder! Só vamos evitar falar muito português fora do lugar porque não é muito educado com quem não entende... Mas no fórum internacional está liberado!

Translation: It is indeed good to see other brazilians interested in this area. I'll try to help whenever I can! Let's just avoid using too much portuguese out of place because it's not very polite to those who don't understand it... It's OK in the international forum though!
User avatar
nathanpc
Posts: 35
Joined: Fri Mar 12, 2010 4:55 pm
Location: Brazil
Contact:

Post by nathanpc »

It's all right ;)
MIPS, x86 and ARM Assembly Developer

Learning 6502 ;)
Post Reply