6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 1:14 pm

All times are UTC




Post new topic Reply to topic  [ 14 posts ] 
Author Message
PostPosted: Sat Jul 14, 2012 8:47 pm 
Offline

Joined: Sat Jul 07, 2012 10:46 pm
Posts: 7
So I am trying to learn how to program the Super Nintendo. I am working on a demo and have run into a stumbling block.
I can't seem to successfully load a 16 bit register into the accumulator register. I have read the docs and have learned that I need
to put the accumulator flag into 16 bit mode in the status register.

So I did the following

Code:
rep #%00110000  ; Put both A and X/Y into 16 bit mode
lda #$100 ; Represents how many tiles I want to draw to the screen... in this case 256
sep #%00100000 ; Reset A back into 8 bit mode

; Do a loop and draw 256 tiles to the screen


Basically I have found that if I load "$FF" or 255 into A, I see 255 tiles drawn the screen.
but if I go outside of 1 byte and try $256, my code fails and I see nothing on screen.
I am pretty sure that the problem is because I either misunderstand or am not putting a
correct 16 bit value in the A register because if I load any other number under a byte from
0-255, my code works as expected. Can anyone please shed some light on my misunderstanding?

Thanks!


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 14, 2012 8:51 pm 
Offline

Joined: Sat Jul 07, 2012 10:46 pm
Posts: 7
I figured it would be more helpful if I actually show my code Here is what I am doing

Code:

.DEFINE TileCounter $21
.DEFINE OffX          $22


GenerateMap:

      ;ldx #$0400
      ;stx $2116
      ;lda #$01
      ;sta $2118

      ldx OffX
      stx $2116
      lda TileCounter
      sta $2118
     
TileSwap:
      ldx TileCounter
      inx
      stx TileCounter
      lda TileCounter
      cmp #4
      bne MapSwap
      lda #1
      sta TileCounter
     
MapSwap:
      ldx OffX
      inx
      stx OffX
      lda OffX
      cmp #255
      bne GenerateMap




The above code works but if I define OffX to be a number greater than 255, I see nothing on the screen.


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 14, 2012 9:35 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8545
Location: Southern California
In know nothing about Super Nintendo, but for the 65816, for your first part, putting A in 16-bit mode then loading $100 and then putting it back in 8-bit mode means you now have 0 in it. Bits 8 and up are in accumulator B which you just made not to be part of A.

But for your code listing:
Code:
TileSwap:
      ldx TileCounter
      inx
      stx TileCounter
      lda TileCounter
      cmp #4
      bne MapSwap
      lda #1
      sta TileCounter

why not just increment TileCounter directly without pulling it into a register and then storing it again. But since you do pull it into a register then store it, why recall it again. Just do LDA, INC, STA, then CMP#4. Same thing after MapSwap, for greater efficiency.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 14, 2012 9:41 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8545
Location: Southern California
REP and SEP are awfully cryptic though. For greater clarity with no penalty in memory or runtime speed, you can use macros to show what you're doing. Define them something like:
Code:
ACCUM_16: MACRO            ; Put accumulator into 16-bit mode.
          REP  #00100000B
          ENDM
 ;---------------

ACCUM_8:  MACRO            ; Put accumulator into 8-bit mode.
          SEP  #00100000B
          ENDM
 ;---------------

INDEX_16: MACRO            ; Put index registers into 16-bit mode.
          REP  #00010000B
          ENDM
 ;---------------

INDEX_8:  MACRO            ; Put index registers into 8-bit mode.
          SEP  #00010000B
          ENDM
 ;---------------

and then just use ACCUM_16, ACCUM_8, etc. as if they were assembly-languange mnemonics. They result in exactly the same machine code which executes in the same number of cycles, but it's much more clear what you're doing.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 14, 2012 10:10 pm 
Offline

Joined: Sat Jul 07, 2012 10:46 pm
Posts: 7
GARTHWILSON, thanks for the heads up. I will definitely use your 8/16 bit mode macro. Seems like a great idea!

As far as incrementing the TileCounter variable directly, I didn't realize I could do that.
How does one increment a variable directly in 65c816?

Also, while we are on the topic of marcos, what is the syntax for writing a macro that takes an immediate value as an argument and loads it directly into a register?

For example, lets say I have a maco called "SetA"
and I want the code to be called like so


Code:
SetA #5


And basically I want the macro to do the following
Code:
.MACRO SetA value
lda value
.ENDM


I still am unsure of how to do something like that.


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 14, 2012 10:38 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8545
Location: Southern California
Your macro listing is nearly perfect, at least for some assemblers. Just put the "#" in front of "value" in the LDA line, in indeed LDA #value is what you want. (It hardly seems very useful to just rename LDA# though, as that's awfully standard and clear 6502/c02/816 assembly language.) Edit: Oh, also, remove the "#" from the line where you invoke the macro. The C32 assembler I use does not put a dot in front of "MACRO" or "ENDM", and the 2500AD assembler I used before didn't either-- but do whatever works in yours.

