Page 1 of 1

Converting project to asm6 from nesasm3 - large chunks of code being marked "unidentified"

Posted: Fri May 29, 2020 9:18 pm
by samcan
Hi,

I'm trying to convert a project I'm working on to asm6 (specifically asm6f [https://github.com/freem/asm6f]) from nesasm3 but I'm running into difficulties. I followed the guidance given in viewtopic.php?t=12219&start=0#p138851 and the NES file compiles without any issues. But when I run in Mesen, it doesn't work. I've been comparing the nesasm3-generated NES to the asm6-generated NES and I'm seeing some weird issues where chunks of code that are interpreted by Mesen's debugger as valid 6502 statements when looking at the nesasm3 file are interpreted as "unidentified data" when looking at the asm6 file, even though the opcodes are the same.

For example, in my RESET handler, I had the following, with VBlankWait as a subroutine later in the program:

Code: Select all

  .org $C000
RESET:
  SEI          ; disable IRQs
  CLD          ; disable decimal mode
  LDX #$40
  STX $4017    ; disable APU frame IRQ
  LDX #$FF
  TXS          ; Set up stack
  INX          ; now X = 0
  STX $2000    ; disable NMI
  STX $2001    ; disable rendering
  STX $4010    ; disable DMC IRQs

  JSR VBlankWait		; First wait for vblank to make sure PPU is ready
  
  LDX #$00
clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  ;STA $01F0, x
  STA $0300, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0200, x
  INX
  CPX #$00
  BNE clrmem
   
  JSR VBlankWait		; Second wait for vblank, PPU is ready after this
  
  LDA <palette
  STA paletteLo
  LDA >palette
  STA paletteHi
  JSR LoadPalettes
This compiles fine with NESASM, and is interpreted correctly by Mesen's debugger. But if I compile with asm6, Mesen's debugger marks the "JSR VBlankWait" as "unidentified data" rather than as a JSR.

if I replace the JSR and just copy-and-paste the VBlankWait function into those two spots and compile with asm6, then Mesen's debugger correctly interprets it. But this is happening in other places as well, and I'm not sure what to do, because I sure can't replace every single JMP or JSR with inlined code!

I also tested the asm6-generated NES file with fceux, and it doesn't work either, so it's not just a Mesen issue. Apparently there's some change I need to make to my code to get it to appropriately assembly with asm6, but reading the included documentation, I'm not sure what it is.

Thanks!

Re: Converting project to asm6 from nesasm3 - large chunks of code being marked "unidentified"

Posted: Fri May 29, 2020 9:21 pm
by samcan
And then I just try putting the VBlankWait subroutine back and Mesen now shows it correctly! Zounds... But there are still other JMPs and JSRs which are malfunctioning. Has anyone ever heard of this?

Re: Converting project to asm6 from nesasm3 - large chunks of code being marked "unidentified"

Posted: Sat May 30, 2020 12:02 am
by Fiskbit
Assuming you mean "unidentified block", Mesen doesn't inherently know whether any given byte is code, data, or unused, so everything starts out as unidentified and is only marked as code or data when it is actually accessed. When an instruction is executed, Mesen will automatically mark everything after that as code up to any instruction that changes control flow, such as RTS, JMP, or branches (though this code will be highlighted in green until it's actually executed). This information is all stored in a code/data log that gets loaded with that ROM.

I think some assemblers, like ca65, can output files that Mesen can use to know what every byte is (and even include your comments and labels in the debugger), but I don't have any experience with this, myself.

Re: Converting project to asm6 from nesasm3 - large chunks of code being marked "unidentified"

Posted: Sat May 30, 2020 12:49 am
by tokumaru
Even if the translation to ASM6 is 100% correct, there's at least one thing that may cause the assembled binary to differ from the one generated by NESASM: ASM6 will use ZP addressing whenever possible, while NESASM will only do it if explicitly told to, so the code will likely be smaller when assembled in ASM6. Maybe this caused something your program to shift when it shouldn't (breaking references/pointers)?

Another possibility is that there's something wrong with the 16-byte NES header at the beginning of the file. NESASM will automatically generate a header for you based on the values passed to the .ines*** directives, but in ASM6 you have to generate that manually (usually via .db statements), and if something is not right it may cause the emulator to load and run your ROM incorrectly, or not at all. Can you verify that the header is correct in the file assembled by ASM6?

Re: Converting project to asm6 from nesasm3 - large chunks of code being marked "unidentified"

Posted: Sat May 30, 2020 9:24 am
by samcan
I figured it out!

I ended up stepping through the ROM in Mesen, and found I was getting stuck in a subroutine I'd created for text display. You'd pass in the low and high bytes of a specially-crafted text string, and the subroutine would display the string on the screen. In NESASM, you used the #LOW and #HIGH to grab the low and high bytes. I'd converted that to < and >, but I didn't realize that I needed to actually convert to #< and #>. Now that I've done that (see below example code from my documentation), it's working!

Code: Select all

  LDA #<helloworldtext
  STA textvarLo
  LDA #>helloworldtext
  STA textvarHi

  LDA #<titletextattr
  STA textattrLo
  LDA #>titletextattr
  STA textattrHi
  JSR DisplayText
Thank you all for your help!

Re: Converting project to asm6 from nesasm3 - large chunks of code being marked "unidentified"

Posted: Sat May 30, 2020 10:55 am
by tokumaru
Oh yeah, the # means "immediate", and is separate from the LOW/HIGH functions and the </> unary operators.

Re: Converting project to asm6 from nesasm3 - large chunks of code being marked "unidentified"

Posted: Sat May 30, 2020 1:51 pm
by samcan
tokumaru wrote:
Sat May 30, 2020 10:55 am
Oh yeah, the # means "immediate", and is separate from the LOW/HIGH functions and the </> unary operators.
Yeah, stupid me thought, "Oh, the #LOW must be a special nesasm function and so I need to replace it all with '<'"



(facepalm)
¯\_(ツ)_/¯

Re: Converting project to asm6 from nesasm3 - large chunks of code being marked "unidentified"

Posted: Sat May 30, 2020 2:32 pm
by tepples
For reference, here are what the popular assemblers accept for extracting bits 7-0 of a symbol and then treating it as an immediate value.

NESASM: #LOW(x)
ASM6: #<x
ca65: #<x or #.lobyte(x)

Re: Converting project to asm6 from nesasm3 - large chunks of code being marked "unidentified"

Posted: Sat May 30, 2020 3:34 pm
by rainwarrior
Just one other thing to be clear, the following in NESASM:
lda <variable ; NESASM load variable from zero-page

In NESASM, this is being used to designate that it should be a zero-page addressing instruction. It also does a check to make sure that variable really does exist on the zeropage.

In ASM6 or ca65, you should not do this. Normally the selection of a (faster/smaller) zero-page vs. absolute addressing instruction is done automatically, but the < has a slightly different meaning. Instead of modifying the instruction, it intentionally truncates the variable's address to 8-bits, so it's forcing it to zero-page whether or not variable actually was there, throwing away the error check.

Instead if using ca65, the direct equivalent is:
lda z:variable ; ca65 load variable from zero-page

However, most of the time there's no need to explicitly ask for zero-page. If variable is already designated as part of the zero-page previously in the file, the following will do the same:
lda variable ; ca65/ASM6 load variable with the best known addressing mode

Conversely, if you want to force absolute addressing even though something is known as zero-page, ca65 lets you do this as well:
lda a:variable ; ca65 load variable with absolute addressing

In NESASM everything is absolute addressing without the <. In ca65, it modifies the value, but in NESASM < actually chooses the type of instruction instead. Any instruction without it uses the absolute version, so this would be equivalent to the a:variable from ca65:
lda variable ; NESASM load variable with absolute addressing