Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[65816/?] A Definition between 2 Sections that use it causes weird behavior #104

Closed
bazz1tv opened this issue Apr 18, 2016 · 9 comments
Closed
Assignees

Comments

@bazz1tv
Copy link

@bazz1tv bazz1tv commented Apr 18, 2016

Reference #102 -- After searching 12 pages of "wla dx" -- I found http://forums.nesdev.com/viewtopic.php?f=12&t=12268&p=139715&hilit=wla+dx#p139715

I managed to identify the cause and created a minimal bug_exhibition.
section_def_bug.zip

The beginning of main.s details the bug:

;»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
; written by bazz 2016
;»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

/* When a definition is defined *between* two sections
which both use the definition, a bug occurs.

In this case, the definition is 16-bits. eg. `.DEFINE YTemp     $1808`

The section *before* the def incorrectly infers the def's bit-width
The section *after* the def correctly infers the def's bit-width.

This example executes the 2nd section which does a jsr into the first section.

Here is a snippet of the ROM output this bug_exhibition creates:

(section *after* def)
(GOOD)  00800b sty $1808     [001808] A:0000 X:1fff Y:0055 S:1fff D:0000 DB:00 nvMxdIzC V:  0 H: 310
(GOOD)  00800e stx $180a     [00180a] A:0000 X:1fff Y:0055 S:1fff D:0000 DB:00 nvMxdIzC V:  0 H: 350
        008011 jsr $8016     [008016] A:0000 X:1fff Y:0055 S:1fff D:0000 DB:00 nvMxdIzC V:  0 H: 390
(section *before* def)
        008016 php                    A:0000 X:1fff Y:0055 S:1ffd D:0000 DB:00 nvMxdIzC V:  0 H: 436
        008017 rep #$10               A:0000 X:1fff Y:0055 S:1ffc D:0000 DB:00 nvMxdIzC V:  0 H: 458
        008019 sep #$20               A:0000 X:1fff Y:0055 S:1ffc D:0000 DB:00 nvMxdIzC V:  0 H: 480
(BAD)   00801b ldy $08       [000008] A:0000 X:1fff Y:0055 S:1ffc D:0000 DB:00 nvMxdIzC V:  0 H: 502
(BAD)   00801d ldx $0a       [00000a]

00801b should be ldy $1808, for example.
*/

Possible Workarounds/Solutions:

  • Place definitions before all sections that will use it
  • Explicit hinting (eg. ldy.w)
  • Disallow mid-placed definitions like this
  • Or, Fix this bug
.MEMORYMAP
DEFAULTSLOT 0
SLOTSIZE $8000
SLOT 0 $8000
.ENDME

.ROMBANKMAP
BANKSTOTAL 1
BANKSIZE $8000
BANKS 1
.ENDRO

.BANK 0 SLOT 0
; === Interrupt Vector Table ====================
.ORG    $7FE4                 ; === Native Mode ===
.DW     EmptyHandler          ; COP
.DW     EmptyHandler          ; BRK
.DW     EmptyHandler          ; ABORT
.DW     VBlank                ; NMI
.DW     $0000                 ; (Unused)
.DW     EmptyHandler          ; IRQ

.ORG    $7FF4   ; === Emulation Mode ===
.DW     EmptyHandler          ; COP
.DW     $0000                 ; (Unused)
.DW     EmptyHandler          ; ABORT
.DW     EmptyHandler          ; NMI
.DW     main                  ; RESET
.DW     EmptyHandler          ; IRQ/BRK


;»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
; main
;»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
; Works OK here
; .DEFINE YTemp     $1808
; .DEFINE XTemp     $180A

.BANK 0 SLOT 0
.ORG 0
.SECTION "WalkerCode"

start_metasprite:
    php
    rep #$10
    sep #$20
    ldy YTemp
    ldx XTemp
    plp     ;no clue
    rts     ;jump back to the main code
.ENDS

; Works BAD here
.DEFINE YTemp       $1808
.DEFINE XTemp       $180A

