snes assembly - beginnings, a few questions (wla-65816)

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by sdm »

Unfortunately, I apparently have problems understanding many things, or I have set it all wrong in my head:
REP #$30 ; Sets A, X and Y to 16-bit mode
PHB
PHD
PHA
PHX
PHY

SEP #$20 ; Sets A to 8-bit mode
JSR CopyOAMBuf

(...)

CopyOAMBuf:
"---- assembler still knows that A is 16 bits and assembles A as 16 bit"
I am asking because I don't understand why assembler "remembers" SEP # $ 30 set earlier than "SEP # $ 20" set just before jsr jump?

(...)
RTS
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by Pokun »

The assembler may follow SEP/REP and change 8-/16-bit mode automatically, but it gets complicated as you have jumps and subroutine calls, and it can't be smart enough to always figure out which instruction you mean. However, any good 65816 assembler should have a way to change the 8-/16-bit mode manually. Though I wouldn't call WLA-DX a good 65816 assembler (I recommend 64TASS), it does have the ACCU and INDEX directives (check the WLA-DX manual) which does just this. Just make sure to always pair your SEP/REP instructions with the appropriate ACCU 8/16 and INDEX 8/16 to what you expect. If you are paranoid you can use them in the start of all subroutines and after any other jump entry point.
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by sdm »

Already a bit clearer.
Will using together with SEP / REP additionally "hinting operand" eg LDA.W / LDA.B ... ..LDX.W etc, work similarly to using .ACCU 8 / .ACCU 16 / .INDEX 8 etc directives?

So far I have no major problems in the code - just experimenting what and how it works. I try to stick to A8 / XY16 and only WHEN I NEEDED - I change the processor mode to another, and going back to A8 / XY16.


EDIT:
It's probably all clear:
REP #$30 ; Sets A, X and Y to 16-bit mode
PHB
PHD
PHA
PHX
PHY

SEP #$20 ; Sets A to 8-bit mode
JSR CopyOAMBuf

(...)

CopyOAMBuf:
.ACCU 8 ; Now it is working.

;;; SEP #$20 ; Sets A to 8-bit mode (### I am moving before I jump into this function ###)

STZ $2102 ; set OAM address to 0
STZ $2103

LDY #$0400
STY $4300

LDY #$1C00
STY $4302 ; source offset

LDY #$0220
STY $4305 ; number of bytes to transfer

LDA #$7E
STA $4304

LDA #$01
STA $420B ; start DMA transfer

RTS
This also works, so just change LDA to "LDA.B" to tell the assembler about A8:
REP #$30 ; Sets A, X and Y to 16-bit mode
PHB
PHD
PHA
PHX
PHY

SEP #$20 ; Sets A to 8-bit mode
JSR CopyOAMBuf

(...)

CopyOAMBuf:
;;;;.ACCU 8
;;; SEP #$20 ; Sets A to 8-bit mode (### I am moving before I jump into this function ###)



STZ $2102 ; set OAM address to 0
STZ $2103

LDY #$0400
STY $4300

LDY #$1C00
STY $4302 ; source offset

LDY #$0220
STY $4305 ; number of bytes to transfer

LDA.B #$7E
STA $4304

LDA.B #$01
STA $420B ; start DMA transfer


RTS
Attachments
output.smc
(256 KiB) Downloaded 34 times
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by Oziphantom »

don't use .B .W to try and fix sizes for immediate values, that will cause you lots of pain. Do it properly.

The issue you have is you think the assembler follows you code path, it doesn't. So you say

Code: Select all

.ACCU 8
jsr my function 
this tell the assembler that this function is to have an 8 bit accumulator.

No, the assembler does not simulate, run, or understand your code. It starts at the top of the file and it goes line by line down the file. It never jumps, stalls, looks ahead, just line by line.

Code: Select all

VBlank:
assembler makes a label at this current PC called `VBlank`

Code: Select all

REP #%00110000						; select 16 bit registers (REP #$30)
assembler outputs `$C2 $30` and sets acc size and index size to 16bits.

Code: Select all

PHB
assembler outputs `$8B`

Code: Select all

PHD
assembler outputs `$0B`

Code: Select all

PHA
assembler outputs `$48`

Code: Select all

PHX
assembler outputs `$DA`

Code: Select all

PHY
assembler outputs `$5A`

