Author Topic: Lesson 01 - fail :(  (Read 8025 times)

0 Members and 1 Guest are viewing this topic.

Offline ChillyWilly

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1751
  • Just a coding machine.
Re: Lesson 01 - fail :(
« Reply #15 on: March 15, 2010, 07:03:52 AM »
This learning ASM business is much slower than I first thought.

You picked the wrong CPU to start with.  ~sm-73.gif~.gif   :D

Offline spinal

  • Coder of DSision
  • Neo MOD
  • Hero Member
  • *
  • Posts: 796
    • spinalcode
Re: Lesson 01 - fail :(
« Reply #16 on: March 15, 2010, 02:48:02 PM »
You picked the wrong CPU to start with.  ~sm-73.gif~.gif   :D

It's not so much about picking a cpu, my only aim was to make a snes game, it just turns out that the only way to do that while being able to get even a small amount of support was asm. And as the snes processor is a 65816, I had little choice but to try to learn it.  ~sm-80.gif~.gif

It looks doubtful that I will have a snes entry in the next contest though.

Offline ~tak

  • Newbie
  • *
  • Posts: 46
Re: Lesson 01 - fail :(
« Reply #17 on: March 15, 2010, 03:03:59 PM »
Quote from: ChillyWilly
You picked the wrong CPU to start with.  ~sm-73.gif~.gif   :D

Confirm! ASM for GBA is much easier and has great documentation (official/unofficial). I'm stuck with simple stuff on SNES which should work however doesn't (yet) :(

Offline mic_

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 632
Re: Lesson 01 - fail :(
« Reply #18 on: March 15, 2010, 04:09:05 PM »
Sure, the ARM is pretty much the best thing since sliced bread for an assembly programmer (except for Thumb which is **** from a coder's point of view. Thumb2 is a lot less awkward).

I'll reiterate my key points about 65816 programming:

1) Make sure that the registers have the widths you expect them to. The assembler may not always be able to figure out what the current registers widths are supposed to be, especially if you set them in function F and then branch to function G. I use REP/SEP frequently to make it clear both to the assembler and myself if I expect the registers to be 8-bit or 16-bit. They only cost 3 cycles so as long as you don't use them inside a loop you're fine. Or you can use the ".8bit"/".16bit" directives in WLA-DX if you prefer that.

2) Make sure that you use the correct addressing mode. If you want long addressing then specify that to the assembler. If an address fits in 16 bits the assembler will probably use word addressing by default and then you need to make sure that DBR points to the bank you expect it to.

Apart from these two points you're basically looking at a 6502 with some improvements.
« Last Edit: March 15, 2010, 04:10:54 PM by mic_ »

Offline ChillyWilly

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1751
  • Just a coding machine.
Re: Lesson 01 - fail :(
« Reply #19 on: March 16, 2010, 01:48:30 AM »
Sure, the ARM is pretty much the best thing since sliced bread for an assembly programmer (except for Thumb which is **** from a coder's point of view. Thumb2 is a lot less awkward).

I'll reiterate my key points about 65816 programming:

1) Make sure that the registers have the widths you expect them to. The assembler may not always be able to figure out what the current registers widths are supposed to be, especially if you set them in function F and then branch to function G. I use REP/SEP frequently to make it clear both to the assembler and myself if I expect the registers to be 8-bit or 16-bit. They only cost 3 cycles so as long as you don't use them inside a loop you're fine. Or you can use the ".8bit"/".16bit" directives in WLA-DX if you prefer that.

2) Make sure that you use the correct addressing mode. If you want long addressing then specify that to the assembler. If an address fits in 16 bits the assembler will probably use word addressing by default and then you need to make sure that DBR points to the bank you expect it to.

Apart from these two points you're basically looking at a 6502 with some improvements.

Yeppers! It's not that I think the 65816 is difficult, it just has more going on that the programmer has to keep track of. That makes it less suitable for a beginner just starting on assembly than another. All the bank selecting in the SNES also contributes to the difficulty. If you want to start on learning, I think a more straightforward CPU on a console with a nice flat map is probably easier. I'm not saying people CAN'T start with the SNES, just that it will require more effort.
 ~sm-78.gif~.gif ~sm-71.gif~.gif ::sm-17.gif::

Offline spinal

  • Coder of DSision
  • Neo MOD
  • Hero Member
  • *
  • Posts: 796
    • spinalcode
Re: Lesson 01 - fail :(
« Reply #20 on: March 16, 2010, 04:04:24 AM »
Time to bug you guys again, I apologise if its this is getting a bit irritating, it seems like you guys have done more work on my game than I have :P

Anyway, I'm stuck again...
Code: [Select]
.MACRO LoadLevel

; BASIC
; For y = 0 to 15
;  For x = 0 to 15
;   A = LevelMaps + 16 * y + x
;   DrawBlock A,x,y
;  Next x
; Next y

   LDY #0 ; Y = 0
  Next_Y:
   LDX #0 ; X = 0
  Next_X:
   STX TX
   STY TY
   LDA LevelMaps + 16*TY + TX ; I hope A = LevelMaps(x + 16 * y)
   DrawBlock,A,TX,TY ; DrawBlock A,X,Y
   INX ; X = X + 1
   CPX #16
    BNE Next_X ; If X != 16 then goto Next_X
   INY ; Y = Y + 1
   CPY #16
    BNE Next_Y ; If Y != 16 then goto Next_Y

.ENDM

Where LevelMaps is -
Code: [Select]
LevelMaps:
.db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $02, $03, $00, $00, $02, $03, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $04, $05, $01, $01, $04, $05, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $01, $00, $00, $10, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $01, $00, $00, $10, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $02, $03, $01, $01, $08, $09, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $04, $05, $00, $00, $06, $07, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
.db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00

I get the following error -

COMPUTE_PENDING_CALCULATIONS: Result (38944/$9820) of a computation is out of range.

The line number is that of
   LDA LevelMaps + 16*TY + TX   ; I hope A = LevelMaps(x + 16 * y)

I assume I'm doing that wrong?

Offline mic_

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 632
Re: Lesson 01 - fail :(
« Reply #21 on: March 16, 2010, 04:47:05 AM »
Quote
LDA LevelMaps + 16*TY + TX   ; I hope A = LevelMaps(x + 16 * y)
TX and TY in this expression will evaluate to whatever TX and TY are defined as. If they are labels then they will evaluate to the addresses of those labels. You can't get the values that those addresses point to in this way.

Assuming A is 8-bit, X and Y are 16-bit and DrawBlocks is working correctly, what you probably want to do is this:

Code: [Select]
.MACRO LoadLevel
  LDY #15 ; Reverse the loop order to simplify the loop
  LDX #255 ; Start with the last byte (16*16 - 1)
Next_Y:
  LDA #15
  STA TX  ; Use TX as a loop counter instead of the X-register
Next_X:
  LDA.L LevelMaps,X
  DrawBlock A,TX,TY
  DEX
  DEC TX
  BPL Next_X  ; Loop while TX >= 0
  DEY
  BPL Next_Y
.ENDM

I still suspect that you need to fix DrawBlock as well. Why would you need to pass A to a macro for example? That will literally pass 'A', not the value that the accumulator happens to contain at the moment.
« Last Edit: March 16, 2010, 04:49:19 AM by mic_ »

Offline spinal

  • Coder of DSision
  • Neo MOD
  • Hero Member
  • *
  • Posts: 796
    • spinalcode
Re: Lesson 01 - fail :(
« Reply #22 on: March 16, 2010, 06:46:30 AM »
So, Am I doing this wrong then?

Code: [Select]
;=== Global Variables ===

.ENUM $00
TX db
TY db
TA db
.ENDE



.MACRO LoadLevel

; BASIC
; For y = 0 to 15
;  For x = 0 to 15
;   A = LevelMaps + 16 * y + x
;   DrawBlock A,x,y
;  Next x
; Next y

  LDY #15 ; Reverse the loop order to simplify the loop
  LDX #255 ; Start with the last byte (16*16 - 1)
Next_Y:
  STY TY
  LDA #15
  STA TX  ; Use TX as a loop counter instead of the X-register
Next_X:
  LDA.L LevelMaps,X
  DrawBlock 1,TX,TY ; 1 to draw tile #1 all over the screen
  DEX
  DEC TX
  BPL Next_X  ; Loop while TX >= 0
  DEY
  BPL Next_Y

.ENDM


.MACRO DrawBlock
; This macro works fine
; e.g. DrawBlock 1,2,3 will draw block#1 at 4,6 on the screen (blocks are 16x16)

LDA #\1 ; A = tile
ASL A ; A << 1 (A = A * 2) (Tiles are 16x16px)

LDX #64*\3 + \2*2 ; X = 32*y+x (tile location)
STA MapBuffer,X ; Map(X) = A
INC A ; A = A + 1
STA MapBuffer+1,X ; Map(X) = A

LDY #$1F ; Y = 32
jump: ; A Lable
INC A ; A = A + 1
DEY ; Y = Y - 1
CPY #$00 ; N 0 - Y
BNE jump ; If N != 0 goto loop
STA MapBuffer+32,X ; Map(X) = A
INC A ; A = A + 1
STA MapBuffer+33,X ; Map(X+1) = A
.ENDM

Offline mic_

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 632
Re: Lesson 01 - fail :(
« Reply #23 on: March 16, 2010, 02:25:20 PM »
Yes, because DrawBlock 1,TX,TY is a macro expansion, which is not the same thing as a function call in a HLL. A macro is kind of like a #define in C. The arguments you pass to it aren't evaluated before being passed - it's simply text replacement.

So with the way you call DrawBlock, the line LDX #64*\3 + \2*2  will become  LDX #64*TY + TX*2 == 64*1 + 0*2 == 64. Remember, this isn't a HLL - complex expressions aren't available. The assembler allows expressions that are constant, i.e. ones that it can evaluate at compile-time. Everything else you'll have to calculate yourself using the correct instruction sequences.


Offline spinal

  • Coder of DSision
  • Neo MOD
  • Hero Member
  • *
  • Posts: 796
    • spinalcode
Re: Lesson 01 - fail :(
« Reply #24 on: March 16, 2010, 02:42:40 PM »
Time to give up I think.

Offline mic_

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 632
Re: Lesson 01 - fail :(
« Reply #25 on: March 16, 2010, 05:20:20 PM »
I think it's a matter of properly understanding the fundamentals of assembly language programming in general, and the ISA of the specific CPU in particular, before trying to use it for a complex project.
The way I got started was by going to the local library and borrowing two books on 80386/486 assembly language programming, and then spending a lot of time trying out different things that I had learned from those books. But that was over 10 years ago and now you've got all kinds of information on the subject available on the internet. For example, "Nerdy Nights" (a NES programming tutorial) could be of help to you, since the 65816 ISA merely is a superset of the 6502 ISA. A few advantages of textbooks are that they often go into more detail than online tutorials; they have usually gone through some form of editing or at least proof-reading; and you won't have to worry that the book just stops abruptly halfway through because the author got tired of writing it.

Offline ChillyWilly

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1751
  • Just a coding machine.
Re: Lesson 01 - fail :(
« Reply #26 on: March 17, 2010, 12:11:41 AM »
Iffen I were you, I'd avoid macros until you understand it better. Just write out ALL the code. That's longer and more work, but much easier to understand if you don't understand how the macros work.