.BANK 0 SLOT 0
.ORG 0
.SECTION "MetaspriteCode"

main:
    sei                     ;disable interrupts
    clc                     ;switch to native mode
    xce
    rep #$38
    sep #$20
    ldx #$1FFF
    txs

    sty YTemp       ;store y to YTemp
    stx XTemp       ;store x to XTemp
    jsr start_metasprite    ;jump to start_metasprite to build a metasprite

EmptyHandler:
    rti
VBlank:
    rti
.ENDS
@nicklausw
Copy link
Contributor

@nicklausw nicklausw commented Apr 18, 2016

People should really define things BEFORE using them, that's just an assembler rule in general.

Ville (not sure if you're still around), when does the assembler go back to fix these defines? Is it during linker stage, or could the proper opcode be selected by the assembler?

Loading

@vhelin
Copy link
Owner

@vhelin vhelin commented Apr 19, 2016

On Tue, Apr 19, 2016 at 3:33 AM, Bazz notifications@github.com wrote:

Reference #102 #102 -- After
searching 12 pages of "wla dx" -- I found
http://forums.nesdev.com/viewtopic.php?f=12&t=12268&p=139715&hilit=wla+dx#p139715

I managed to identify the cause and created a minimal bug_exhibition.
section_def_bug.zip
https://github.com/vhelin/wla-dx/files/224627/section_def_bug.zip

The beginning of main.s details the bug:

;»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
; written by bazz 2016
;»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

/* When a definition is defined between two sections
which both use the definition, a bug occurs.

In this case, the definition is 16-bits. eg. .DEFINE YTemp $1808

The section before the def incorrectly infers the def's bit-width
The section after the def correctly infers the def's bit-width.

This example executes the 2nd section which does a jsr into the first section.

Here is a snippet of the ROM output this bug_exhibition creates:

(section after def)
(GOOD) 00800b sty $1808 [001808] A:0000 X:1fff Y:0055 S:1fff D:0000 DB:00 nvMxdIzC V: 0 H: 310
(GOOD) 00800e stx $180a [00180a] A:0000 X:1fff Y:0055 S:1fff D:0000 DB:00 nvMxdIzC V: 0 H: 350
008011 jsr $8016 [008016] A:0000 X:1fff Y:0055 S:1fff D:0000 DB:00 nvMxdIzC V: 0 H: 390
(section before def)
008016 php A:0000 X:1fff Y:0055 S:1ffd D:0000 DB:00 nvMxdIzC V: 0 H: 436
008017 rep #$10 A:0000 X:1fff Y:0055 S:1ffc D:0000 DB:00 nvMxdIzC V: 0 H: 458
008019 sep #$20 A:0000 X:1fff Y:0055 S:1ffc D:0000 DB:00 nvMxdIzC V: 0 H: 480
(BAD) 00801b ldy $08 [000008] A:0000 X:1fff Y:0055 S:1ffc D:0000 DB:00 nvMxdIzC V: 0 H: 502
(BAD) 00801d ldx $0a [00000a]

00801b should be ldy $1808, for example.
*/

Possible Workarounds/Solutions:

  • Place definitions before all sections that will use it
  • Explicit hinting (eg. ldy.w)

Both of these solutions above are valid. If you refer to a definition (or
it could also be a label that gets lexically introduced later, or in some
other file) before it's defined, WLA makes a guess about the size, and I
think it always used the smallest size possible, unless instructed
otherwise with size hints.

  • Disallow mid-placed definitions like this
  • Or, Fix this bug

Disallowing is not possible, and fixing this bug is not possible as it's
not a bug. :)

.MEMORYMAP
DEFAULTSLOT 0
SLOTSIZE $8000
SLOT 0 $8000
.ENDME

.ROMBANKMAP
BANKSTOTAL 1
BANKSIZE $8000
BANKS 1
.ENDRO

