-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy path65816syntax.html
More file actions
2269 lines (1694 loc) · 83.1 KB
/
65816syntax.html
File metadata and controls
2269 lines (1694 loc) · 83.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<html>
<head>
<title>65816 syntax</title>
<link rel="stylesheet" type="text/css" href="./index.css" />
</head>
<body>
<table>
<tr>
<td>
<pre>
A Proposed Assembly Language Syntax For 65c816 Assemblers
by Randall Hyde
This is a proposed standard for 65c816 assembly language. The
proposed standard comes in three levels: subset, full, and extended. The
subset standard is intended for simple (or inexpensive) products,
particularly those aimed at beginning 65c816 assembly language programmers.
The full standard is the focus of this proposal. An assembler meeting the
full level adopts all of the requirements outlined in this paper. The
extended level is a mechanism whereby a vendor can claim full compliance
with the standard and point out that there are extensions as well. An
assembler cannot claim extended level compliance unless it also complies with
the full standard. An assembler, no matter how many extensions are
incorporated, will have to claim subset level unless the full standard is
supported. This ensures that programmers who do not use any assembler
extensions can assemble their programs on any assembler meeting the full or
extended compliance levels.
In addition to the items required for compliance, this proposal
suggests several extensions in the interests of compatibility with existing
65c816 assemblers. These recommendations are not required for full
compliance with the standard, they're included in this proposal as suggestions
to help make conversion of existing programs easier. The suggestions are
presented in two levels: recommended and optional. Recommended items should
be present in any decent 65c816 package. Inclusion of the optional items
is discouraged (since there are other ways to accomplish the same operation
within the confines of the standard) but may be included in the assembler
at the vendor's discretion to help alleviate conversion problems.
65c816 Instruction Mnemonics
----------------------------
All of the following mnemonics are required at the subset, full,
and extended standard levels.
The following mnemonics handle the basic 65c816 instruction set:
ADC - add with carry
AND - logical AND
BCC - branch if carry clear
BCS - branch if carry set
BEQ - branch if equal
BIT - bit test
BMI - branch if minus
BNE - branch if not equal
BPL - branch if plus
BRA - branch always
BRK - break point instruction
BVC - branch if overflow clear
BVS - branch if overflow set
CLC - clear the carry flag
CLD - clear the decimal flag
CLI - clear the interrupt flag
CLP - clear bits in P
CLR - store a zero into memory
CMP - compare accumulator
CPX - compare x register
CPY - compare y register
CSP - call system procedure
DEC - decrement acc or memory
DEX - decrement x register
DEY - decrement y register
EOR - exclusive-or accumulator
HLT - halt (stop) the clock
INC - increment acc or memory
INX - increment x register
INY - increment y register
JMP - jump to new location
JSR - jump to subroutine
LDA - load accumulator
LDX - load x register
LDY - load y register
MVN - block move (decrement)
MVP - block move (increment)
NOP - no operation
ORA - logical or accumulator
PHA - push accumulator
PHP - push p
PHX - push x register
PHY - push y register
PLA - pop accumulator
PLP - pop p
PLX - pop x register
PLY - pop y register
PSH - push operand
PUL - pop operand
RET - return from subroutine
ROL - rotate left acc/mem
ROR - rotate right acc/mem
RTI - return from interrupt
RTL - return from long subroutine
RTS - return from short subroutine
SBC - subtract with carry
SED - set decimal flag
SEI - set interrupt flag
SEP - set bits in P
SHL - shift left acc/mem
SHR - shift right acc/mem
STA - store accumulator
STX - store x register
STY - store y register
SWA - swap accumulator halves
TAD - transfer acc to D
TAS - transfer acc to S
TAX - transfer acc to x
TAY - transfer acc to y
TCB - test and clear bit
TDA - transfer D to acc
TSA - transfer S to acc
TSB - test and set bit
TSX - transfer S to X
TXA - transfer x to acc
TXS - transfer x to S
TXY - transfer x to y
TYA - transfer y to acc
TYX - transfer y to x
WAI - wait for interrupt
XCE - exchange carry with emulation bit
Comments:
CLP replaces REP in the original 65c816 instruction set, since CLP
is a tad more consistent with the original 6502 instruction set. See
"recommended options" for the status of REP. CLR replaces the STZ
instruction. Since STA, STX, and STY are used to store 65c816 registers,
STZ seems to imply that there is a Z register. Using CLR (clear) eliminates
any confusion. CSP (call system procedure) replaces the COP mnemonic. COP
was little more than a software interrupt in both intent and implementation.
CSP helps make this usage a little clearer. HLT replaces the STP mnemonic.
STP, like the STZ mnemonic, implies that the P register is being stored
somewhere. HLT (for halt) is just as obvious as "stop the clock" yet it
doesn't have the same "look and feel" as a store instruction. JML and JSL
are not really required by the new standard; but see recommended options
concerning these two instructions. Most of the new 65c816 push and pull
instructions have been collapsed into two instructions: PSH and PUL.
PEA label becomes PSH #label
PEI (label) becomes PSH label
PER label becomes PSH @label
PHB becomes PSH DBR
PHD becomes PSH D
PHK becomes PSH PBR
PLB becomes PUL DBR
PLD becomes PUL D
These mnemonics are more in line with the original design of the 6502
instruction set whereby the mnemonic specifies the operation and the operand
specifies the addressing mode and address. The RET instruction gets converted
to RTS or RTL, depending on the type of subroutine being declared. RTS and
RTL still exist in order to force a short or long return. SHL and SHR (shift
left and shift right) are used instead of ASL and LSR. The 6500 family has
NEVER supported an arithmetic shift left instruction. The operation performed
by the ASL mnemonic is really a logical shift left. To simplify matters, SHL
and SHR are used to specify shift left and shift right. SWA (swap accumulator
halves) is used instead of XBA. Since this is the only instruction that
references the "B" accumulator, there's no valid reason for even treating
the accumulator as two distinct entities (this is just a carry-over from the
6800 MPU). Likewise, since the eight-bit accumulator cannot be distinguished
from the 16-bit accumulator on an instruction by instruction basis (it depends
on the setting of the M bit in the P register), the accumulator should always
be referred to as A, regardless of whether the CPU is in the eight or sixteen
bit mode. Therefore, instructions like TCD, TCS, TDC, and TSC should be
replaced by TAD, TAS, TDA, and TSA. For more info on these new mnemonics,
see the section on "recommended options".
Built-in Macros
---------------
The following instructions actually generate one or more instructions.
They are not required at the subset level, but are required at the full and
extended levels.
ADD - emits CLC then ADC
BFL - emits BEQ (branch if false)
BGE - emits BCS
BLT - emits BCC
BTR - emits BNE (branch if true)
BSR - emits PER *+2 then BRA (short) or PER *+3 then BRL (long)
SUB - emits SEC then SBC
Recommended Options
-------------------
The following mnemonics are aliases of existing instructions. The
(proposed) standard recommends that the assembler support these mnemonics,
mainly to provide compatibility with older source code, but does not
recommend their use in new programs. Some (or all) of these items may be
removed from the recommended list in future revisions of the standard. None
of these recommended items need be present at the subset level. If these
are the only extensions over and above the full syntax, the assembler
CANNOT claim to be an extended level assembler.
ASL BRL COP JML JSL LSR PEA PEI PER
PHB PHK PHK PLB PLD REP TCD TCS TDC
TSC TRB WDM XBA
Symbols, Constants, and Other Items
-----------------------------------
Symbols may contain any reasonable number of characters at the full
level. At the subset compliance level, at least 16 characters should be
supported and 32 is recommeded. A "reasonable" number of characters should
be at least 64 if the implementor needs a maximum value.
Symbols must begin with an alphabetic character and may contain
(only) the following symbols: A-Z, a-z, 0-9, "_", "$", and "!". The
assembler must be capable of treating upper and lower case alphabetic
characters identically. Note that this does not disallow an assembler from
allowing the programmer to choose that upper and lower case be distinct, it
simply requires that in the default case, upper and lower case characters
are treated identically. Note that the standard does not require case
sensitivity in the assembler (and, in fact, recommends against it).
Therefore, anyone foolish enough (for many, many reasons) to create variables
that differ only in the case of the letters they contain is risking port-
ability problems (as well as maintenence, readability, and other problems).
The following symbols are reserved and may not be redefined within
the program:
A, X, Y, S, DBR, PBR, D, M, P
Nor may these symbol appear as fields to a record or type definition (which
will be described later).
Constants take six different forms: character constants, string
constants, binary constants, decimal constants, hexadecimal constants and
set constants.
Character constants are created by surrounding a single character by
a pair of apostrophes or quotation marks, e.g., "s", "a", '$', and 'p'. If
the character is surrounded by apostrophes, then the ASCII code for that
character WITH THE H.O. BIT CLEAR will be used. If the quotation marks are
used, then the ASCII code for the character WITH THE H.O. BIT SET will be
used. If you need to represent the apostrophe with the H.O. bit clear or a
quotation mark with the H.O. bit set, simply double up the characters, e.g.,
'''' - emits a single apostrophe.
"""" - emits a single quotation mark.
String constants are generated by placing a sequence of two or more
characters within a pair of apostrophes or quotation marks. The choice of
apostrophe or quotation mark controls the H.O. bit, as for character
constants. Likewise, to place an apostrophe or quote within a string
delimited by the same character, just double up the apostrophe or quotation
mark:
'This isn''t bad!' - generates --This isn't bad--
"He said ""Hello""" - generates --He said "Hello"--
Binary integer constants consist of a sequence of 1 through 32 zeros
or ones preceded by a percent sign ("%"). Examples:
%10110010
%001011101
%10
%1100
Decimal integer constants consist of strings of decimal digits without
any preceding characters. E.g., 25, 235, 8325, etc. Decimal constants
may be (optionally) preceded by a minus sign.
Hexadecimal constants consist of a dollar sign ("$") followed by
a string of hexadecimal digits (0..9 and A..F). Values in the range $0
through $FFFFFFFF are allowed.
Set constants are only required at the full and extended compliance
levels. A set constant consists of a list of items surrounded by braces,
e.g., {0,3,5}. For more information, see the .SET directive.
Address Expressions
-------------------
Most instructions and many pseudo-opcode/assembler directives require
operands of some sort. Often these operands contain some sort of address
expression (some, ultimately, numeric or string value). This proposed
standard defines the operands, precision, accuracy, and available operations
that constitutes an address expression.
Precision: all integer expressions are computed using 32 bits. All string
expressions are computed with strings up to 255 characters in length. All
floating point operations are performed using IEEE 80-bit extended floating
point values (i.e., Apple SANE routines). All set operations are performed
using 32 bits of precision.
Accuracy: all integer operations (consisting of two 32-bit operands and an
operator on those operands) must produce the correct result if the actual
result can fit within 32 bits. If an overflow occurs, the value is truncated
and only the low order 32 bits are retained. If an underflow occurs, zero
is used as the result. If an overflow or underflow occurs, a special bit will
be set (until the next value is computed) that can be tested by the ".IFOVR"
and ".IFUNDR" directives. Other than that, such errors are ignored. All
arithmetic is performed using unsigned arithmetic operations. All
floating point operations follow the IEEE (and Apple SANE) suggestions, and
are otherwise ignored by the assembler. Any string operation producing a
string longer than 255 characters produces an assembly time error. All set
operations must be exact.
Integer operations: The following integer operations must be provided at all
compliance levels:
+ (binary) adds the two operands.
- (binary) subracts second operand from the first.
* multiplies the two operands.
/ divides the first operand by the second.
\ divides the first operand by the second and returns the remainder.
& logically ANDs the two operands.
| logically ORs the two operands.
^ logically XORs the two operands.
=
<> These operators compare the two operands (unsigned comparison) and
< return 1 if the comparison is true, 0 otherwise.
>
<=
>=
- (unary) negates (2's complement) the operand
~ (unary) complements (inverts - 1's complement) the operand
The following operators must be provided at the full and extended compliance
levels:
<- shifts the first operand to the left the number of bits specified by the
second operand.
-> shifts the first operand to the right the number of bits specified by the
second operand.
@ (unary) subtracts the location counter at the beginning of the current
statement from the following address expression.
% (ternary, e.g.: X%Y:Z) This operator extracts bits Y through Z from X and
returns that result right justified.
Floating point operations: floating point numbers and operations are required
only at the full and extended levels. The following operations must be
available as well:
+ adds the two operands.
- subtracts the second operand from the first.
* multiplies the two operands.
/ divides the first operand by the second.
- (unary) negates the operand.
=
<> These operators compare the two operands and
< return 1 if the comparison is true, 0 otherwise.
>
<=
>=
String operations: strings and string operations are not required at the
subset level, but the standard recommends their presence. The following
string operations must be provided at the full and extended levels:
+ concatenates two strings
% (ternary, e.g., X%Y:Z) returns the substring composed of the characters in
X starting at position Y of length Z. Generate an error if X doesn't
contain sufficient characters.
=
<> These operators compare the two operands and
< return 1 if the comparison is true, 0 otherwise.
>
<=
>=
Set operations: sets and set operations are required only at the full and
extended levels. The following set operations must be provided:
+ union of two sets (logical OR of the bits).
* intersection of two sets (logical AND of the bits).
- set difference (set one ANDed with the NOT of the second set)
= returns 1 if the two sets are equal, zero otherwise.
<> returns 1 if the two sets are not equal, zero otherwise.
< returns 1 if the first set is a proper subset of the second.
<= returns 1 if the first set is a subset of the second.
> returns 1 if the first set is a proper superset of the second.
>= returns 1 if the first set is a superset of the second.
% (ternary, e.g., X % Y:Z) extracts elements Y..Z from X and returns those
items.
In addition to the above operators, several pre-defined functions are also
available. Note that these functions are not required at the subset
compliance level, only at the full and extended levels:
float(i) - Converts integer "i" to a floating point value.
trunc(r) - Converts real "r" to a 32-bit unsigned integer (or generates an
error).
valid(r) - returns "1" if r is a valid floating point value, 0 otherwise
(for example, if r is NaN, infinity, etc.)
length(s)- returns the length of string s.
lookup(s)- returns "1" if s is a valid symbol in the symbol table.
value(s) - returns value of symbol specified by string "s" in the symbol
table.
type(s) - returns type of symbol "s" in symbol table. Actual values
returned are yet to be defined.
mode(a) - returns the addressing mode of item "a". Used mainly in macros.
STR(s) - returns string s with a prefixed length byte.
ZRO(s) - returns string s with a suffixed zero byte.
DCI(s) - returns string s with the H.O. bit of its last char inverted.
RVS(s) - returns string s with its characters reversed.
FLP(s) - returns string s with its H.O. bits inverted.
IN(v,s) - returns one if value v is in set s, zero otherwise.
The following integer functions must be present at all compliance levels:
LB(i),
LBYTE(i),
BYTE(i) - returns the L.O. byte of i.
HB(i),
HBYTE(i) - returns byte #1 (bits 8-15) of i.
BB(i),
BBYTE(i) - returns bank byte (bits 16-23) of i.
XB,
XBYTE(i) - returns H.O. byte of i.
LW(i),
LWORD(i),
WORD(i) - returns L.O. word of i.
HW(i),
HWORD(i) - returns H.O. word of i.
WORD(i)
Pack(i,j)- returns a 16-bit value whose L.O. byte is the L.O. byte of i and
whose H.O. byte is the L.O. byte of j.
Pack(i,j,k,l)- returns a 32-bit value consisting of (i,j,k,l) where i is the
L.O. byte and l is the H.O. byte. Note: l is optional. If
it isn't present, substitute zero for l.
The order of evaluation for an expression is strictly left to right
unless parentheses are used to modify the precedence of a sub-expression.
Since parentheses are used to specify certain indirect addressing modes, the
use of paretheses to override the strict left-to-right evaluation order
introduces some ambiguity. For example, should the following be treated
as jump indirect through location $1001 or jump directly to location $1001?
JMP ($1000+1)
The ambiguity is resolved as follows: if the parenthesis is the first char-
acter in the operand field, then the indirect addressing mode is assumed.
Otherwise, the parentheses are used to override the left-to-right precedence.
The example above would be treated as a jump indirect through location $1001.
If you wanted to jump directly to location $1001 in this fashion, the state-
ment could be modified to
JMP 0+($1000+1)
so that the parenthesis is no longer the first character in the operand
field.
The use of parentheses to override the left-to-right precedence is
only required at the full and extended compliance levels. It is not
required at the subset compliance level.
Expression Types
----------------
Expressions, in addition to having a value associated with
them, also have a specific type. The three basic types of expressions are
integer, floating point, and string expressions. Integer expressions can
be broken down into subtypes as well. A hierarchical diagram is the easiest
way to describe integer expressions:
integers ------ constants ------------ user defined (enumerated) types
| |
| +----- simple numeric constants
|
|
+-- addresses ------------ direct page addresses
|
+----- absolute addresses --- full 16-bit
| |
| +- relative 8-bit
|
+----- long addresses
This diagram points out that there are two types of integer expres-
sions: constants and addresses. Further, there are two types of constants
and four types of addresses. Before discussion operations on these different
types of integer values, their purpose should be presented.
Until now, most 65xxx assembler did little to differentiate between
the different types of integer values. In this proposed standard, however,
strong type checking is enforced. Whereas in previous assemblers you could
use the following code:
label equ $1000
lda #Label
sta Label
such operations are illegal within the confines of the new standard. The
problem with this short code segment is that the symbol "label" is used as
both an integer constant (in the LDA instruction) and as an address
expression (in the STA instruction). To help prevent logical errors from
creeping into a program, the assembler doesn't allow the use of addresses
where constants are expected and vice versa. To that end, a new assembler
directive, CON, is used to declare constants while EQU is used to declare
an (absolute) address. Symbols declared by CON cannot be (directly) used
as an address. Likewise, symbols declared by EQU (and others) cannot be
used where a constant is expected (such as in an immediate operand).
Although this type checking can be quite useful for locating bugs
within the source file, it can also be a source of major annoyance. Some-
times (quite often, in fact) you may want to treat an address expression
as a constant or a constant expression as an address. Two functions are
used to coerce these expressions to their desired form: PTR and OFS.
PTR(expr) converts the supplied constant expression to an address expression.
OFS(expr) converts the supplied address expression to a constant expression.
The following is perfectly legal:
Cons1 CON $5A
DataLoc EQU $1000
lda #OFS(DataLoc)
sta PTR(Cons1)
For more information, see the section on assembler directives. PTR and OFS
are required at all compliance levels of this proposed standard.
While any constant value may be used anywhere a constant is allowed,
the 65c816 microprocessor must often differentiate between the various types
of address expressions. This is particularly true when emitting code since
the length of an instruction depends on the particular address expression.
If an expression contains only constants, direct page values, absolute
values, or long values, there isn't much of a problem. The assembler uses
the specified type as the addressing mode. If the expression contains mixed
types, the resulting type is as follows:
Expression contains: Result is:
| |
| |
+------------+-- Constants - Constant
| |
+-- Direct | - Direct
|
+--+ Absolute - Absolute
|
+--+- Long - Long
Allowable forms:
constant
direct constant+direct
absolute constant+absolute
long constant+long
absolute+long
constant+absolute+long
This says that if you expression contains only constants, then the
result is a constant. If it contains a mixture of constants and direct
page addresses, the result is a direct page address. Note that direct page
addresses cannot be mixed with other types of addresses. An error must be
reported in this situation (although you could get around it with an
expression of the form "abs+OFS(direct)"). Likewise, adding a constant to
an absolute address produces an absolute address. Adding an absolute and
a long address produces a long address, etc.
Sometimes, you need to force an expression to be a certain type.
For example, the instruction "LDA $200" normally assembles to a load
absolute from location $200 in the current data bank. If you need to force
this to location $200 in bank zero, regardless of the content of the DBR,
the address expression must be coerced to a long address. Coercion of this
type is accomplished with the ":D", ":A", ":L", and ":S" expression suffixes.
To force "LDA $200" to be assembled using the long address mode, the in-
struction is modified to be "LDA $200:L". The coercion suffix must always
follow the full address expression. The ":S" (for short branches) suffix
is never required, since a short branch (for BRA and BSR) is always assumed,
but it is included for completeness. For BRA and BSR, the ":L" suffix is
used to imply a long branch (+/- 32K) rather than the long addressing mode.
Caveats: If ":D" or ":A" is used to coerce a large address expression
to direct or absolute, the high order byte(s) of the expression are truncated
and ignored. The assembler must assume that when a programmer uses these
constructs he knows exactly what he's doing. Therefore, "LDA $1001:D" will
happily assemble this instruction into a "LDA $01" instruction despite the
actual value of the address expression.
Addressing Mode Specification
-----------------------------
65c816 addressing modes are specified by certain symbols in the op-
erand field. A quick rundown follows:
Addressing mode Format(s) Example(s)
--------------- ------------------ ----------------------
Immediate #<expression> LDA #0
=<expression> CMP =LastValue
Direct Page <expression> LDA DPG
<expression>:D LDA ANY:D
Absolute <expression> LDA ABS
<expression>:A LDA ANY:A
Long <expression> LDA LONG
<expression>:L LDA ANY:L
Accumulator {no operand} ASL
INC
Implied {no operand} CLC
SED
Direct, Indirect,
Indexed by Y (<direct expr>),Y LDA (DPG),Y
(<direct expr>).Y LDA (ANY:D).Y
Direct, Indirect,
Indexed by Y, Long [<direct expr>],Y LDA [DPG],Y
[<direct expr>].Y LDA [DPG].Y
Direct, Indexed by X,
Indirect (<direct expr>,X) LDA (DPG,X)
(<direct expr>.X) LDA (ANY:D.X)
Direct, Indexed by X <direct expr>,X LDA DPG,X
<direct expr>.X LDA DPG.X
Direct, Indexed by Y <direct expr>,Y LDX DPG,Y
<direct expr>.Y LDX DPG.Y
Absolute, Indexed by X <abs expr>,X LDA ABS,X
<abs expr>.X LDA ANY:A.X
Long, Indexed by X <long expr>,X LDA ANY:L,X
<long expr>.X LDA LONG.X
Absolute, Indexed by Y <abs expr>,Y LDA ANY:A,Y
<abs expr>.Y LDA ABS.Y
Program Counter
Relative (branches) <expression> BRA ABS
@<expression> BRA @ABS
PC Relative (PSH) @<expression> PSH @ABS
Absolute, Indirect (<abs expr>) JMP (ABS)
Absolute, Indexed,
Indirect (<abs expr>,X) JMP (ABS,X)
(<abs expr>.X) JMP (ABS.X)
Direct, Indirect (<dpg expr>) LDA (DPG)
STA (ANY:D)
Stack Relative <expr8>,S LDA 2,S
<expr8>.S LDA 2.S
Stack Relative,
Indirect, Indexed (<expr8>,S),Y LDA (2,S),Y
(<expr8).S),Y LDA (2.S),y
(<expr8),S).Y LDA (2,S).y
(<expr8).S).Y LDA (2.S).y
Block Move <long expr>,<long expr> MVN LONG,LONG
MVP LONG,LONG
<dpg expr>, DPG- Any direct page expression or symbol.
<abs expr>, ABS- Any absolute expression or symbol.
<long expr>, Long- Any long expression or symbol.
expr8- Any expression evaluating to a value less than
256.
Note: the only real difference between the existing standard and the proposed
standard is that the period (".") can be used to form an indexed address ex-
pression. This is compatible (in practice, as well as philosophy) with the
record structure mechanism supported by this proposed standard. This syntax
for the various addressing modes is required at all compliance levels.
Suggestion: (<dpg expr>):L, (<dpg expr>):L,Y, and (<dpg expr):L.Y
should be allowed as substitutes for [<dpg expr>], [<dpg expr>],Y, and
[<dpg expr].Y, respectively. This, however, is not required by this proposed
standard.
Assembler Directives and Pseudo-Opcodes
---------------------------------------
An assembler directive is a message to the assembler to change some
status or otherwise affect the assembly operation. It does not generate any
object code. A pseudo-opcode, on the other hand, is not a standard 65c816
instruction but does generate object code. Examples of assembler directives
include instructions that turn the listing on or off, define procedures,
equate labels to values, etc. Examples of pseudo-opcodes include instructions
like .BYTE which emit bytes of object code based on the instruction's
parameters.
Equates:
--------
Probably the most important assembler directives are the equates.
The equate directives let you associate a value and a type with a symbol.
The possible equates use the syntax:
<label> .EQU <16-bit value>
<label> .EDP <8-bit value>
<label> .EQL <24-bit value>
<label> .CON <32-bit value>
<label> .FCON <SANE floating point value>
All except .FCON are required at all compliance levels. .FCON is required
at the full and extended levels.
.EQU lets you define a absolute symbol; an address whose value is
relative to the DBR. An error should be generated if the value in the
operand field requires more than 16 bits. The type of the operand expression
is ignored. It may be a constant expression, a direct page expression, or
even a long address expression. As long as it's an integer expression an
can fit into 16 bits, it's quite acceptable.
.EDP (equate to direct page) is used to define direct page symbols.
Again, the operand field may be of any integer type as long as the result
fits into 8 bits. A recommended synonym for .EDP is .EPZ (equate to page
zero) in deference to the 6502's zero page addressing mode.
.EQL (equate long) defines long address expressions. As usual, the
operand field may contain any integer expression that fits within 24 bits.
.CON (constant) is used to define integer numeric constants. Any
32 bit numeric value may be specified in the operand field.
.FCON (floating point constant) is used to declare symbolic floating
point constants. Such constants must be stored in the symbol table as
80-bit SANE extended values.
In addition to the typed equates, this proposed standard also allows
an untyped equate, which takes the form:
<label> = <operand>
where "<operand>" is any valid operand that may appear in the operand field
of any instruction. <operand>'s type may be integer, string, floating point
and may also include an addressing mode. The following are all legal:
lbl = 5
lbl = 5.5
lbl = "Five"
lbl = Array,X
lbl = (dp,s),y
Labels defined by "=" may appear anywhere the operand field specified for
that label is allowed. In general, a simple string substitution should be
performed when a label defined by "=" is used. Note: a label declared by
"=" can be redefined without error throughout the program. The "=" directive
is required only at the full and extended compliance levels.
Data Definitions:
-----------------
While the equates are probably the most important assembler
directives, the data definition instructions are probably the most important
pseudo-opcodes around. These instructions are classed into four groups
determined by the types of operands they accept. In the following paragraphs
all optional items are enclosed within braces.
The first group of data reservation instructions accept any integer
type expression as operands. They are:
{label} .BYTE {expr1, expr2, ..., exprn}
{label} .WORD {expr1, expr2, ..., exprn}
{label} .LONG {expr1, expr2, ..., exprn}
If a label is present, it is treated as a statement label within the current
segment and assigned the value of the location counter before any bytes are
emitted. For the .BYTE opcode, one byte of data is emitted for each operand
in the operand field, that byte being the L.O. byte of each expression.
Operands are purely optional. If no operand appears, then an indeterminate
value is emitted. The .WORD opcodes outputs two bytes for each expression in
the operand field (or two indeterminate bytes if no operand is present). The
.LONG instruction outputs four bytes for each operand. These three pseudo-
opcodes must be present at all compliance levels.
The next group of pseudo-opcodes are used to create tables of
addresses. As such, they only allow symbols that have been defined by
.EQU, .EQL, "=" (as applicable), statement labels, procedure labels, and
segment labels in their operand fields. They are:
{label} .OFFS expr1 {,expr2, ..., exprn}
{label} .ADRS expr1 {,expr2, ..., exprn}
{label} .PTR expr1 {,expr2, ..., exprn}
.OFFS outputs two bytes for each operand; .ADRS outputs three bytes for
each operand; and .PTR outputs four bytes for each operand. These three
pseudo-opcodes are only required at the full and extended compliance levels.
The third group of declarations are used to create constant tables.
As such, they only allow symbols declared by .CON. They are:
{label} .SHORT expr1 {,expr2, ..., exprn}
{label} .INTEGER expr1 {,expr2, ..., exprn}
{label} .LONGINT expr1 {,expr2, ..., exprn}
These pseudo-ops output one, two, and four bytes respectively. These
pseudo-opcodes are not required at the subset compliance level, they are
required only at the full and extended levels.
Note: non-symbolic constants are allowed in any of the above
pseudo-opcodes. Only symbols should have their type information checked.
The last group of data declaration pseudo-opcodes are used to
initialize floating point values. These pseudo-ops are:
{label} .FLOAT {item1, item2, ..., itemn}
{label} .DOUBLE {item1, item2, ..., itemn}
{label} .EXTENDED {item1, item2, ..., itemn}
{label} .COMP {item1, item2, ..., itemn}
each instruction generates operands of 4, 8, 10, or 8 bytes in length,
respectively. If the operand field is left blank, the corresponding bytes
contain an indeterminate value, but the assembler should initialize them to
NaN (not a number). These four pseudo-opcodes are required only at the
full and extended levels.
Although not required by the standard, the following data declaration
directives are recommended and should be supported:
{label} .HBYTE expr1 {,expr2, ..., exprn}
{label} .BBYTE expr1 {,expr2, ..., exprn}
{label} .XBYTE expr1 {,expr2, ..., exprn}
{label} .HWORD expr1 {,expr2, ..., exprn}
the first three reserve one byte of memory for each operand and store the
H.O (bits 8-15), bank (bits 16-23), or extra byte (bits 24-31) respectively.
.HWORD reserves two bytes composed of bits 16-31 for each operand.
Arrays:
-------
Space for arrays and data tables can be reserved using the data
declaration statement mentioned above in conjunction with the "DUP" operator.
DUP is a binary operator that takes the form:
count DUP (list)
where count is some constant value and list is a (possibly empty) list of
values. The items in (list) are repeated "count" times. For example, the
following .BYTE statement reserves space for an array of 64 bytes and
initializes each byte to zero:
MyArray .BYTE 64 DUP (0)
The following statement reserves 256 bytes consisting of the values 1, 2, 3,
4, 5, 6, 7, and 8 repeated 32 times:
MyArray .BYTE 32 DUP (1,2,3,4,5,6,7,8)
The DUP operator is fully recursive. That is, one of the items in
the list may, itself, be a list defined by the DUP operator. For example,
Example .BYTE 16 DUP (0,1,2 DUP (3,4,5))
reserves 128 bytes consisting of the list "0,1,3,4,5,3,4,5" repeated 16 times.
If the DUP list is empty, e.g., "16 dup ()", then exactly one item
is reserved for each entry, but it is not initialized. The following example
reserves space for 128 uninitialized words:
OffsetTable .WORD 128 DUP ()
Type definitions:
-----------------
Enumerated data types can be declared with the ".TYPE" directive.
This directive takes the form:
{label} .TYPE item1 {,item2, ..., itemn}
The items in the list are assigned consecutive values starting from zero.
For example, in the following .TYPE statement, the symbols red, green, and
blue are assigned the values zero, one, and two, respectively:
colors .TYPE red,green,blue
The symbols in the operand field of a .TYPE statement must be unique and
undefined elsewhere (within the current scope, more on that later). The
.TYPE statement above is almost identical to the statements:
red .con 0
green .con 1
blue .con 2
However, there is one major difference. The .TYPE statement also defines a
symbol specified in the label field. This symbol can be used as a pseudo-
opcode to reserve space for values of the specified type. In the example
above, "colors" could be used as a pseudo-opcode to reserve space for the
values red, green, and blue. To differentiate type declarations from other
instructions, a special lead-in character is used. The slash ("/") is
recommended by this standard, but the user should have the option of choosing
this character via a setup program for the assembler. From the example
above, colors could be used as a pseudo-opcode in the following manner:
Christmas /colors red,green
Ocean /colors blue,green
Sky /colors blue
/colors red
Primaries /colors red,blue,green
Unlike other data reserving pseudo-opcodes, a "/colors" definition only
allows symbols that appear in the operand field of the associated .TYPE
statement or one of those symbols in a expression that contains a single
such symbol plus or minus a numeric constant, as long as the result is still
within the range of symbols declared for that type. E.g.,
Okay /colors red,green+1,blue
NotOkay1 /colors blue+2 ;Outside allowable range
NotOkay2 /colors red+blue ;can't add two such symbols
NotOkay3 /colors $25 ;Not red, green, or blue
If you need to coerce an expression to the proper form, simply use the type
name as a pseudo-function. E.g.,
ThisIsOkay /colors colors(0),blue ;Same as red, blue
If the operand is not appropriate, the assembler should generate a warning
and emit the code as though the .BYTE statement were used.
If there isn't a label starting in column one of a .TYPE statement
then the symbols defined in the operand field are applied to the previous
.TYPE statement. This allows you to create .TYPEs where several symbols
(which couldn't possibly fit on a single line) are declared as constants.
E.g.,
colors .TYPE red, yellow, blue
.TYPE orange, green violet
.TYPE brown, black, white
All of these symbols will be associated with "colors". A maximum of 256
symbols can be associated with a symbol via the .TYPE statement. Whenever
the data reservation form is used, exactly one byte is reserved for each