Code: Select all

SEP #$20
assembler outputs `$E2 $20` and sets acc size to 8bits

Code: Select all

JSR CopyOAMBuf
assembler outputs `$20 $00 $00` and makes a note that the current address + 1 needs to have the address for CopyOamBuf inserted

Code: Select all

LDA $4210
assembler outputs `$AD $10 $42`

Code: Select all

REP #%00110000						; select 16 bit registers (REP #$30)
assembler outputs `$C2 $30` and sets acc size and index size to 16bits.

Code: Select all

PLY
assembler outputs `$7A`

Code: Select all

PLX
assembler outputs `$FA`

Code: Select all

PLA
assembler outputs `$68`

Code: Select all

PLD
assembler outputs `$2B`

Code: Select all

PLB
assembler outputs `$AB`

Code: Select all

RTI
assembler outputs `$40`

Code: Select all

CopyOAMBuff:
assembler makes a label for CopyOAMBuff at the current PC, it then patches the address in the JSR above to point to this

Code: Select all

STZ $2102
assembler outputs `$9C $02 $21`

Code: Select all

STZ $2103
assembler outputs `$9C $03 $21`

Code: Select all

LDY #$0400
assembler does an Index size check, last set to 16bits so outputs `$A0 $00 $04`

Code: Select all

STY $4300
assembler outputs `$8C $00 $43`

Code: Select all

LDY #$1C00
assembler does an Index size check, last set to 16bits so outputs `$A0 $00 $1C`

Code: Select all

STY $4302						; source offset
assembler outputs `$8C $02 $21`

Code: Select all

LDY #$0220
assembler does an Index size check, last set to 16bits so outputs `$A0 $02 $21`

Code: Select all

STY $4305						; number of bytes to transfer
assembler outputs `$8C $02 $21`

Code: Select all

LDA #$7E
assembler does an Accumulator size check, last set to 16bits so outputs `$A9 $7E $00`

Code: Select all

STA $4304
assembler outputs `$8D $04 $43`

Code: Select all

LDA #$01
assembler does an Accumulator size check, last set to 16bits so outputs `$A9 $01 $00`

Code: Select all

STA $420B						; start DMA transfer
assembler outputs `$8D $0B $42`

So always set the accumulator and index sizes before each function, as you can change it accidentally with a small code change and then it could just break every function after it.
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by Oziphantom »

also another trap with auto

Code: Select all

SEP #$30
...code...
PHP
REP #$30
...code...
PLP
.. this is actually 8axy but the assembler doesn't understand PHP/PLP tracking,
.. so the assembler still thinks you have 16bit axy as the last Auto command was REP.
so you need to make sure you do

Code: Select all

SEP #$30
...code...
PHP
REP #$30
...code...
PLP
.accu8
.index8
...code...
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by sdm »

Oziphantom wrote: Fri Mar 25, 2022 10:33 pm The issue you have is you think the assembler follows you code path, it doesn't.
I know how assembler works and I know that it doesn't follow my thinking, it just translates line by line into machine code.

My question concerns only the operation of the 8/16 modes of this processor, which is unclear to me due to the first contact with such a solution.
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by Oziphantom »

which part of the operation don't you understand?

If M flag is 1 the CPU reads 8 bits values on the accumulator operations and memory operations. If it's 0 it does 16 bit operations.
If X flag is 1 the CPU reads 8 bits values on the index operations . If it's 0 it does 16 bit operations.

Only changing the M or X flags will change the way the CPU operates in 8 or 16 bit data mode. M X flags or modified by the REP and SEP commands, or the PLP command. So for example you can do

Code: Select all

lda #$30
pha
plp
This will set N,Z,V,C,B,I to 0 and M,X to 1.

There is nothing in the instruction it self that determines if the data is to be 8bit or 16 bit, only the status flags determine it. Some instructions are not affected by the M,X and will always interact with a certain number of bytes, but those are rare.

for example LDA #00
So 8bit immediate is A9 00
and 16bit immediate is A9 00 00
how many bytes it writes depends upon the perceived size state by the assembler, and how many it expects to read is determined by the CPU and its current status flags.
So if the assembler puts A9 00 00 but the CPU is in 8bit mode it will read LDA #00 BRK
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by Pokun »