.BANK 0 SLOT 0
; === Interrupt Vector Table ====================
.ORG $7FE4 ; === Native Mode ===
.DW EmptyHandler ; COP
.DW EmptyHandler ; BRK
.DW EmptyHandler ; ABORT
.DW VBlank ; NMI
.DW $0000 ; (Unused)
.DW EmptyHandler ; IRQ

.ORG $7FF4 ; === Emulation Mode ===
.DW EmptyHandler ; COP
.DW $0000 ; (Unused)
.DW EmptyHandler ; ABORT
.DW EmptyHandler ; NMI
.DW main ; RESET
.DW EmptyHandler ; IRQ/BRK

;»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
; main
;»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
; Works OK here
; .DEFINE YTemp $1808
; .DEFINE XTemp $180A

.BANK 0 SLOT 0
.ORG 0
.SECTION "WalkerCode"

start_metasprite:
php
rep #$10
sep #$20
ldy YTemp
ldx XTemp
plp ;no clue
rts ;jump back to the main code
.ENDS

; Works BAD here
.DEFINE YTemp $1808
.DEFINE XTemp $180A

.BANK 0 SLOT 0
.ORG 0
.SECTION "MetaspriteCode"

main:
sei ;disable interrupts
clc ;switch to native mode
xce
rep #$38
sep #$20
ldx #$1FFF
txs

sty YTemp       ;store y to YTemp
stx XTemp       ;store x to XTemp
jsr start_metasprite    ;jump to start_metasprite to build a metasprite

EmptyHandler:
rti
VBlank:
rti
.ENDS


You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
#104

Loading

@vhelin
Copy link
Owner

@vhelin vhelin commented Apr 19, 2016

On Tue, Apr 19, 2016 at 6:34 AM, nicklausw notifications@github.com wrote:

People should really define things BEFORE using them, that's just an
assembler rule in general.

Absolutely. :)

Ville (not sure if you're still around), when does the assembler go back
to fix these defines? Is it during linker stage, or could the proper opcode
be selected by the assembler?

If I remember correctly, assembler tries to solve a reference to a
definition (could also be a label as there is no way to telling the
difference until the definition/label is introduced) as it assembles
things, on the go, lexically, but if it doesn't find value for a definition
I think it then assumes that it's actually a reference to a label, and
leaves it for the linker as linker has all the information later, after it
has placed all the sections with labels, and the linker can solve all
pending computations (unless some data is missing).

The assembler selects the opcodes and turns them into bits and bytes. The
linker has no idea of opcodes, it just deals with raw data and can
calculate some checksums...


You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
#104 (comment)

Loading

@bazz1tv
Copy link
Author

@bazz1tv bazz1tv commented Apr 19, 2016

Is there some kind of test that can be made in the assembler/linker so the user can be made aware when this situation exists?

I can see it going over many people's heads that they have created this circumstance and unprepared for the mayhem it can cause.

Please understand that this situation is what led several programmers to believe WLA-DX is a bad assembler.

Loading

@vhelin
Copy link
Owner

@vhelin vhelin commented Apr 19, 2016

On Tue, Apr 19, 2016 at 9:17 AM, Bazz notifications@github.com wrote:

Is there some kind of test that can be made in the assembler/linker so the
user can be made aware when this situation exists?

I can see it going over many people's heads that they have created this
circumstance and unprepared for the mayhem it can cause.

Please understand that this situation is what led several programmers to
believe WLA-DX is a bad assembler.

They are not very old programmers then as assemblers that can handle such
situations were not (commonly) present in the 90's when WLA DX was born...
:) Not a reason to not add support for such parsing, but might be quite
complicated given the current architecture of WLA DX.

Perhaps a message in the README would be enough? For the user it's just
about where to put the definitions, not a very complicated thing to have
the definition lexically before you use it. :)


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
#104 (comment)

Loading

@bazz1tv
Copy link
Author

@bazz1tv bazz1tv commented Apr 19, 2016

Having this detailed in the README is imperative without any assembler/linker warnings. Think of all the n00bs who were just trying to learn to code their favorite console with WLA DX who made this mistake and silently blew things up and had no idea why their program never worked properly. This is likely to have happened to lots of people.

