Page 1 of 1

asm6 Errors That Don't Occur On NESASM

Posted: Sun Apr 11, 2010 5:16 am
by nathanpc
Hello,
As many people suggested me to change from NESASM to asm6, but now I'm getting errors. My code is 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
addrLO = $10 
addrHI = $11
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

	;set the destination address for sprite palettes ($3F10) 
	lda #$3F 
	sta $2006 
	lda #$10 
	sta $2006 

	;copy 16 colors 
	ldx #$00 
LoadSpritePalette: 
   	lda tilepal, x 
   	sta $2007 
   	inx 
   	cpx #16 
   	bne LoadSpritePalette 

   	;set the destination address for background palettes ($3F00) 
   	lda #$3F 
   	sta $2006 
   	lda #$00 
   	sta $2006 

   	;copy 16 colors 
   	ldx #$00 
LoadBackgroundPalette: 
  	lda bkgpal, x 
  	sta $2007 
  	inx 
  	cpx #16 
  	bne LoadBackgroundPalette

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 

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 sprite pallete
	
bkgpal:
	.incbin "bkg.pal" ; include and label our background 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"  ; background data
	.incbin "our.spr"  ; our sprite pic data
But when I try to compile it I got this:

Code: Select all

[~/NES]$ asm6 our.asm

pass 1..
our.asm(1): Illegal instruction.
our.asm(2): Illegal instruction.
our.asm(3): Illegal instruction.
our.asm(4): Illegal instruction.
our.asm(6): Illegal instruction.
our.asm(58): Illegal instruction.
our.asm(60): Illegal instruction.
our.asm(194): Illegal instruction.
our.asm(201): Illegal instruction.

[~/NES]$ 
What can I do?

Best Regards,
Nathan Paulino Campos

Posted: Sun Apr 11, 2010 6:05 am
by tepples
If you're not using an NES-specific assembler, you'll need to make the iNES header and set memory areas (your .bank) a different way.

Posted: Sun Apr 11, 2010 6:07 am
by nathanpc
Inside which bank(or place) I need to put the iNES headers?

Posted: Sun Apr 11, 2010 8:03 am
by koitsu
Usually people set .org $7FF0 and then use .db statements to represent each of the 16 bytes of the iNES header.

So you'd probably want to do this after the .org $0000 / .db section, but before the .org $8000 section.

Posted: Sun Apr 11, 2010 8:05 am
by Bregalad
You hit the biggest issue with assembly : There is no standard way to give commands to the assembler. The only "semi-standard" are directive like .db, .include, .incbin but even then not all assemblers have them.

You'll have to change a lot of things in your source so that ASM6 takes it, and whenever you decide to change again to yet another assembler, you'll have to do a lot of changes again. This is really terrible so you'd better be sure of you choice when you pick an assembler and be sure it has all features you 'd like it to do, and be prepared for a few boring weekends to change syntax of your code whenever you decide to change which assembler you use.

Posted: Sun Apr 11, 2010 9:28 am
by blargg
Write a file that you include at the top of all your programs, which sets up the assembler-specific things. This of course fails for assemblers like wla that force you to do weird things all throughout your code. But for ones like ca65, nesasm, asm6, etc., it should work well.

Posted: Sun Apr 11, 2010 9:54 am
by Bregalad
Nope, all assemblers handles labels, local labels and unlabeled labels differently. Without counting that many "forces you to do weird things in your code".

Posted: Sun Apr 11, 2010 11:34 am
by koitsu
Usually an assembler is intended for certain architectures or platforms (for example, x816) -- and because of that, offers pseudo-ops (ex: .ineschr) which control platform-specific details.

This really isn't a downside or a negative. asm6 chooses to remain a generic 6502 assembler, which means it lacks such psuedo-ops. A NES developer would consider this a negative/fault, while someone working on, say, the Apple II would consider this a plus/feature.

The method I described is how most things got done "back in the day" -- given that this is discussing development on hardware from "back in the day", I don't see the problem with using the same methods. :)

Bregalad's comments regarding how different assemblers behave differently is absolutely correct -- it's the responsibility of the developer to learn and become familiar with their assembler. (That said, I do find it amazing how many people are attempting to develop "NES stuff" yet aren't familiar with the tools they're using -- don't people read README files any more? I guess not...)

Posted: Sun Apr 11, 2010 12:32 pm
by Disch
koitsu wrote:don't people read README files any more? I guess not...)
Did they ever?

XD

Posted: Sun Apr 11, 2010 3:02 pm
by tokumaru
nathanpc, did you look at the ASM6 templates I posted? There you can see how to make the header. These ".inesprg", ".ineschr" and such directives are exclusive to NESASM, they won't work in any other assembler. But as you can see in my templates setting up a header with ".db" statements is not hard at all.

Another obvious difference is the lack of ".bank" directives. In ASM6 you simply don't need them, just use ".org" and ".base" appropriately to organize your banks as necessary.

Posted: Mon Apr 12, 2010 2:14 am
by doppelganger
nathanpc wrote:Inside which bank(or place) I need to put the iNES headers?
iNES headers, being what they are, go at the beginning of the .nes file. The easiest way to do this is to insert the header before any .org or .base directives.

Posted: Sun May 02, 2010 7:05 pm
by nathanpc
Disch wrote:
koitsu wrote:don't people read README files any more? I guess not...)
Did they ever?

XD
Normal people(like me) never read a README file! :P

tokumaru wrote:nathanpc, did you look at the ASM6 templates I posted? There you can see how to make the header. These ".inesprg", ".ineschr" and such directives are exclusive to NESASM, they won't work in any other assembler. But as you can see in my templates setting up a header with ".db" statements is not hard at all.

Another obvious difference is the lack of ".bank" directives. In ASM6 you simply don't need them, just use ".org" and ".base" appropriately to organize your banks as necessary.
Thanks mate, I've followed it, done all that you've said and now all is working. :)