The accumulator and the two index registers are each 16-bit. In 8-bit mode only the low byte is used while the high byte still have whatever value you last loaded it with and is unaffected by most instructions. The high byte of the accumulator is sometimes called B and in 16-bit mode B is combined with A so that the accumulator becomes 16-bit, and the combined accumulator is sometimes called C. You find these notations in certain mnemonics such as XBA (eXchange accumulator B with accumulator A) and TCS (Transfer accumulator C to Stack pointer). Most mnemonics of course stay the same no matter if you use 8- or 16-bit mode.
I don't think the high bytes of the index registers X and Y are named as there are no instructions for swapping them or so.
93143
Posts: 1717
Joined: Fri Jul 04, 2014 9:31 pm

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by 93143 »

The X and Y high bytes are cleared when setting them to 8-bit, unlike the accumulator where the top byte is preserved.

Also, when transferring values between registers, it's the destination that determines the size of the transfer. TXA with 16-bit index registers and 8-bit accumulator will only change A and leave B as it is. TAX under the same circumstances will replace the entire current value of X with the value of C. TXA with 8-bit index registers and 16-bit accumulator will set the bottom byte of C to X and zero the top byte.
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by Pokun »

Ah I see, that's why the high index register bytes are unnamed, they are never used alone and even cleared in 8-bit mode.
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by sdm »

How to declare a higher WRAM BANK in WLA-DX WLA-65816? For example 01x0000? I can't figure out how to do this ... Using ENUM, from what I can see you can only set 2-byte addresses.

Code: Select all

.ENUM	$0000				; wram 00x0000

wariable0			DB
wariable1			DB
(...)

.ENDE

93143
Posts: 1717
Joined: Fri Jul 04, 2014 9:31 pm

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by 93143 »

sdm wrote: Mon Nov 07, 2022 11:42 amHow to declare a higher WRAM BANK in WLA-DX WLA-65816? For example 01x0000?
I'm pretty sure you can .DEFINE anything you want. If you must make a list of variables and sizes, apparently .RAMSECTION is designed to do this, but I've never used it.

Why are you making a list of variables in high RAM anyway? Have you run out of space in shadow RAM?

Also, $010000 isn't the high WRAM bank. It's bank $01 of the SNES memory map, of which the top half is ROM and the bottom half is generally identical to bank $00, including the 8 KB WRAM mirror. To address anything beyond the bottom 8 KB of WRAM, you need banks $7E and $7F (or the port at $2180, obviously, but accessing variables through that is probably suboptimal in most cases).
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by sdm »

There are a lot of theories, but I don't know how to practically set up these higher WRAM banks ... Maybe some examples? .RAMSECTION unfortunately I tried in different ways and I really don't know how to handle it ...

I thought the wram banks are as follows:
$ 000000-001FFF
$ 010000-011FFF
$ 020000-021FFF ...
$ 3F0000-3F1FFF.
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by rainwarrior »

sdm wrote: Wed Nov 16, 2022 2:12 pmI thought the wram banks are as follows:
$ 000000-001FFF
$ 010000-011FFF
$ 020000-021FFF ...
$ 3F0000-3F1FFF.
No, those are all mirrors of the same block of RAM.

That first 8kb of RAM ("Low RAM") is available in half of all banks. This means it can conveniently be accessed without having to change the data bank register (B) when using LoROM (or a LoROM area of HiROM).

The remaining 120k of RAM is available exclusively at $7E2000-7FFFF, which means you either have to change the data bank to access it, or use far/long addressing (which takes an extra byte per instruction, and there are fewer available operations).

Maybe these diagrams would be helpful: Wiki: Memory map
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: snes assembly - beginnings, a few questions (wla-65816)

Post by sdm »

Ok .. Thanks, now it's clear. I misunderstood the memory map :)

Code: Select all

.ENUM $7E2000

variable					DB

.ENDE

or.

.DEFINE variable      $7E2000

However, something is wrong.
For example, when I set a variable, as above in 7E2000, and perform a simple operation on it:

Code: Select all

INC variable
I get this compiler error:

main.asm:642: INPUT_NUMBER: Out of 16-bit range.
main.asm:642: ERROR: Couldn't parse "inc".

But when I do it this way it all works:

Code: Select all

LDA variable
INC A
STA variable
I don't really understand what's going on: / ?

Are there any restrictions on using higher banks against the low one (0000-1FFF)?
Post Reply