This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

asm6 Errors That Don't Occur On NESASM

asm6 Errors That Don't Occur On NESASM
by on (#59950)
Hello,
As many people suggested me to change from NESASM to asm6, but now I'm getting errors. My code is like this:
Code:
   .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:
[~/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

by on (#59957)
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.

by on (#59959)
Inside which bank(or place) I need to put the iNES headers?

by on (#59961)
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.

by on (#59962)
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.

by on (#59963)
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.

by on (#59964)
Nope, all assemblers handles labels, local labels and unlabeled labels differently. Without counting that many "forces you to do weird things in your code".

by on (#59968)
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...)

by on (#59969)
koitsu wrote:
don't people read README files any more? I guess not...)


Did they ever?

XD

by on (#59972)
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.

by on (#59973)
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.

by on (#60758)
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. :)