"INC TileCounter" works in 6502, 65c02, and 65816. They all have the same addressing modes available in INC except the NMOS 6502 which does not let you increment the accumulator. On the '816, if you increment the variable without bringing it into a register, it will treat it as the width that the accumulator is set to; so if 8-bit, it will increment a one-byte variable, and if 16-bit, it will increment the two-byte variable residing at that address and the following one, low byte first of course.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 15, 2012 2:25 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8509
Location: Midwestern USA
GARTHWILSON wrote:
Your macro listing is nearly perfect, at least for some assemblers. Just put the "#" in front of "value" in the LDA line, in indeed LDA #value is what you want. (It hardly seems very useful to just rename LDA# though, as that's awfully standard and clear 6502/c02/816 assembly language.) Edit: Oh, also, remove the "#" from the line where you invoke the macro. The C32 assembler I use does not put a dot in front of "MACRO" or "ENDM", and the 2500AD assembler I used before didn't either-- but do whatever works in yours.

"INC TileCounter" works in 6502, 65c02, and 65816. They all have the same addressing modes available in INC except the NMOS 6502 which does not let you increment the accumulator. On the '816, if you increment the variable without bringing it into a register, it will treat it as the width that the accumulator is set to; so if 8-bit, it will increment a one-byte variable, and if 16-bit, it will increment the two-byte variable residing at that address and the following one, low byte first of course.

Unfortunately, macro languages are not standardized amongst 65xx assemblers, so any help we offer is going to be somewhat vague. I use the Kowalski simulator's assembler to write '816 code. Its macro language is a bit different than what Garth described, but all of it works on the same principle.

BTW, I use LONGA, LONGR, LONGX, SHORTA, SHORTR and SHORTX to change register widths. Beats typing REP#%--------- and SEP #%--------- all the time. :lol:

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 15, 2012 7:48 am 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
In addition to the SEP/REP instructions most 65816 assemblers will need a directive to tell them whether to generate 8 or 16 bit literal values for the following immediate load instructions.
Code:
    SEP #$30
    .LONGA OFF

    REP #$30
    .LONGA ON
    .LONGI ON

Look at your listing and if you see a two byte instruction for a load immediate (e.g LDA #$FF => A9 FF) then your assembler is in 6502 mode if its three bytes (e.g. A9 FF 00) then its generated a 16-bit literal.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 15, 2012 8:09 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8545
Location: Southern California
Ah yes, I forgot to mention it. For the C32 assembler however, instead of .LONGA ON/OFF, you do for example LDA #0 for A9 00 00, and LDA #<0 for the single-byte operand.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 16, 2012 1:23 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8509
Location: Midwestern USA
BitWise wrote:
Code:
    SEP #$30
    .LONGA OFF

    REP #$30
    .LONGA ON
    .LONGI ON

That's the syntax used in the WDC compiler/assembler/linker package. No one has really standardized in that area. However, one could create a, say, LONGA macro that would combine the .LONGA ON pseudo-op with the REP #%00100000 incantation required to set .A to 16 bits.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 16, 2012 3:10 am 
Offline

Joined: Sat Jul 07, 2012 10:46 pm
Posts: 7
So I am now doing the following

Code:
.MACRO CreateWater
GenerateMap:

rep #%00110000 ; Make A and X/Y 16 bit

   ;ldx #$0400
   ;stx $2116
   ;lda #$01
   ;sta $2118

   ldx OffX
   stx $2116
   lda TileCounter
   sta $2118
   
TileSwap:
   inc TileCounter
   lda TileCounter
   cmp #4
   bne MapSwap
   lda #1
   sta TileCounter
   
MapSwap:
   inc OffX
   lda OffX
   cmp #\1 ; This number could be 400 which requires 16 bit
   bne GenerateMap

sep #%00100000 ; When done, set A back to 8 bit

.ENDM

;...
 CreateWater 10


If I take out the rep/sep, my code draws 10 water tiles on the screen.
But if I put A into 16 bit mode, I see garbage on the screen.
Am I not using 16 bit mode correctly? I know that I need to do 2 writes to A when
in 16 bit mode but I am unsure of how to make my macro play nicely with 16 bit numbers.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 16, 2012 3:38 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8545
Location: Southern California
You don't need to write code for two writes of A in 16-bit mode, because STA <addr> for example writes the low byte to <addr> and the high byte to <addr+1>, adding an extra cycle to the instruction to fit both byte writes in. IOW, a single instruction handles both bytes. Remember that INC does that too, so make sure that second byte is part of the variable. Make sure your code is consistent with numbers of bits. When you put A in 16-bit mode, the CMP# and LDA# for example need to have two-byte operands. There may be other such things also that you'll have to keep in agreement on the number of bits.

Edit: If your "inc OffX" is a direct-page addressing mode (is that supposed to be $FF?), then the next byte will be 100, and the 1 in the address offset gets lost. The first byte of the two-byte variable will be DP addr base + FF, and the 2nd (ie, high) byte will be DP addr base + 00, which may not be what you wanted.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 16, 2012 4:41 am 
Offline

Joined: Sat Jul 07, 2012 10:46 pm
Posts: 7
Interesting, I guess not understanding how 16 bit mode works is an issue for me. So you said that I need to use 2 operands when using lda and cmp in 16 bit mode. Does that mean if I want to load 256 into the A register then I should do the following?

lda #$FF, #$01

$FF is the 255 high byte component and the $01 if the low byte component.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 16, 2012 4:55 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8545
Location: Southern California
It'll just be LDA #$1FF. It's a single 2-byte operand.

Edit: Woops, if your really want FF to be the high byte, make it LDA#FF01, and it will lay down A9 01 FF. Is that really what you meant though, or did you want $1FF, ie, 511 in decimal?

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 19 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: