Category:6502 Assembly: Difference between revisions

no edit summary
No edit summary
Line 297:
 
Unfortunately, almost all optimizations in assembly languages are at the expense of readability (probably the biggest reason why assembly isn't used as much these days), and this one is no exception. When programming in 6502 in particular you will find yourself committing all the taboos of modern programming, such as <code>BREAK</code>, <code>GOTO</code>, and sometimes even the dreaded, forbidden, <code>SELF-MODIFYING CODE!</code>
 
 
==Assembler Syntax==
Syntax is mostly dependent on the assembler itself. However, there are a few common standards:
* A numeral with a dollar sign in front <code>$</code> represents a hexadecimal value.
* A numeral with a percent sign in front <code>%</code> represents a binary value.
* A numeral with no <code>$</code> or <code>%</code> in front represents a decimal value.
* A numeral without a <code>#</code> in front is interpreted as a memory address, regardless of whether it is decimal, binary, or hexadecimal. <code>LDA 0</code> will load <i>the value at zero page memory address $00</i> into the accumulator. If you want to load the number 0 into the accumulator you need to type <code>LDA #0</code>.
 
===Value Labels===
Whether a given number is written in binary, hexadecimal, or decimal does not affect the assembled code. The resulting bytecode is the same regardless. For example,
* <code>LDA #$20</code>
* <code>LDA #32</code>
* <code>LDA #%00100000</code>
are all equivalent in the eyes of the assembler. It is best to write a number in the way it is meant to be interpreted for clarity's sake. For example, memory addresses are best written in hexadecimal, and the operand of a bitwise <code>AND</code> should be written in binary, since it is being used to compare individual bits.
 
Labeled values can be defined with a <code>define</code>, <code>=</code> or <code>equ</code> directive. This is useful for communicating the purpose of a zero page variable or constant. However, you must still place a <code>#</code> in front of the label if you wish for it to be interpreted as a constant value rather than a memory address.
<lang 6502asm>tempStorage equ $00 ;intended as a zero page memory address
maxScreenWidth equ $40 ;intended as a constant
 
LDA #maxScreenWidth
STA tempStorage</lang>
All labels <i>must</i> be uniquely named, however you may assign any number of differently named labels to the same value. Labels cannot begin with a number.
 
===Code Labels===
Sections of code can also be given a label. The assembler dereferences the label at compile time to the memory address of the byte just below that label. This is arguably the most powerful feature of assemblers, as it removes the tedium of having to manually update your labels every time you add new code to your source document. Labeled sections of code do not use an <code>equ</code> directive; rather, they typically end in a colon and the actual instruction they point to is underneath. Code labels are useful for naming functions, or being used as a pointer to the beginning of a data table.
 
Like value labels, code labels must be unique. Some assemblers allow the use of local labels, which do not have to be unique throughout the entire program. Local labels often begin with a period or an @, depending on the assembler. A branch or jump to a local label is interpreted as a branch or jump to the closest local label with that name. Often these labels and any code that references them must all be contained between two global labels.
<lang 6502asm>
MyRoutine: ;this label is global. You cannot use the label "MyRoutine" anywhere else in your program
lda tempData
beq .skip
lda #$50
.skip: ;this label is local. You can use ".skip" multiple times, but not in the same function.
sta tempStorage
rts</lang>
 
===Defining Data===
Data can be defined with a <code>db</code> or <code>byte</code> directive for byte-length data or a <code>dw</code> or <code>word</code> directive for word-length (16-bit) data. (Some assemblers require a period before the directive name.) Each entry can be separated by commas or separate lines, each beginning with the appropriate directive. Each entry is placed in the order they are typed, from left to right, up to down. For example, the following data blocks are identical (apart from their labels and memory location), though they look different:
 
<lang 6502asm>
MyData:
db $00,$01,$02,$03
 
MyData2: db $00,$01,$02,$03
 
MyData3:
db $00
db $01
db $02
db $03
 
MyData4:
db $00,$01
db $02,$03</lang>
 
Unlike immediate operands, data does not get a # in front of the value. The values loaded are loaded as immediates regardless.
<lang 6502asm>LDA MyData ;load the value #$00 into the accumulator</lang>
 
Word data is a little different than byte data. Since the 6502 is little-endian, the bytes are stored in reverse order.
<lang 6502asm>WordData:
dw $2000,$3010,$4020
 
EquivalentByteData:
db $00,$20 ;each pair of bytes was stored on its own row for clarity. It makes no difference to the assembler.
db $10,$30
db $20,$40</lang>
 
===Label Arithmetic===
Assemblers offer varying degrees of label arithmetic. The operators +,-,*,or / that are typical in other programming languages can be applied to constants or labels. In addition, most 6502 assemblers offer special operators that are specific to the language. Some assemblers allow the [[C]] standard operators for bitwise operations, bit shifts, etc.
<lang 6502asm>
pointer equ $20
 
LDA #$20+3 ;load #$23 into the accumulator
LDA #$30+$10 ;load #$40 into the accumulator
LDA #$50+20 ;load #$64 into the accumulator (notice the lack of a $ in front of 20)
 
LDA #0-8 ;load #$F8 into the accumulator
LDA #1000/64 ;load decimal 15 into the accumulator. This is valid as long as the entire expression equals 255 or less.
 
LDX #<$3001 ;load #$01 into X (#$01 is the low byte)
LDY #>$0534 ;load #05 into Y (#$05 is the high byte)
 
LDA #<myTable ;load the low byte of the memory address that myTable represents.
sta pointer ;store this into the low byte of a zero page entry named "pointer"
LDA #>myTable ;load the high byte of the memory address that myTable represents.
sta pointer+1 ;store this into the zero page entry immediately after the address of "pointer"
 
LDA (pointer),y ;load the value stored at myTable, offset by positive 5. (Remember we loaded 5 into Y earlier with LDY #>$0534)
;the accumulator now contains #$60.
rts
 
myTable:
db #$10,#$20,#$30,#$40
db #$50,#$60,#$70,#$80</lang>
 
==Citations==
1,489

edits