I understand that the architecture of WLA-DX might make warning of such a circumstance difficult, but just realize we are allowing the user to unknowingly make mistakes, with terrible repercussions.

Loading

@vhelin
Copy link
Owner

@vhelin vhelin commented Apr 19, 2016

On 19 Apr 2016 09:35, "Bazz" notifications@github.com wrote:

Having this detailed in the README is imperative without any
assembler/linker warnings. Think of all the n00bs who were just trying to
learn to code their favorite console with WLA DX who made this mistake and
silently blew things up and had no idea why their program never worked
properly. This is likely to have happened to lots of people.

Ok, I'll write about this to README later today - it's my day off from day
trips and scuba diving, just resting... :)

I understand that the architecture of WLA-DX might make warning of such a
circumstance difficult, but just realize we are allowing the user to
unknowingly make mistakes, with terrible repercussions.

I'm not sure if it's possible to tell the difference between a problematic
case and a non-prob one, from the assembler's point of view, easily and
generally. One case specific hack comes into my mind: in the assembler,
while parsing, when the assembler spots a reference to an unknown
label/definition, it adds that to a list. When the assembler encounters a
.define and spots it on the list, it gives a warning... And these warnings
could be silenced using the upcoming --quiet :)


You are receiving this because you commented.

Reply to this email directly or view it on GitHub

Loading

@bazz1tv
Copy link
Author

@bazz1tv bazz1tv commented Apr 19, 2016

I like that idea!

On Mon, Apr 18, 2016 at 11:09 PM, Ville Helin notifications@github.com
wrote:

On 19 Apr 2016 09:35, "Bazz" notifications@github.com wrote:

Having this detailed in the README is imperative without any
assembler/linker warnings. Think of all the n00bs who were just trying to
learn to code their favorite console with WLA DX who made this mistake and
silently blew things up and had no idea why their program never worked
properly. This is likely to have happened to lots of people.

Ok, I'll write about this to README later today - it's my day off from day
trips and scuba diving, just resting... :)

I understand that the architecture of WLA-DX might make warning of such a
circumstance difficult, but just realize we are allowing the user to
unknowingly make mistakes, with terrible repercussions.

I'm not sure if it's possible to tell the difference between a problematic
case and a non-prob one, from the assembler's point of view, easily and
generally. One case specific hack comes into my mind: in the assembler,
while parsing, when the assembler spots a reference to an unknown
label/definition, it adds that to a list. When the assembler encounters a
.define and spots it on the list, it gives a warning... And these warnings
could be silenced using the upcoming --quiet :)


You are receiving this because you commented.

Reply to this email directly or view it on GitHub


You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
#104 (comment)


Michael Bazzinotti
​Technologist & Musician​

http://www.bazz1.com

[image: Attleboro-low rez] http://locations.schoolofrock.com/attleboro
http://locations.schoolofrock.com/attleboro

Loading

@vhelin vhelin self-assigned this May 31, 2016
@vhelin
Copy link
Owner

@vhelin vhelin commented May 25, 2021

I see that there is a note in the documentation about declaring .DEFINE before using it, and currently if you create the .DEFINE after using it in e.g., .DB, it'll get the last value of last .DEFINE/.REDEFINE:

WARNING: Please declare your definition lexically before using it as otherwise
the assembler might make incorrect assumptions about its value and size and
choose e.g. wrong opcodes and generate binary that doesn't run properly.

...

Note that you must do your definition before you use it, otherwise
WLA will use the final value of the definition. Here's an example
of this::

    .DEFINE AAA 10
    .DB AAA            ; will be 10.
    .REDEFINE AAA 11

but::

    .DB AAA            ; will be 11.
    .DEFINE AAA 10
    .REDEFINE AAA 11

I think this solves this issue. If you think otherwise, please reopen this issue.

Loading

@vhelin vhelin closed this May 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants