mirror of
https://github.com/uffejakobsen/acme.git
synced 2024-06-01 13:41:29 +00:00
Compare commits
30 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a5bc7a48bd | ||
|
4901f44fdd | ||
|
d59b45036d | ||
|
88cc8cd886 | ||
|
5b1fabc1f5 | ||
|
beb1e178cd | ||
|
2be25080aa | ||
|
aa8d766e6c | ||
|
b2b14cb176 | ||
|
b03b217979 | ||
|
3db33bafb5 | ||
|
26168e6752 | ||
|
2acece9c60 | ||
|
6dd15f7116 | ||
|
f87ddbb5e6 | ||
|
32d59eafa3 | ||
|
a3d36ca156 | ||
|
78390cb632 | ||
|
465da8c139 | ||
|
62dd48ab9f | ||
|
b8f9bb9d36 | ||
|
ca08a1d150 | ||
|
eb138ae785 | ||
|
70b9ee222d | ||
|
a7dd713d93 | ||
|
a534d9c28a | ||
|
94f36db2e5 | ||
|
21cc635bc8 | ||
|
ecca1552d0 | ||
|
d0c824c60a |
|
@ -1,4 +1,4 @@
|
|||
;ACME 0.96.5
|
||||
;ACME 0.97
|
||||
!set split_cache = [] ; start every pass with an empty cache
|
||||
!ifdef lib_6502_split_a !eof
|
||||
lib_6502_split_a = 1
|
||||
|
|
20
ACME_Lib/cbm/msbstring.a
Normal file
20
ACME_Lib/cbm/msbstring.a
Normal file
|
@ -0,0 +1,20 @@
|
|||
;ACME 0.97
|
||||
|
||||
; macro to store a petscii string with msb set in last byte
|
||||
!macro msbstring @s {
|
||||
!ct pet {
|
||||
@l = len(@s)
|
||||
!if @l < 1 {
|
||||
!error "String is empty!"
|
||||
}
|
||||
!for @i, 0, @l - 1 {
|
||||
!if $80 & @s[@i] {
|
||||
!error "String already contains character(s) with MSB set!"
|
||||
}
|
||||
}
|
||||
!for @i, 0, @l - 2 {
|
||||
!byte @s[@i]
|
||||
}
|
||||
!byte $80 | @s[-1]
|
||||
}
|
||||
}
|
94
ACME_Lib/cbm/multicolor.a
Normal file
94
ACME_Lib/cbm/multicolor.a
Normal file
|
@ -0,0 +1,94 @@
|
|||
;ACME 0.97
|
||||
|
||||
!ifdef lib_cbm_multicolor_a !eof
|
||||
lib_cbm_multicolor_a = 1
|
||||
|
||||
; this file contains macros to convert strings into bit patterns.
|
||||
; the idea is to use four different characters to indicate the four
|
||||
; different bit patterns of multicolor graphics, so mc sprites can be
|
||||
; "drawn" in the source code even though ACME does not support any
|
||||
; four-based number system. see the end of this file for an example.
|
||||
|
||||
; macro to set "digit" characters
|
||||
; example:
|
||||
; +mc_set " .o#"
|
||||
!macro mc_set .s {
|
||||
!if is_number(.s) or is_list(.s) {
|
||||
!error "Argument to +mc_set must be a string."
|
||||
} else if len(.s) != 4 {
|
||||
!error "Argument to +mc_set must be four characters."
|
||||
} else {
|
||||
!set multicolor_alphabet = .s
|
||||
}
|
||||
}
|
||||
|
||||
; macro to convert string to number
|
||||
!macro mc_value ~.result, .in, .len {
|
||||
!ifndef multicolor_alphabet {
|
||||
!error "Called +mc_value before calling +mc_set."
|
||||
} else if is_number(.in) or is_list(.in) {
|
||||
!error "Argument to +mc_value must be a string."
|
||||
} else if len(.in) != .len {
|
||||
!error "Argument to +mc_value must have ", .len, " characters."
|
||||
} else {
|
||||
!set .result = 0
|
||||
!for .idx, 0, (.len / 2) - 1 {
|
||||
!set .char = .in[2 * .idx] ; get first of pair
|
||||
!if .char != .in[2 * .idx + 1] { ; compare to second
|
||||
!error "Characters in argument to +mc_value must be given in pairs."
|
||||
} else {
|
||||
!if .char = multicolor_alphabet[0] {
|
||||
!set .result = (.result << 2)
|
||||
} else if .char = multicolor_alphabet[1] {
|
||||
!set .result = (.result << 2) + 1
|
||||
} else if .char = multicolor_alphabet[2] {
|
||||
!set .result = (.result << 2) + 2
|
||||
} else if .char = multicolor_alphabet[3] {
|
||||
!set .result = (.result << 2) + 3
|
||||
} else {
|
||||
!error "Characters in argument to +mc_value must be from alphabet set via +mc_set."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
; macro for a multicolor byte (for charsets)
|
||||
!macro mc_8 .in {
|
||||
+mc_value ~.result, .in, 8
|
||||
!by .result
|
||||
}
|
||||
|
||||
; macro for a multicolor sprite line
|
||||
!macro mc_be24 .in {
|
||||
+mc_value ~.result, .in, 24
|
||||
!be24 .result
|
||||
}
|
||||
|
||||
!eof
|
||||
; Here's an example on how to use this:
|
||||
!to "mc-sprites.prg", cbm
|
||||
*=$e00
|
||||
+mc_set " .o#" ; set four characters
|
||||
; and now use those four characters to "paint" the sprite:
|
||||
+mc_be24 " "
|
||||
+mc_be24 ".. .."
|
||||
+mc_be24 ".... ...."
|
||||
+mc_be24 "...... ##....## ......"
|
||||
+mc_be24 " .................... "
|
||||
+mc_be24 " .................... "
|
||||
+mc_be24 " ................ "
|
||||
+mc_be24 " ######........###### "
|
||||
+mc_be24 " ..oo####....####oo.. "
|
||||
+mc_be24 "##..oo ######## oo..##"
|
||||
+mc_be24 "....oo oo....oo oo...."
|
||||
+mc_be24 "......oooo....oooo......"
|
||||
+mc_be24 "........................"
|
||||
+mc_be24 "......oooo....oooo......"
|
||||
+mc_be24 "....oooooooooooooooo...."
|
||||
+mc_be24 ".... oooooooooooo ...."
|
||||
+mc_be24 ".. ####oooooooo#### .."
|
||||
+mc_be24 ".. ######oooo###### .."
|
||||
+mc_be24 " ###### #### "
|
||||
+mc_be24 " ###### ## "
|
||||
+mc_be24 " "
|
12
README.md
Normal file
12
README.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# ACME
|
||||
Multi-platform cross-assembler for MOS 6502/65C02/6510/65816 CPUs
|
||||
|
||||
ACME is a free cross assembler released under the GNU GPL.
|
||||
It can produce code for the following processors: 6502, 6510 (including illegal opcodes), 65c02 and 65816.
|
||||
ACME supports the standard assembler stuff like global/local/anonymous labels, offset assembly, conditional assembly and looping assembly. It can include other source files as well as binaries while assembling.
|
||||
Calculations can be done in integer or float mode.
|
||||
Oh, and it is fast.
|
||||
|
||||
Imported from SourceForge SVN repository: https://sourceforge.net/projects/acme-crossass/
|
||||
|
||||
Release tags added - based on SVN commit messages
|
|
@ -8,7 +8,7 @@ If you destroy your system, don't come whining to me.
|
|||
--------------------
|
||||
|
||||
1) Copy the syntax file to the correct directory by typing:
|
||||
cp acme.jsf /etc/joe/syntax/
|
||||
cp acme.jsf /usr/share/joe/syntax/
|
||||
|
||||
2) Add the following lines to the "SECOND SECTION" of "/etc/joe/joerc":
|
||||
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
# new in version 5: changed mnemo colors
|
||||
# new in version 6: added !ifndef, !addr
|
||||
# new in version 7: added !symbollist
|
||||
# new in version 8: adjusted for ACME 0.97
|
||||
# added backslash escaping,
|
||||
# added "//" comments,
|
||||
# added new mnemonics, keywords and pseudo opcodes,
|
||||
# reduced colors for different instruction sets
|
||||
|
||||
# define colors
|
||||
#
|
||||
|
@ -18,16 +23,13 @@
|
|||
=Call bold
|
||||
=Comment green
|
||||
=Constant cyan
|
||||
=Escape bold cyan
|
||||
=Keyword bold
|
||||
=Pseudo bold
|
||||
=Mnemo6502 bold yellow
|
||||
=PCMnemo6502 bold red
|
||||
=Mnemo6510 bg_red bold yellow
|
||||
=PCMnemo6510 bg_red bold red
|
||||
=Mnemo65c02 bg_cyan bold yellow
|
||||
=PCMnemo65c02 bg_cyan bold red
|
||||
=Mnemo65816 bg_blue bold yellow
|
||||
=PCMnemo65816 bg_blue bold red
|
||||
=MnemoExt bg_blue bold yellow
|
||||
=PCMnemoExt bg_blue bold red
|
||||
|
||||
:reset Idle
|
||||
* idle noeat
|
||||
|
@ -36,6 +38,7 @@
|
|||
:idle Idle
|
||||
* idle
|
||||
";" line_comment recolor=-1
|
||||
"//" line_comment recolor=-1
|
||||
":{\n" reset
|
||||
"!.a-zA-Z_€-" checkstring recolor=-1 buffer
|
||||
"+" anonf_or_macro recolor=-1
|
||||
|
@ -101,10 +104,18 @@
|
|||
:string Constant
|
||||
* string
|
||||
"\"" idle
|
||||
"\\" string_escape recolor=-1
|
||||
|
||||
:string_escape Escape
|
||||
* string
|
||||
|
||||
:char Constant
|
||||
* char
|
||||
"'" idle
|
||||
"\\" char_escape recolor=-1
|
||||
|
||||
:char_escape Escape
|
||||
* char
|
||||
|
||||
:ident Idle
|
||||
* idle noeat
|
||||
|
@ -117,10 +128,16 @@
|
|||
"!by" pseudo
|
||||
"!byte" pseudo
|
||||
"!16" pseudo
|
||||
"!le16" pseudo
|
||||
"!be16" pseudo
|
||||
"!wo" pseudo
|
||||
"!word" pseudo
|
||||
"!24" pseudo
|
||||
"!le24" pseudo
|
||||
"!be24" pseudo
|
||||
"!32" pseudo
|
||||
"!le32" pseudo
|
||||
"!be32" pseudo
|
||||
"!tx" pseudo
|
||||
"!text" pseudo
|
||||
"!raw" pseudo
|
||||
|
@ -148,10 +165,17 @@
|
|||
"!set" pseudo
|
||||
"!macro" pseudo
|
||||
"!if" pseudo
|
||||
"!do" pseudo
|
||||
"!for" pseudo
|
||||
"!ifdef" pseudo
|
||||
"!ifndef" pseudo
|
||||
"else" keyword
|
||||
"if" keyword
|
||||
"ifdef" keyword
|
||||
"ifndef" keyword
|
||||
"!for" pseudo
|
||||
"!while" pseudo
|
||||
"!do" pseudo
|
||||
"until" keyword
|
||||
"while" keyword
|
||||
"!al" pseudo
|
||||
"!as" pseudo
|
||||
"!rl" pseudo
|
||||
|
@ -162,6 +186,10 @@
|
|||
"!serious" pseudo
|
||||
"!addr" pseudo
|
||||
"!address" pseudo
|
||||
"!h" pseudo
|
||||
"!hex" pseudo
|
||||
"!xor" pseudo
|
||||
"!skip" pseudo
|
||||
"ora" mnemo6502
|
||||
"asl" mnemo6502
|
||||
"and" mnemo6502
|
||||
|
@ -205,9 +233,9 @@
|
|||
"inx" mnemo6502
|
||||
"nop" mnemo6502
|
||||
"sed" mnemo6502
|
||||
"jsr" mnemo6502
|
||||
"brk" pcmnemo6502
|
||||
"jmp" pcmnemo6502
|
||||
"jsr" pcmnemo6502
|
||||
"bpl" pcmnemo6502
|
||||
"bmi" pcmnemo6502
|
||||
"bvc" pcmnemo6502
|
||||
|
@ -218,61 +246,149 @@
|
|||
"beq" pcmnemo6502
|
||||
"rti" pcmnemo6502
|
||||
"rts" pcmnemo6502
|
||||
"phy" mnemo65c02
|
||||
"ply" mnemo65c02
|
||||
"phx" mnemo65c02
|
||||
"plx" mnemo65c02
|
||||
"tsb" mnemo65c02
|
||||
"trb" mnemo65c02
|
||||
"stz" mnemo65c02
|
||||
"bra" pcmnemo65c02
|
||||
"wai" mnemo65816
|
||||
"pei" mnemo65816
|
||||
"per" mnemo65816
|
||||
"mvp" mnemo65816
|
||||
"mvn" mnemo65816
|
||||
"rep" mnemo65816
|
||||
"sep" mnemo65816
|
||||
"pea" mnemo65816
|
||||
"phd" mnemo65816
|
||||
"tcs" mnemo65816
|
||||
"pld" mnemo65816
|
||||
"tsc" mnemo65816
|
||||
"wdm" mnemo65816
|
||||
"phk" mnemo65816
|
||||
"tcd" mnemo65816
|
||||
"tdc" mnemo65816
|
||||
"phb" mnemo65816
|
||||
"txy" mnemo65816
|
||||
"plb" mnemo65816
|
||||
"tyx" mnemo65816
|
||||
"xba" mnemo65816
|
||||
"xce" mnemo65816
|
||||
"brl" pcmnemo65816
|
||||
"cop" pcmnemo65816
|
||||
"jml" pcmnemo65816
|
||||
"jsl" pcmnemo65816
|
||||
"rtl" pcmnemo65816
|
||||
"stp" pcmnemo65816
|
||||
"slo" mnemo6510
|
||||
"rla" mnemo6510
|
||||
"sre" mnemo6510
|
||||
"rra" mnemo6510
|
||||
"sax" mnemo6510
|
||||
"lax" mnemo6510
|
||||
"dcp" mnemo6510
|
||||
"isc" mnemo6510
|
||||
"anc" mnemo6510
|
||||
"asr" mnemo6510
|
||||
"arr" mnemo6510
|
||||
"sbx" mnemo6510
|
||||
"dop" mnemo6510
|
||||
"top" mnemo6510
|
||||
"lxa" mnemo6510
|
||||
"jam" pcmnemo6510
|
||||
"else" keyword
|
||||
"until" keyword
|
||||
"while" keyword
|
||||
"phy" mnemoExt
|
||||
"ply" mnemoExt
|
||||
"phx" mnemoExt
|
||||
"plx" mnemoExt
|
||||
"tsb" mnemoExt
|
||||
"trb" mnemoExt
|
||||
"stz" mnemoExt
|
||||
"bra" pcmnemoExt
|
||||
"rmb0" mnemoExt
|
||||
"bbr0" mnemoExt
|
||||
"smb0" mnemoExt
|
||||
"bbs0" mnemoExt
|
||||
"rmb1" mnemoExt
|
||||
"bbr1" mnemoExt
|
||||
"smb1" mnemoExt
|
||||
"bbs1" mnemoExt
|
||||
"rmb2" mnemoExt
|
||||
"bbr2" mnemoExt
|
||||
"smb2" mnemoExt
|
||||
"bbs2" mnemoExt
|
||||
"rmb3" mnemoExt
|
||||
"bbr3" mnemoExt
|
||||
"smb3" mnemoExt
|
||||
"bbs3" mnemoExt
|
||||
"rmb4" mnemoExt
|
||||
"bbr4" mnemoExt
|
||||
"smb4" mnemoExt
|
||||
"bbs4" mnemoExt
|
||||
"rmb5" mnemoExt
|
||||
"bbr5" mnemoExt
|
||||
"smb5" mnemoExt
|
||||
"bbs5" mnemoExt
|
||||
"rmb6" mnemoExt
|
||||
"bbr6" mnemoExt
|
||||
"smb6" mnemoExt
|
||||
"bbs6" mnemoExt
|
||||
"rmb7" mnemoExt
|
||||
"bbr7" mnemoExt
|
||||
"smb7" mnemoExt
|
||||
"bbs7" mnemoExt
|
||||
"wai" mnemoExt
|
||||
"pei" mnemoExt
|
||||
"per" mnemoExt
|
||||
"mvp" mnemoExt
|
||||
"mvn" mnemoExt
|
||||
"rep" mnemoExt
|
||||
"sep" mnemoExt
|
||||
"pea" mnemoExt
|
||||
"phd" mnemoExt
|
||||
"tcs" mnemoExt
|
||||
"pld" mnemoExt
|
||||
"tsc" mnemoExt
|
||||
"wdm" mnemoExt
|
||||
"phk" mnemoExt
|
||||
"tcd" mnemoExt
|
||||
"tdc" mnemoExt
|
||||
"phb" mnemoExt
|
||||
"txy" mnemoExt
|
||||
"plb" mnemoExt
|
||||
"tyx" mnemoExt
|
||||
"xba" mnemoExt
|
||||
"xce" mnemoExt
|
||||
"brl" pcmnemoExt
|
||||
"cop" mnemoExt
|
||||
"jml" pcmnemoExt
|
||||
"jsl" mnemoExt
|
||||
"rtl" pcmnemoExt
|
||||
"stp" pcmnemoExt
|
||||
"slo" mnemoExt
|
||||
"rla" mnemoExt
|
||||
"sre" mnemoExt
|
||||
"rra" mnemoExt
|
||||
"sax" mnemoExt
|
||||
"lax" mnemoExt
|
||||
"dcp" mnemoExt
|
||||
"isc" mnemoExt
|
||||
"anc" mnemoExt
|
||||
"ane" mnemoExt
|
||||
"asr" mnemoExt
|
||||
"arr" mnemoExt
|
||||
"alr" mnemoExt
|
||||
"sbx" mnemoExt
|
||||
"sha" mnemoExt
|
||||
"shx" mnemoExt
|
||||
"shy" mnemoExt
|
||||
"las" mnemoExt
|
||||
"tas" mnemoExt
|
||||
"dop" mnemoExt
|
||||
"top" mnemoExt
|
||||
"lxa" mnemoExt
|
||||
"jam" pcmnemoExt
|
||||
"map" mnemoExt
|
||||
"eom" mnemoExt
|
||||
"aug" mnemoExt
|
||||
"sac" mnemoExt
|
||||
"sir" mnemoExt
|
||||
"orq" mnemoExt
|
||||
"aslq" mnemoExt
|
||||
"inq" mnemoExt
|
||||
"bitq" mnemoExt
|
||||
"andq" mnemoExt
|
||||
"rolq" mnemoExt
|
||||
"deq" mnemoExt
|
||||
"asrq" mnemoExt
|
||||
"eorq" mnemoExt
|
||||
"lsrq" mnemoExt
|
||||
"adcq" mnemoExt
|
||||
"rorq" mnemoExt
|
||||
"stq" mnemoExt
|
||||
"ldq" mnemoExt
|
||||
"cpq" mnemoExt
|
||||
"sbcq" mnemoExt
|
||||
"cle" mnemoExt
|
||||
"see" mnemoExt
|
||||
"tsy" mnemoExt
|
||||
"inz" mnemoExt
|
||||
"tys" mnemoExt
|
||||
"dez" mnemoExt
|
||||
"neg" mnemoExt
|
||||
"taz" mnemoExt
|
||||
"tab" mnemoExt
|
||||
"bsr" mnemoExt
|
||||
"tza" mnemoExt
|
||||
"tba" mnemoExt
|
||||
"ldz" mnemoExt
|
||||
"cpz" mnemoExt
|
||||
"dew" mnemoExt
|
||||
"asw" mnemoExt
|
||||
"phz" mnemoExt
|
||||
"inw" mnemoExt
|
||||
"row" mnemoExt
|
||||
"phw" mnemoExt
|
||||
"plz" mnemoExt
|
||||
"lbpl" pcmnemoExt
|
||||
"lbmi" pcmnemoExt
|
||||
"lbvc" pcmnemoExt
|
||||
"lbvs" pcmnemoExt
|
||||
"lbra" pcmnemoExt
|
||||
"lbcc" pcmnemoExt
|
||||
"lbcs" pcmnemoExt
|
||||
"lbne" pcmnemoExt
|
||||
"lbeq" pcmnemoExt
|
||||
"rtn" pcmnemoExt
|
||||
done
|
||||
"!a-zA-Z0-9" checkstring
|
||||
# " \t" idle noeat
|
||||
|
@ -283,17 +399,9 @@ done
|
|||
* idle noeat
|
||||
:pcmnemo6502 PCMnemo6502
|
||||
* idle noeat
|
||||
:mnemo65c02 Mnemo65c02
|
||||
:mnemoExt MnemoExt
|
||||
* idle noeat
|
||||
:pcmnemo65c02 PCMnemo65c02
|
||||
* idle noeat
|
||||
:mnemo65816 Mnemo65816
|
||||
* idle noeat
|
||||
:pcmnemo65816 PCMnemo65816
|
||||
* idle noeat
|
||||
:mnemo6510 Mnemo6510
|
||||
* idle noeat
|
||||
:pcmnemo6510 PCMnemo6510
|
||||
:pcmnemoExt PCMnemoExt
|
||||
* idle noeat
|
||||
:keyword Keyword
|
||||
* idle noeat
|
||||
|
|
|
@ -1,27 +1,22 @@
|
|||
;ACME 0.91 ; comments are green
|
||||
;ACME 0.97 ; comments are green
|
||||
!serious "This file is not meant to be assembled."
|
||||
|
||||
binary1=%00001000 ; label names are grey, constants are cyan
|
||||
binary2=%....#...
|
||||
octal=&0123456789 ; bad constants are bold red
|
||||
decimal=63
|
||||
hex1=0xcd
|
||||
hex2=$ef
|
||||
binary1 = %00001000 ; label names are grey, constants are cyan
|
||||
binary2 = %....#...
|
||||
octal = &0123456789 ; bad constants are bold red
|
||||
decimal = 63
|
||||
hex1 = 0xcd
|
||||
hex2 = $ef
|
||||
!sl "labeldump.l" ; strings are cyan
|
||||
*=$1300
|
||||
* = $1300
|
||||
+dings ; macro calls are bold
|
||||
else ; keyword: bold
|
||||
!eof ; pseudo: bold
|
||||
-- ; anonymous labels should be bold (white)
|
||||
; 6502 mnemonics
|
||||
nop ; normal ones are yellow
|
||||
rts ; PC-changing ones are red
|
||||
; illegals
|
||||
dop ; most of them are yellow on red
|
||||
jam ; this single one's red on red. Guess why.
|
||||
; 65c02 extensions
|
||||
stz ; normal ones are yellow on cyan
|
||||
bra ; PC-changing ones (just "BRA") are red
|
||||
; 65816 extensions
|
||||
xce ; yellow on blue
|
||||
cop ; PC-changing ones are red
|
||||
; base 6502 mnemonics:
|
||||
inx ; normal ones are yellow,
|
||||
beq -- ; all that break sequential flow are red
|
||||
rts
|
||||
; all extended instruction sets:
|
||||
stz ; normal ones are yellow on blue
|
||||
bra ; flow-breaking ones are red
|
||||
|
|
|
@ -12,10 +12,10 @@ ACME.
|
|||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Section: Command aliases for "long" JMPs and JSRs
|
||||
Section: Aliases for "long" JMPs and JSRs
|
||||
----------------------------------------------------------------------
|
||||
|
||||
In addition to the commands JMP and JSR, the 65816 processor also
|
||||
In addition to the mnemonics JMP and JSR, the 65816 processor also
|
||||
knows JML and JSL, which are JMP and JSR using new (long) addressing
|
||||
modes. ACME also accepts the new addressing modes when using the old
|
||||
mnemonics JMP and JSR, but the old addressing modes cannot be used
|
||||
|
@ -55,13 +55,13 @@ this at any time using the following pseudo opcodes:
|
|||
!rs ; switch to short index registers
|
||||
|
||||
Please note that ACME, unlike some other assemblers, does *not* track
|
||||
SEP/REP commands: I don't like that method - it fails when
|
||||
SEP/REP instructions: I don't like that method - it fails when
|
||||
encountering PLPs, for example. So if it doesn't work reliably in the
|
||||
first place, why use it? :)
|
||||
|
||||
If you don't like that you always have to use a pseudo opcode
|
||||
alongside SEP/REP commands, then have a look at the file <65816/std.a>
|
||||
(in the library). There are some predefined macros that you can use.
|
||||
alongside SEP/REP instructions, then have a look at the library file
|
||||
<65816/std.a> which has some predefined macros you can use.
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
|
|
@ -72,6 +72,8 @@ Fix: Characters are now unsigned (had been architecture-dependent).
|
|||
Improved error handling of "--cpu" and "--format" switches.
|
||||
Added opcode table for NMOS6502 cpu to docs.
|
||||
Added some test sources.
|
||||
Added support for "hashbang" lines (if file starts with a '#'
|
||||
character, the first line is ignored)
|
||||
Fixed some minor bugs no-one ever seems to have encountered.
|
||||
Rewritten "docs/Upgrade.txt".
|
||||
|
||||
|
|
102
docs/Errors.txt
102
docs/Errors.txt
|
@ -112,12 +112,12 @@ Label name starts with a shift-space character.
|
|||
warning is issued.
|
||||
|
||||
Memory already initialised.
|
||||
The "!initmem" command was given more than once (or in addition to
|
||||
the "--initmem" command line option). Only use it once.
|
||||
The "!initmem" pseudo opcode was given more than once, or in
|
||||
addition to the "--initmem" command line option. Only use it once.
|
||||
|
||||
Output file already chosen.
|
||||
The "!to" command was given more than once (or in addition to the
|
||||
"--outfile" command line option). Only use it once.
|
||||
The "!to" pseudo opcode was given more than once, or in addition
|
||||
to the "--outfile" command line option. Only use it once.
|
||||
|
||||
Segment reached another one, overwriting it.
|
||||
The program counter has just reached the start of another segment.
|
||||
|
@ -129,7 +129,7 @@ Segment reached another one, overwriting it.
|
|||
ACME this might become the default.
|
||||
|
||||
Segment starts inside another one, overwriting it.
|
||||
The given value in a "*=" command is located inside another
|
||||
The given value in a "*=" assignment is located inside another
|
||||
segment. Because some people might want to assemble "onto" a
|
||||
binary file that was loaded before, this warning can be inhibited
|
||||
using modifier keywords when changing the program counter via
|
||||
|
@ -139,8 +139,8 @@ Segment starts inside another one, overwriting it.
|
|||
ACME this might become the default.
|
||||
|
||||
Symbol list file name already chosen.
|
||||
The "!sl" command was given more than once (or in addition to the
|
||||
"--symbollist" command line option). Only use it once.
|
||||
The "!sl" pseudo opcode was given more than once, or in addition
|
||||
to the "--symbollist" command line option. Only use it once.
|
||||
|
||||
Used "!to" without file format indicator. Defaulting to "cbm".
|
||||
Now that "!to" can be given a file format keyword (either "plain"
|
||||
|
@ -148,19 +148,19 @@ Used "!to" without file format indicator. Defaulting to "cbm".
|
|||
works though.
|
||||
|
||||
Using oversized addressing mode.
|
||||
ACME just assembled a command using an addressing mode that was
|
||||
larger than needed. This only happens if ACME could not work out
|
||||
the argument's value in the first pass, therefore assuming a 16-
|
||||
bit addressing mode. If, in a later pass, ACME finds out that the
|
||||
argument is small enough to fit in 8 bits, then this warning is
|
||||
shown. If you define all your zeropage symbols *before* they are
|
||||
first used, this shouldn't happen. If you know that a specific
|
||||
ACME just assembled an instruction using an addressing mode that
|
||||
was larger than needed. This only happens if ACME could not work
|
||||
out the argument's value in the first pass, therefore assuming a
|
||||
16-bit addressing mode. If, in a later pass, ACME finds out that
|
||||
the argument is small enough to fit in 8 bits, then this warning
|
||||
is shown. If you define all your zeropage symbols *before* they
|
||||
are first used, this shouldn't happen. If you know that a specific
|
||||
argument fits in 8 bits, you can force ACME to use 8 bits
|
||||
addressing by postfixing the command with "+1". Example:
|
||||
addressing by postfixing the mnemonic with "+1". Example:
|
||||
lda+1 label
|
||||
ACME will then use an 8-bit addressing mode, regardless of whether
|
||||
the label is known or not. If the label value happens to be too
|
||||
large to fit in 8 bits, ACME will show an error of course (To
|
||||
large to fit in 8 bits, ACME will show an error of course (to
|
||||
always truncate a value to 8 bits, use the '<' operator).
|
||||
More about the postfixing method can be found in "AddrModes.txt".
|
||||
|
||||
|
@ -233,6 +233,15 @@ Conversion table incomplete.
|
|||
The conversion table file is too small. It needs to be exactly 256
|
||||
bytes in size.
|
||||
|
||||
CPU does not support this addressing mode for this mnemonic.
|
||||
The given mnemonic cannot be combined with the given addressing
|
||||
mode on the CPU you have chosen.
|
||||
|
||||
CPU does not support this postfix for this mnemonic.
|
||||
The given mnemonic cannot be combined with the addressing mode
|
||||
indicated by the given postfix, at least not on the CPU you have
|
||||
chosen.
|
||||
|
||||
Division by zero.
|
||||
Guess what - you attempted to divide by zero.
|
||||
|
||||
|
@ -271,14 +280,6 @@ Hex digits are not given in pairs.
|
|||
The two digits of a hex byte are separated by another character,
|
||||
or there is an odd number of digits.
|
||||
|
||||
Illegal combination of command and addressing mode.
|
||||
The given command cannot be used with the given addressing mode on
|
||||
the CPU you have chosen.
|
||||
|
||||
Illegal combination of command and postfix.
|
||||
The given command cannot be used with the addressing mode
|
||||
indicated by the given postfix.
|
||||
|
||||
Illegal postfix.
|
||||
You used a postfix other than "+1", "+2" or "+3".
|
||||
|
||||
|
@ -317,8 +318,9 @@ Negative value - cannot choose addressing mode.
|
|||
No string given.
|
||||
ACME expects a string but doesn't find it, or the string is empty.
|
||||
|
||||
Number does not fit in N bits.
|
||||
Number out of range.
|
||||
A value is too high or too low.
|
||||
A value is too high or too low to be stored in 8/16/24 bits.
|
||||
This can also mean the desired addressing mode is not available,
|
||||
as in "sty $e000, x".
|
||||
|
||||
|
@ -349,14 +351,19 @@ Syntax error.
|
|||
|
||||
Target not in bank (0xTARGET).
|
||||
You tried to branch to an address not in the 0x0000..0xffff range.
|
||||
Relative addressing (branch commands or PER) cannot leave the
|
||||
Relative addressing (branch instructions or PER) cannot leave the
|
||||
current code bank of 64 KiB.
|
||||
|
||||
Target out of range (N; M too far).
|
||||
Branch commands use relative addressing, which only has a limited
|
||||
range. You exceeded it. N is the attempted offset, M is the
|
||||
difference to the limit - so if you succeed in optimizing M bytes
|
||||
away, the code would assemble.
|
||||
Branch instructions use relative addressing, which only has a
|
||||
limited range. You exceeded it. N is the attempted offset, M is
|
||||
the difference to the limit - so if you succeed in optimizing M
|
||||
bytes away, the code would assemble.
|
||||
|
||||
The chosen CPU uses opcode 0xXY as a prefix code, do not use this mnemonic!
|
||||
The mnemonic is valid, but should not be used on this CPU. If you
|
||||
know better, you can get around this error like this:
|
||||
!cpu ANY_OTHER_CPU { PROBLEMATIC_MNEMONIC }
|
||||
|
||||
There's more than one character.
|
||||
You used a text string containing more than one character in a
|
||||
|
@ -384,7 +391,8 @@ Un-pseudopc operator '&' has no !pseudopc context.
|
|||
around the definition.
|
||||
|
||||
Unknown encoding.
|
||||
You used the "!convtab" command with a keyword ACME does not know.
|
||||
You used the "!convtab" pseudo opcode with a keyword ACME does not
|
||||
know.
|
||||
|
||||
Unknown function.
|
||||
You used a mathematical function ACME does not know.
|
||||
|
@ -393,17 +401,26 @@ Unknown operator.
|
|||
You used an arithmetic/logical operator ACME does not know.
|
||||
|
||||
Unknown output format.
|
||||
You used the "!to" command with a keyword ACME does not know.
|
||||
You used the "!to" pseudo opcode with a format specifier ACME does
|
||||
not know.
|
||||
|
||||
Unknown processor.
|
||||
You used the "!cpu" command with a keyword ACME does not know.
|
||||
You used the "!cpu" pseudo opcode with a cpu specifier ACME does
|
||||
not know.
|
||||
|
||||
Unknown pseudo opcode.
|
||||
You have mistyped a "!" command.
|
||||
You have mistyped the keyword after "!".
|
||||
|
||||
Unknown "*=" segment modifier.
|
||||
You used a modifier keyword ACME does not know.
|
||||
|
||||
Unsupported backslash sequence.
|
||||
The character following the backslash was not one of the allowed
|
||||
ones. Backslash escaping was added in release 0.97 of ACME.
|
||||
If you want to assemble an old source code without first updating
|
||||
it, you can use the "--dialect" CLI switch to make ACME mimic an
|
||||
older version.
|
||||
|
||||
Unterminated index spec.
|
||||
An index was started with '[' but did not end with ']'.
|
||||
|
||||
|
@ -429,8 +446,9 @@ Found end-of-file instead of '}'.
|
|||
(because there was at least one block left open).
|
||||
|
||||
Loop count is negative.
|
||||
You used the "!for" command with a negative loop count (getting
|
||||
this error is only possible when using the now deprecated syntax).
|
||||
You used the "!for" pseudo opcode with a negative loop count
|
||||
(getting this error is only possible when using the now deprecated
|
||||
syntax).
|
||||
|
||||
Macro already defined.
|
||||
Macros can only be defined once. If you define a macro twice, ACME
|
||||
|
@ -440,7 +458,7 @@ Macro already defined.
|
|||
|
||||
Missing '{'.
|
||||
ACME didn't find the expected '{' character. Remember that '{'
|
||||
characters must be given on the same line as the command they
|
||||
characters must be given on the same line as the keyword they
|
||||
belong to.
|
||||
|
||||
Out of memory.
|
||||
|
@ -533,9 +551,15 @@ IllegalImmediateMode
|
|||
The mnemonic tree contains invalid info about the size of immediate
|
||||
arguments.
|
||||
|
||||
IllegalInputSource
|
||||
Input is taken neither from a file nor from a RAM block.
|
||||
|
||||
IllegalNumberTypeX
|
||||
A number was neither INT nor FLOAT nor UNDEFINED.
|
||||
|
||||
IllegalObjectType
|
||||
A symbol is used that is neither number nor list nor string.
|
||||
|
||||
IllegalOperatorId
|
||||
IllegalOperatorGroup
|
||||
The expression parser found an operator that does not exist.
|
||||
|
@ -547,6 +571,7 @@ NotEnoughArgs
|
|||
There was not enough data for a dyadic operator to work on.
|
||||
|
||||
NullTypeObject
|
||||
ObjectHasNullType
|
||||
A symbol is used that does not have a type (number/list/string)
|
||||
associated with it.
|
||||
|
||||
|
@ -558,6 +583,9 @@ OperatorStackNotEmpty
|
|||
The expression parser has finished though there are still
|
||||
operators left to process.
|
||||
|
||||
PartialEscapeSequence
|
||||
Buffered data ended on a backslash, which shouldn't be possible.
|
||||
|
||||
SecondArgIsNotAnInt
|
||||
A sanity check failed: An argument should have been converted to
|
||||
integer but wasn't.
|
||||
|
|
|
@ -69,7 +69,7 @@ The files in the docs directory and what they contain:
|
|||
IMPORTANT: If you upgrade from an earlier version of ACME, don't
|
||||
forget to read the files "Changes.txt" and "Upgrade.txt". Adding new
|
||||
features can not always be done in a 100% compatible way, so newer
|
||||
version may behave slightly different. To solve this problem, the
|
||||
versions may behave slightly differently. To solve this problem, the
|
||||
"--dialect" CLI switch can be used.
|
||||
|
||||
If you want to start using ACME right away, read the file
|
||||
|
|
|
@ -40,7 +40,7 @@ opcodes (mnemonics in parentheses are used by other sources):
|
|||
mnemonic | implied #8 8 8,x 16 16,x | performs:
|
||||
----------------+---------------------------------+-----------------------
|
||||
anc (ana, anb) | 0b* | A = A & arg, then C=N
|
||||
asr (alr) | 4b | A = A & arg, then lsr
|
||||
alr/asr | 4b | A = A & arg, then lsr
|
||||
arr | 6b | A = A & arg, then ror
|
||||
sbx (axs, sax) | cb | X = (A & X) - arg
|
||||
dop (nop, skb) | 80** 80 04 14 | skips next byte
|
||||
|
|
|
@ -213,8 +213,8 @@ Available options are:
|
|||
--vicelabels FILE set file name for label dump in VICE format
|
||||
The resulting file uses a format suited for the VICE emulator.
|
||||
|
||||
--setpc NUMBER set program counter
|
||||
This can also be given in the source code using "* = NUMBER".
|
||||
--setpc VALUE set program counter
|
||||
This can also be given in the source code using "* = VALUE".
|
||||
|
||||
--cpu CPU_TYPE set target processor
|
||||
This can be changed in the source code using the "!cpu" pseudo
|
||||
|
@ -222,7 +222,7 @@ Available options are:
|
|||
Use this with a bogus cpu type to get a list of all supported
|
||||
ones.
|
||||
|
||||
--initmem NUMBER define 'empty' memory
|
||||
--initmem VALUE define 'empty' memory
|
||||
This can also be given using the "!initmem" pseudo opcode.
|
||||
Defaults to zero.
|
||||
|
||||
|
@ -374,9 +374,9 @@ poll_joy2 a global symbol
|
|||
will give the same value four times. I think most
|
||||
assemblers do it this way.
|
||||
|
||||
In older versions of ACME , 'x' and "x" were the same thing, namely
|
||||
the character code of the letter x using the currently selected
|
||||
encoding table.
|
||||
In older versions of ACME, 'x' and "x" were the same thing, namely the
|
||||
character code of the letter x using the currently selected encoding
|
||||
table.
|
||||
Since release 0.97, anything in single quotes gives the character code
|
||||
(as before), while anything in double quotes is treated as a string
|
||||
object. To be compatible to those older versions, ACME keeps accepting
|
||||
|
|
|
@ -163,8 +163,8 @@ The mnemonic BIT can no longer be assembled without any argument. If
|
|||
you want to insert the opcode only to mask the next instruction, use
|
||||
!src <6502/std.a>
|
||||
to get the definitions for these two macros:
|
||||
+bit8 ; output $24 to mask following 1-byte command
|
||||
+bit16 ; output $2c to mask following 2-byte command
|
||||
+bit8 ; output $24 to mask following 1-byte instruction
|
||||
+bit16 ; output $2c to mask following 2-byte instruction
|
||||
|
||||
When using the 65816 cpu, ACME now uses the correct argument order for
|
||||
the MVN and MVP mnemonics, which is:
|
||||
|
|
|
@ -7,11 +7,32 @@
|
|||
--- cpu types ---
|
||||
|
||||
|
||||
ACME supports the following cpu types:
|
||||
ACME supports the following cpu types (shown here as a sort of family
|
||||
tree):
|
||||
|
||||
6502 standard
|
||||
|
|
||||
|\_nmos6502 (=6510) + undocumented opcodes
|
||||
|
|
||||
|\_c64dtv2 + BRA/SAC/SIR and some (not all!) undocumented
|
||||
|
|
||||
\_65c02 + BRA/PHX/PHY/PLX/PLY/STZ/TRB/TSB/...
|
||||
|
|
||||
|\_65816 16 bit regs, 24 bit address space, ...
|
||||
|
|
||||
\_r65c02 + bit manipulation instructions
|
||||
|
|
||||
|\_w65c02 + STP/WAI
|
||||
|
|
||||
\_65ce02 + Z reg, long branches, ...
|
||||
|
|
||||
\_4502 + MAP/EOM
|
||||
|
|
||||
\_m65 + 32-bit pointers, 32-bit 'Q' register
|
||||
|
||||
|
||||
|
||||
*** 6502
|
||||
!cpu 6502
|
||||
|
||||
This is the official instruction set of the original NMOS 6502 CPU
|
||||
designed by MOS (later CSG).
|
||||
|
@ -21,16 +42,34 @@ the mnemonic without any argument: "LSR" will work, "LSR A" won't.
|
|||
|
||||
|
||||
|
||||
*** 6510
|
||||
!cpu nmos6502
|
||||
|
||||
This is the 6502 variant used in the C64 computer. It uses the same
|
||||
instruction set as the 6502, but in addition to that, ACME supports
|
||||
most of the undocumented opcodes as well.
|
||||
This instruction set includes the undocumented ("illegal") opcodes of
|
||||
the NMOS 6502.
|
||||
See "docs/Illegals.txt" for more info.
|
||||
|
||||
|
||||
|
||||
*** 65c02
|
||||
!cpu 6510
|
||||
|
||||
This is an alias for "nmos6502", because the 6510 cpu (as used in the
|
||||
C64 computer) is a variant of this type.
|
||||
|
||||
|
||||
|
||||
!cpu c64dtv2
|
||||
|
||||
This is the cpu in version 2 of the C64DTV. It uses a superset of the
|
||||
6502 instruction set. Features:
|
||||
- new instructions:
|
||||
BRA near_target branch always
|
||||
SAC #$12 set accumulator mapping
|
||||
SIR #$12 set index register mapping
|
||||
- support for some (but not all!) of the undocumented opcodes.
|
||||
|
||||
|
||||
|
||||
!cpu 65c02
|
||||
|
||||
This is the CMOS re-design of the 6502. It seems to have also been
|
||||
available from Rockwell, GTE/CMD and others. Features:
|
||||
|
@ -61,7 +100,21 @@ There are 178 documented opcodes.
|
|||
|
||||
|
||||
|
||||
*** r65c02
|
||||
!cpu 65816
|
||||
|
||||
This is a superset of 65c02, originally designed by WDC (it seems to
|
||||
have been available from GTE/CMD as well). Features:
|
||||
- register sizes can be changed to 16-bit
|
||||
- 24-bit address space
|
||||
- several new instructions (including block transfers)
|
||||
- several new addressing modes for existing instructions
|
||||
There are 256 documented opcodes, but one of them ("WDM") is reserved
|
||||
for future expansion.
|
||||
See "docs/65816.txt" for more info.
|
||||
|
||||
|
||||
|
||||
!cpu r65c02
|
||||
|
||||
This is a superset of 65c02, probably originally by Rockwell. It adds
|
||||
bit manipulation instructions:
|
||||
|
@ -77,7 +130,7 @@ There are 210 documented opcodes.
|
|||
|
||||
|
||||
|
||||
*** w65c02
|
||||
!cpu w65c02
|
||||
|
||||
This is a superset of r65c02, originating at WDC. It adds two new
|
||||
instructions:
|
||||
|
@ -87,21 +140,7 @@ There are 212 documented opcodes.
|
|||
|
||||
|
||||
|
||||
*** 65816
|
||||
|
||||
This is a superset of 65c02, originally designed by WDC (it seems to
|
||||
have been available from GTE/CMD as well). Features:
|
||||
- register sizes can be changed to 16-bit
|
||||
- 24-bit address space
|
||||
- several new instructions (including block transfers)
|
||||
- several new addressing modes for existing instructions
|
||||
There are 256 documented opcodes, but one of them ("WDM") is reserved
|
||||
for future expansion.
|
||||
See "docs/65816.txt" for more info.
|
||||
|
||||
|
||||
|
||||
*** 65ce02
|
||||
!cpu 65ce02
|
||||
|
||||
This is a superset of r65c02, originating at CSG. Features:
|
||||
- Z register
|
||||
|
@ -121,7 +160,7 @@ unconditional") instead. ACME accepts both mnemonics.
|
|||
|
||||
|
||||
|
||||
*** 4502
|
||||
!cpu 4502
|
||||
|
||||
This is basically the same as 65ce02, but
|
||||
- MAP replaces AUG
|
||||
|
@ -131,65 +170,55 @@ There are 256 documented opcodes.
|
|||
|
||||
|
||||
|
||||
*** m65
|
||||
!cpu m65
|
||||
|
||||
This is a superset of 4502 specified by the MEGA65 project. It uses
|
||||
NOP and NEG:NEG as prefix bytes to extend the instruction set.
|
||||
NEG:NEG and NOP as prefix bytes to extend the instruction set.
|
||||
Features:
|
||||
- new "long indirect z-indexed" addressing mode with four-byte-pointer
|
||||
for existing instructions:
|
||||
LDA/STA/ADC/SBC [$12], z ; contents of $12/$13/$14/$15
|
||||
AND/ORA/EOR/CMP [$12], z ; plus z form the address
|
||||
- 32-bit data operations indicated via 'Q' ("quad"):
|
||||
- "quad mode" (32-bit data operations on virtual register 'Q')
|
||||
- "long mode" (32-bit pointer addressing for existing mnemonics)
|
||||
- "quad" and "long" modes can be combined
|
||||
quad mode introduces several new mnemonics:
|
||||
LDQ/STQ/CPQ like LDA/STA/CMP
|
||||
ADCQ/SBCQ like ADC/SBC
|
||||
ANDQ/EORQ/ORQ like AND/EOR/ORA
|
||||
ASLQ/LSRQ/ROLQ/RORQ like ASL/LSR/ROL/ROR
|
||||
INQ/DEQ like INC/DEC
|
||||
The new mnemonics support all the addressing modes of the original
|
||||
mnemonics, except there are no 32-bit immediate arguments.
|
||||
CAUTION: The STQ mnemonic clobbers the N and Z flags!
|
||||
BITQ like BIT
|
||||
ASRQ like ASR
|
||||
The new mnemonics support most of the addressing modes of the
|
||||
original mnemonics with these exceptions:
|
||||
- there is no immediate addressing
|
||||
- indirect-Z-indexed addressing becomes indirect addressing
|
||||
- all other indexed addressing modes can only really be used
|
||||
with read-modify-write instructions or LDQ, because otherwise
|
||||
a part of the 'Q' value would be used as the index.
|
||||
CAUTION: The STQ instruction clobbers the N and Z flags!
|
||||
There is no "real" Q register, instead A/X/Y/Z are combined to form
|
||||
the Q register (A holds lsb, Z holds msb), except for read-modify-
|
||||
write instructions, where the 32-bit operation is performed without
|
||||
using A/X/Y/Z.
|
||||
- The NOP mnemonic is disabled for this instruction set because its
|
||||
opcode is re-used internally as a prefix byte.
|
||||
CAUTION: The !align pseudo opcode still inserts NOPs.
|
||||
|
||||
|
||||
|
||||
*** c64dtv2
|
||||
|
||||
This is the cpu in version 2 of the C64DTV. It uses a superset of the
|
||||
6502 instruction set. Features:
|
||||
- new instructions:
|
||||
BRA near_target branch always
|
||||
SAC #$12 set accumulator mapping
|
||||
SIR #$12 set index register mapping
|
||||
- support for some of the undocumented opcodes.
|
||||
|
||||
|
||||
|
||||
|
||||
Here's a family tree:
|
||||
|
||||
6502 (standard)
|
||||
|
|
||||
|\_6510 (+ undocumented opcodes of nmos6502)
|
||||
|
|
||||
|\_c64dtv2 (+ bra/sac/sir and some undocumented)
|
||||
|
|
||||
\_65c02 (+ bra/phx/phy/plx/ply/stz/trb/tsb, ...)
|
||||
|
|
||||
|\_65816 (16 bit regs, 24 bit address space, ...)
|
||||
|
|
||||
\_r65c02 (+ bit manipulation instructions)
|
||||
|
|
||||
|\_w65c02 (+ stp/wai)
|
||||
|
|
||||
\_65ce02 (+ Z reg, long branches, ...)
|
||||
|
|
||||
\_4502 (+ map/eom)
|
||||
|
|
||||
\_m65 (+ 32-bit pointers, 32-bit data)
|
||||
To load a 32-bit immediate constant into the Q register, use the
|
||||
+movq macro from the <m65/std.a> library file.
|
||||
long mode brings a single new addressing mode for eight mnemonics:
|
||||
LDA [$12], z contents of $12/$13/$14/$15
|
||||
STA [$12], z plus z form the address
|
||||
CMP [$12], z
|
||||
ADC [$12], z
|
||||
SBC [$12], z
|
||||
AND [$12], z
|
||||
EOR [$12], z
|
||||
ORA [$12], z
|
||||
quad and long modes combined result in another addressing mode for
|
||||
eight of the new mnemonics:
|
||||
LDQ [$12] contents of $12/$13/$14/$15
|
||||
STQ [$12] form the address
|
||||
CPQ [$12]
|
||||
ADCQ [$12]
|
||||
SBCQ [$12]
|
||||
ANDQ [$12]
|
||||
EORQ [$12]
|
||||
ORQ [$12]
|
||||
The NOP mnemonic is disabled for this instruction set because its
|
||||
opcode is re-used internally as a prefix byte.
|
||||
CAUTION: The !align pseudo opcode still inserts NOPs.
|
||||
|
|
120
docs/cputypes/cpu m65.txt
Normal file
120
docs/cputypes/cpu m65.txt
Normal file
|
@ -0,0 +1,120 @@
|
|||
|
||||
m65 opcode table(s)
|
||||
|
||||
The m65 instruction set extends the 4502 instruction set using prefix bytes.
|
||||
Therefore, the "normal" opcode table is the same as for the 4502 cpu (see that
|
||||
file), so this file only contains information about the extensions.
|
||||
|
||||
|
||||
"quad mode" allows 32-bit data operations using a virtual register called 'Q'.
|
||||
The mnemonics aslq/lsrq/rolq/rorq/inq/deq have five addressing modes.
|
||||
The mnemonic ldq has eight addressing modes in quad mode, and a ninth when
|
||||
combined with long mode.
|
||||
The mnemonics stq/cpq/adcq/sbcq/andq/eorq/orq have three addressing modes in
|
||||
quad mode, and a fourth when combined with long mode.
|
||||
The mnemonic bitq has two addressing modes.
|
||||
The mnemonic asrq has three addressing modes.
|
||||
This mode is entered after a NEG:NEG (42 42) prefix, the following opcode is
|
||||
then taken from this table:
|
||||
|
||||
00 01 02 03
|
||||
04 05 orq zp 06 aslq zp 07
|
||||
08 09 0a aslq 0b
|
||||
0c 0d orq abs16 0e aslq abs16 0f
|
||||
10 11 12 orq (zp) 13
|
||||
14 15 16 aslq zp, x 17
|
||||
18 19 1a inq 1b
|
||||
1c 1d 1e aslq abs16, x 1f
|
||||
|
||||
20 21 22 23
|
||||
24 bitq zp 25 andq zp 26 rolq zp 27
|
||||
28 29 2a rolq 2b
|
||||
2c bitq abs16 2d andq abs16 2e rolq abs16 2f
|
||||
30 31 32 andq (zp) 33
|
||||
34 35 36 rolq zp, x 37
|
||||
38 39 3a deq 3b
|
||||
3c 3d 3e rolq abs16, x 3f
|
||||
|
||||
40 41 42 43 asrq
|
||||
44 asrq zp 45 eorq zp 46 lsrq zp 47
|
||||
48 49 4a lsrq 4b
|
||||
4c 4d eorq abs16 4e lsrq abs16 4f
|
||||
50 51 52 eorq (zp) 53
|
||||
54 asrq zp, x 55 56 lsrq zp, x 57
|
||||
58 59 5a 5b
|
||||
5c 5d 5e lsrq abs16, x 5f
|
||||
|
||||
60 61 62 63
|
||||
64 65 adcq zp 66 rorq zp 67
|
||||
68 69 6a rorq 6b
|
||||
6c 6d adcq abs16 6e rorq abs16 6f
|
||||
70 71 72 adcq (zp) 73
|
||||
74 75 76 rorq zp, x 77
|
||||
78 79 7a 7b
|
||||
7c 7d 7e rorq abs16, x 7f
|
||||
|
||||
80 81 82 83
|
||||
84 85 stq zp 86 87
|
||||
88 89 8a 8b
|
||||
8c 8d stq abs16 8e 8f
|
||||
90 91 92 stq (zp) 93
|
||||
94 95 96 97
|
||||
98 99 9a 9b
|
||||
9c 9d 9e 9f
|
||||
|
||||
a0 a1 a2 a3
|
||||
a4 a5 ldq zp a6 a7
|
||||
a8 a9 aa ab
|
||||
ac ad ldq abs16 ae af
|
||||
b0 b1 ldq (zp), y b2 ldq (zp) b3
|
||||
b4 b5 ldq zp, x b6 b7
|
||||
b8 b9 ldq abs16, y ba bb
|
||||
bc bd ldq abs16, x be bf
|
||||
|
||||
c0 c1 c2 c3
|
||||
c4 c5 cpq zp c6 deq zp c7
|
||||
c8 c9 ca cb
|
||||
cc cd cpq abs16 ce deq abs16 cf
|
||||
d0 d1 d2 cpq (zp) d3
|
||||
d4 d5 d6 deq zp, x d7
|
||||
d8 d9 da db
|
||||
dc dd de deq abs16, x df
|
||||
|
||||
e0 e1 e2 ldq (zp, s), y e3
|
||||
e4 e5 sbcq zp e6 inq zp e7
|
||||
e8 e9 ea eb
|
||||
ec ed sbcq abs16 ee inq abs16 ef
|
||||
f0 f1 f2 sbcq (zp) f3
|
||||
f4 f5 f6 inq zp, x f7
|
||||
f8 f9 fa fb
|
||||
fc fd fe inq abs16, x ff
|
||||
|
||||
zp: 8-bit zeropage address
|
||||
abs16: 16-bit absolute address
|
||||
|
||||
|
||||
"long mode" adds an addressing mode using 32-bit pointers for eight existing
|
||||
mnemonics. This mode is entered after a NOP (ea) prefix, the following opcode
|
||||
should then be one of these:
|
||||
|
||||
12 ora [zp], z 32 and [zp], z 52 eor [zp], z 72 adc [zp], z
|
||||
92 sta [zp], z b2 lda [zp], z d2 cmp [zp], z f2 sbc [zp], z
|
||||
|
||||
|
||||
"quad" and "long" modes can be combined to have 32-bit data access using a
|
||||
32-bit pointer. This adds another addressing mode for eight of the new
|
||||
mnemonics. This mode is entered after a NEG:NEG:NOP (42 42 ea) prefix, the
|
||||
following opcode should then be one of these:
|
||||
|
||||
12 orq [zp] 32 andq [zp] 52 eorq [zp] 72 adcq [zp]
|
||||
92 stq [zp] b2 ldq [zp] d2 cpq [zp] f2 sbcq [zp]
|
||||
|
||||
|
||||
Because the addressing modes are changed a bit by the prefix codes, here are
|
||||
some of the unsupported combinations just for comparison (these result in
|
||||
"Illegal combination of command and addressing mode"):
|
||||
lda (zp) ; 65c02 knew this, but 65ce02 added z index!
|
||||
lda [zp] ; long mode also expects z index!
|
||||
ldq #imm ; quad mode has no immediate addressing!
|
||||
ldq (zp), z ; quad mode does not use z index!
|
||||
ldq [zp], z ; quad and long modes combined do not use z index!
|
|
@ -27,7 +27,7 @@ marked using '+' or '!' signs:
|
|||
|
||||
40 rti 41 eor (zp, x) 42! jam 43+ sre (zp, x)
|
||||
44! nop zp 45 eor zp 46 lsr zp 47+ sre zp
|
||||
48 pha 49 eor #imm8 4a lsr 4b+ asr #imm8
|
||||
48 pha 49 eor #imm8 4a lsr 4b+ alr #imm8
|
||||
4c jmp abs16 4d eor abs16 4e lsr abs16 4f+ sre abs16
|
||||
50 bvc rel8 51 eor (zp), y 52! jam 53+ sre (zp), y
|
||||
54! nop zp, x 55 eor zp, x 56 lsr zp, x 57+ sre zp, x
|
||||
|
|
|
@ -32,7 +32,7 @@ encoding.o: config.h alu.h acme.h dynabuf.h global.h output.h input.h tree.h enc
|
|||
|
||||
flow.o: config.h acme.h alu.h dynabuf.h global.h input.h mnemo.h symbol.h tree.h flow.h flow.c
|
||||
|
||||
global.o: config.h platform.h acme.h cpu.h encoding.h input.h macro.h pseudoopcodes.h section.h symbol.h global.h global.c
|
||||
global.o: config.h platform.h acme.h cpu.h dynabuf.h encoding.h input.h macro.h pseudoopcodes.h section.h symbol.h global.h global.c
|
||||
|
||||
input.o: config.h alu.h dynabuf.h global.h section.h symbol.h tree.h input.h input.c
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ encoding.o: config.h alu.h acme.h dynabuf.h global.h output.h input.h tree.h enc
|
|||
|
||||
flow.o: config.h acme.h alu.h dynabuf.h global.h input.h mnemo.h symbol.h tree.h flow.h flow.c
|
||||
|
||||
global.o: config.h platform.h acme.h cpu.h encoding.h input.h macro.h pseudoopcodes.h section.h symbol.h global.h global.c
|
||||
global.o: config.h platform.h acme.h cpu.h dynabuf.h encoding.h input.h macro.h pseudoopcodes.h section.h symbol.h global.h global.c
|
||||
|
||||
input.o: config.h alu.h dynabuf.h global.h section.h symbol.h tree.h input.h input.c
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ encoding.o: config.h alu.h acme.h dynabuf.h global.h output.h input.h tree.h enc
|
|||
|
||||
flow.o: config.h acme.h alu.h dynabuf.h global.h input.h mnemo.h symbol.h tree.h flow.h flow.c
|
||||
|
||||
global.o: config.h platform.h acme.h cpu.h encoding.h input.h macro.h pseudoopcodes.h section.h symbol.h global.h global.c
|
||||
global.o: config.h platform.h acme.h cpu.h dynabuf.h encoding.h input.h macro.h pseudoopcodes.h section.h symbol.h global.h global.c
|
||||
|
||||
input.o: config.h alu.h dynabuf.h global.h section.h symbol.h tree.h input.h input.c
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
CFLAGS = -O3 -mthrowback -mlibscl -Wall -Wstrict-prototypes
|
||||
LINKFLAGS = -mlibscl -Wall
|
||||
LIBS = -lm
|
||||
CC = gcc
|
||||
RM = rm
|
||||
|
@ -13,7 +14,7 @@ OBJS = acme.o alu.o cliargs.o cpu.o dynabuf.o encoding.o flow.o global.o input.
|
|||
all: $(PROGS)
|
||||
|
||||
acme: $(OBJS)
|
||||
$(CC) $(CFLAGS) -o !Unsqueezed $(OBJS) $(LIBS)
|
||||
$(CC) $(LINKFLAGS) -o !Unsqueezed $(OBJS) $(LIBS)
|
||||
Squeeze -f -v !Unsqueezed !ACME.!RunImage
|
||||
|
||||
acme.o: config.h platform.h acme.h alu.h cpu.h dynabuf.h encoding.h flow.h global.h input.h macro.h mnemo.h output.h pseudoopcodes.h section.h symbol.h version.h acme.h acme.c
|
||||
|
@ -30,7 +31,7 @@ encoding.o: config.h alu.h acme.h dynabuf.h global.h output.h input.h tree.h enc
|
|||
|
||||
flow.o: config.h acme.h alu.h dynabuf.h global.h input.h mnemo.h symbol.h tree.h flow.h flow.c
|
||||
|
||||
global.o: config.h platform.h acme.h cpu.h encoding.h input.h macro.h pseudoopcodes.h section.h symbol.h global.h global.c
|
||||
global.o: config.h platform.h acme.h cpu.h dynabuf.h encoding.h input.h macro.h pseudoopcodes.h section.h symbol.h global.h global.c
|
||||
|
||||
input.o: config.h alu.h dynabuf.h global.h section.h symbol.h tree.h input.h input.c
|
||||
|
||||
|
|
23
src/acme.c
23
src/acme.c
|
@ -129,9 +129,9 @@ static void show_help_and_exit(void)
|
|||
" -l, --" OPTION_SYMBOLLIST " FILE set symbol list file name\n"
|
||||
" --" OPTION_LABELDUMP " (old name for --" OPTION_SYMBOLLIST ")\n"
|
||||
" --" OPTION_VICELABELS " FILE set file name for label dump in VICE format\n"
|
||||
" --" OPTION_SETPC " NUMBER set program counter\n"
|
||||
" --" OPTION_SETPC " VALUE set program counter\n"
|
||||
" --" OPTION_CPU " CPU set target processor\n"
|
||||
" --" OPTION_INITMEM " NUMBER define 'empty' memory\n"
|
||||
" --" OPTION_INITMEM " VALUE define 'empty' memory\n"
|
||||
" --" OPTION_MAXERRORS " NUMBER set number of errors before exiting\n"
|
||||
" --" OPTION_MAXDEPTH " NUMBER set recursion depth for macro calls and !src\n"
|
||||
" --" OPTION_IGNORE_ZEROES " do not determine number size by leading zeroes\n"
|
||||
|
@ -422,6 +422,7 @@ static void set_starting_pc(const char expression[])
|
|||
start_address = string_to_number(expression);
|
||||
if ((start_address > -1) && (start_address < 65536))
|
||||
return;
|
||||
|
||||
fprintf(stderr, "%sProgram counter out of range (0-0xffff).\n", cliargs_error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -433,6 +434,7 @@ static void set_mem_contents(const char expression[])
|
|||
fill_value = string_to_number(expression);
|
||||
if ((fill_value >= -128) && (fill_value <= 255))
|
||||
return;
|
||||
|
||||
fprintf(stderr, "%sInitmem value out of range (0-0xff).\n", cliargs_error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -637,24 +639,15 @@ int main(int argc, const char *argv[])
|
|||
if (argc == 1)
|
||||
show_help_and_exit();
|
||||
cliargs_init(argc, argv);
|
||||
DynaBuf_init(); // inits *global* dynamic buffer - important, so first
|
||||
// Init platform-specific stuff.
|
||||
// For example, this could read the library path from an
|
||||
// environment variable, which in turn may need DynaBuf already.
|
||||
// init platform-specific stuff.
|
||||
// this may read the library path from an environment variable.
|
||||
PLATFORM_INIT;
|
||||
// prepare a buffer large enough to hold pointers to "-D" switch values
|
||||
// cli_defines = safe_malloc(argc * sizeof(*cli_defines));
|
||||
includepaths_init(); // must be done before cli arg handling
|
||||
// handle command line arguments
|
||||
cliargs_handle_options(short_option, long_option);
|
||||
// generate list of files to process
|
||||
cliargs_get_rest(&toplevel_src_count, &toplevel_sources, "No top level sources given");
|
||||
// Init modules (most of them will just build keyword trees)
|
||||
ALU_init();
|
||||
Macro_init();
|
||||
Mnemo_init();
|
||||
Output_init(fill_value);
|
||||
pseudoopcodes_init(); // setup keyword tree for pseudo opcodes
|
||||
// init output buffer
|
||||
Output_init(fill_value, config.test_new_features);
|
||||
if (do_actual_work())
|
||||
save_output_file();
|
||||
return ACME_finalize(EXIT_SUCCESS); // dump labels, if wanted
|
||||
|
|
57
src/alu.c
57
src/alu.c
|
@ -35,8 +35,8 @@
|
|||
|
||||
// constants
|
||||
|
||||
#define ERRORMSG_DYNABUF_INITIALSIZE 256 // ad hoc
|
||||
#define FUNCTION_DYNABUF_INITIALSIZE 8 // enough for "arctan"
|
||||
#define ERRORMSG_INITIALSIZE 256 // ad hoc
|
||||
#define FUNCTION_INITIALSIZE 8 // enough for "arctan"
|
||||
#define HALF_INITIAL_STACK_SIZE 8
|
||||
static const char exception_div_by_zero[] = "Division by zero.";
|
||||
static const char exception_no_value[] = "No value given.";
|
||||
|
@ -167,8 +167,8 @@ static struct op ops_isstring = {42, OPGROUP_MONADIC, OPID_ISSTRING, "is_string
|
|||
|
||||
|
||||
// variables
|
||||
static struct dynabuf *errormsg_dyna_buf; // dynamic buffer to build variable-length error messages
|
||||
static struct dynabuf *function_dyna_buf; // dynamic buffer for fn names
|
||||
static STRUCT_DYNABUF_REF(errormsg_dyna_buf, ERRORMSG_INITIALSIZE); // to build variable-length error messages
|
||||
static STRUCT_DYNABUF_REF(function_dyna_buf, FUNCTION_INITIALSIZE); // for fn names
|
||||
// operator stack, current size and stack pointer:
|
||||
static struct op **op_stack = NULL;
|
||||
static int opstack_size = HALF_INITIAL_STACK_SIZE;
|
||||
|
@ -186,22 +186,22 @@ enum alu_state {
|
|||
};
|
||||
static enum alu_state alu_state; // deterministic finite automaton
|
||||
// predefined stuff
|
||||
static struct ronode *op_tree = NULL; // tree to hold operators
|
||||
static struct ronode op_list[] = {
|
||||
PREDEFNODE(s_asr, &ops_asr),
|
||||
PREDEFNODE(s_lsr, &ops_lsr),
|
||||
PREDEFNODE(s_asl, &ops_shift_left),
|
||||
static struct ronode op_tree[] = {
|
||||
PREDEF_START,
|
||||
PREDEFNODE("asr", &ops_asr),
|
||||
PREDEFNODE("lsr", &ops_lsr),
|
||||
PREDEFNODE("asl", &ops_shift_left),
|
||||
PREDEFNODE("lsl", &ops_shift_left),
|
||||
PREDEFNODE("div", &ops_intdiv),
|
||||
PREDEFNODE("mod", &ops_modulo),
|
||||
PREDEFNODE(s_and, &ops_and),
|
||||
PREDEFNODE("and", &ops_and),
|
||||
PREDEFNODE("or", &ops_or),
|
||||
PREDEFNODE(s_eor, &ops_eor), // FIXME - remove
|
||||
PREDEFLAST("xor", &ops_xor),
|
||||
PREDEFNODE("eor", &ops_eor), // FIXME - remove
|
||||
PREDEF_END("xor", &ops_xor),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
static struct ronode *function_tree = NULL; // tree to hold functions
|
||||
static struct ronode function_list[] = {
|
||||
static struct ronode function_tree[] = {
|
||||
PREDEF_START,
|
||||
PREDEFNODE("addr", &ops_addr),
|
||||
PREDEFNODE("address", &ops_addr),
|
||||
PREDEFNODE("int", &ops_int),
|
||||
|
@ -215,7 +215,7 @@ static struct ronode function_list[] = {
|
|||
PREDEFNODE("arctan", &ops_arctan),
|
||||
PREDEFNODE("sin", &ops_sin),
|
||||
PREDEFNODE("cos", &ops_cos),
|
||||
PREDEFLAST("tan", &ops_tan),
|
||||
PREDEF_END("tan", &ops_tan),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
|
@ -248,6 +248,7 @@ do { \
|
|||
static void enlarge_operator_stack(void)
|
||||
{
|
||||
opstack_size *= 2;
|
||||
//printf("Doubling op stack size to %d.\n", opstack_size);
|
||||
op_stack = realloc(op_stack, opstack_size * sizeof(*op_stack));
|
||||
if (op_stack == NULL)
|
||||
Throw_serious_error(exception_no_memory_left);
|
||||
|
@ -258,24 +259,13 @@ static void enlarge_operator_stack(void)
|
|||
static void enlarge_argument_stack(void)
|
||||
{
|
||||
argstack_size *= 2;
|
||||
//printf("Doubling arg stack size to %d.\n", argstack_size);
|
||||
arg_stack = realloc(arg_stack, argstack_size * sizeof(*arg_stack));
|
||||
if (arg_stack == NULL)
|
||||
Throw_serious_error(exception_no_memory_left);
|
||||
}
|
||||
|
||||
|
||||
// create dynamic buffer, operator/function trees and operator/argument stacks
|
||||
void ALU_init(void)
|
||||
{
|
||||
errormsg_dyna_buf = DynaBuf_create(ERRORMSG_DYNABUF_INITIALSIZE);
|
||||
function_dyna_buf = DynaBuf_create(FUNCTION_DYNABUF_INITIALSIZE);
|
||||
Tree_add_table(&op_tree, op_list);
|
||||
Tree_add_table(&function_tree, function_list);
|
||||
enlarge_operator_stack();
|
||||
enlarge_argument_stack();
|
||||
}
|
||||
|
||||
|
||||
// not-so-braindead algorithm for calculating "to the power of" function for
|
||||
// integer arguments.
|
||||
// my_pow(whatever, 0) returns 1.
|
||||
|
@ -2378,6 +2368,12 @@ static int parse_expression(struct expression *expression)
|
|||
{
|
||||
struct object *result = &expression->result;
|
||||
|
||||
// make sure stacks are ready (if not yet initialised, do it now)
|
||||
if (arg_stack == NULL)
|
||||
enlarge_argument_stack();
|
||||
if (op_stack == NULL)
|
||||
enlarge_operator_stack();
|
||||
|
||||
// init
|
||||
expression->is_empty = TRUE; // becomes FALSE when first valid char gets parsed
|
||||
expression->open_parentheses = 0;
|
||||
|
@ -2390,9 +2386,10 @@ static int parse_expression(struct expression *expression)
|
|||
PUSH_OP(&ops_start_expression);
|
||||
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
|
||||
do {
|
||||
// check stack sizes. enlarge if needed
|
||||
// check arg stack size. enlarge if needed
|
||||
if (arg_sp >= argstack_size)
|
||||
enlarge_argument_stack();
|
||||
// (op stack size is checked whenever pushing an operator)
|
||||
switch (alu_state) {
|
||||
case STATE_EXPECT_ARG_OR_MONADIC_OP:
|
||||
if (expect_argument_or_monadic_operator(expression))
|
||||
|
@ -2445,8 +2442,8 @@ static int parse_expression(struct expression *expression)
|
|||
// make sure no additional (spurious) errors are reported:
|
||||
Input_skip_remainder();
|
||||
// FIXME - remove this when new function interface gets used:
|
||||
// callers must decide for themselves what to do when expression parser returns error
|
||||
// (currently LDA'' results in both "no string given" AND "illegal combination of command and addressing mode"!)
|
||||
// callers must decide for themselves what to do when expression
|
||||
// parser returns error (and may decide to call Input_skip_remainder)
|
||||
return 1; // error
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,19 +50,16 @@ struct expression {
|
|||
// labels that are undefined, we can't simply get the addressing mode
|
||||
// from looking at the parameter's value. FIXME - rename to TAINTED :)
|
||||
|
||||
|
||||
// create dynamic buffer, operator/function trees and operator/operand stacks
|
||||
extern void ALU_init(void);
|
||||
|
||||
/*
|
||||
// FIXME - replace all the functions below with a single one using a "flags" arg!
|
||||
// its return value would then be "error"/"ok".
|
||||
// input flags:
|
||||
#define ACCEPT_UNDEFINED (1u << 0) // if not given, undefined throws serious error
|
||||
#define ACCEPT_INT (1u << 1) needed when strings come along!
|
||||
#define ACCEPT_INT (1u << 1)
|
||||
#define ACCEPT_FLOAT (1u << 2) // if not given, floats are converted to integer
|
||||
#define ACCEPT_OPENPARENTHESIS (1u << 3) // if not given, throws syntax error
|
||||
//#define ACCEPT_STRING
|
||||
#define ACCEPT_STRING (1u << 4) // if not given, convert 1-char strings to int?
|
||||
#define ACCEPT_LIST (1u << 5)
|
||||
// do I need ACCEPT_NONADDR and/or ACCEPT_ADDRESS?
|
||||
*/
|
||||
|
||||
|
|
|
@ -71,8 +71,8 @@ static struct cpu_type cpu_type_m65 = {
|
|||
// variables
|
||||
|
||||
// predefined stuff
|
||||
static struct ronode *cputype_tree = NULL;
|
||||
static struct ronode cputype_list[] = {
|
||||
static struct ronode cputype_tree[] = {
|
||||
PREDEF_START,
|
||||
#define KNOWN_TYPES "'6502', 'nmos6502', '6510', '65c02', 'r65c02', 'w65c02', '65816', '65ce02', '4502', 'm65', 'c64dtv2'" // shown in CLI error message for unknown types
|
||||
// PREDEFNODE("z80", &cpu_type_Z80),
|
||||
PREDEFNODE("6502", &cpu_type_6502),
|
||||
|
@ -85,7 +85,7 @@ static struct ronode cputype_list[] = {
|
|||
PREDEFNODE("65ce02", &cpu_type_65ce02),
|
||||
PREDEFNODE("4502", &cpu_type_4502),
|
||||
PREDEFNODE("m65", &cpu_type_m65),
|
||||
PREDEFLAST("c64dtv2", &cpu_type_c64dtv2),
|
||||
PREDEF_END("c64dtv2", &cpu_type_c64dtv2),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
const char cputype_names[] = KNOWN_TYPES; // string to show if cputype_find() returns NULL
|
||||
|
@ -95,9 +95,6 @@ const struct cpu_type *cputype_find(void)
|
|||
{
|
||||
void *node_body;
|
||||
|
||||
// make sure tree is initialised
|
||||
if (cputype_tree == NULL)
|
||||
Tree_add_table(&cputype_tree, cputype_list);
|
||||
// perform lookup
|
||||
if (!Tree_easy_scan(cputype_tree, &node_body, GlobalDynaBuf))
|
||||
return NULL;
|
||||
|
|
|
@ -21,10 +21,12 @@
|
|||
// initial size for global dynabuf
|
||||
// (as it holds macros, loop bodies, etc., make it large to begin with)
|
||||
#define GLOBALDYNABUF_INITIALSIZE 1024 // should be >0 (see above)
|
||||
// TODO - get rid of this, or move to global.c
|
||||
|
||||
|
||||
// Variables
|
||||
struct dynabuf *GlobalDynaBuf; // global dynamic buffer
|
||||
STRUCT_DYNABUF_REF(GlobalDynaBuf, GLOBALDYNABUF_INITIALSIZE); // global dynamic buffer
|
||||
// TODO - get rid of this, or move to global.c
|
||||
|
||||
|
||||
// Functions
|
||||
|
@ -34,37 +36,42 @@ static void resize(struct dynabuf *db, size_t new_size)
|
|||
{
|
||||
char *new_buf;
|
||||
|
||||
//printf("Growing dynabuf to size %d.\n", new_size);
|
||||
new_buf = realloc(db->buffer, new_size);
|
||||
if (new_buf == NULL)
|
||||
Throw_serious_error(exception_no_memory_left);
|
||||
db->reserved = new_size;
|
||||
db->buffer = new_buf;
|
||||
}
|
||||
// get buffer mem and fill in struct
|
||||
static void initstruct(struct dynabuf *db, size_t initial_size)
|
||||
{
|
||||
//printf("dynabuf-init: %d.\n", initial_size);
|
||||
if (initial_size < DYNABUF_MINIMUM_INITIALSIZE)
|
||||
initial_size = DYNABUF_MINIMUM_INITIALSIZE;
|
||||
db->size = 0;
|
||||
db->reserved = initial_size;
|
||||
db->buffer = malloc(initial_size);
|
||||
if (db->buffer == NULL) {
|
||||
// scream and die because there is not enough memory
|
||||
fputs("Error: No memory for dynamic buffer.\n", stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Exported functions
|
||||
|
||||
// Create and init a dynamic buffer and return pointer
|
||||
struct dynabuf *DynaBuf_create(int initial_size)
|
||||
// (ensure buffer is ready to use, then) clear dynamic buffer
|
||||
void dynabuf_clear(struct dynabuf *db)
|
||||
{
|
||||
struct dynabuf *db;
|
||||
|
||||
if (initial_size < DYNABUF_MINIMUM_INITIALSIZE)
|
||||
initial_size = DYNABUF_MINIMUM_INITIALSIZE;
|
||||
if ((db = malloc(sizeof(*db)))) {
|
||||
db->size = 0;
|
||||
db->reserved = initial_size;
|
||||
db->buffer = malloc(initial_size);
|
||||
if (db->buffer)
|
||||
return db; // if both pointers are != NULL, no error
|
||||
}
|
||||
// otherwise, complain
|
||||
fputs("Error: No memory for dynamic buffer.\n", stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
if (db->buffer == NULL)
|
||||
initstruct(db, db->reserved); // get initial buffer
|
||||
db->size = 0; // clear buffer
|
||||
}
|
||||
|
||||
// Enlarge buffer
|
||||
void DynaBuf_enlarge(struct dynabuf *db)
|
||||
void dynabuf_enlarge(struct dynabuf *db)
|
||||
{
|
||||
resize(db, MAKE_LARGER_THAN(db->reserved));
|
||||
}
|
||||
|
@ -112,6 +119,11 @@ void DynaBuf_to_lower(struct dynabuf *target, struct dynabuf *source)
|
|||
*write,
|
||||
byte;
|
||||
|
||||
// if target has not been initialised yet, do it now
|
||||
// (do not clear it unconditionally, because it may equal source!)
|
||||
if (target->buffer == NULL)
|
||||
initstruct(target, target->reserved); // get initial buffer
|
||||
|
||||
// make sure target can take it
|
||||
if (source->size > target->reserved)
|
||||
resize(target, source->size);
|
||||
|
@ -131,9 +143,3 @@ void DynaBuf_to_lower(struct dynabuf *target, struct dynabuf *source)
|
|||
// FIXME - use BYTE_ macro from global.h
|
||||
*write = '\0'; // terminate
|
||||
}
|
||||
|
||||
// Initialisation - allocate global dynamic buffer
|
||||
void DynaBuf_init(void)
|
||||
{
|
||||
GlobalDynaBuf = DynaBuf_create(GLOBALDYNABUF_INITIALSIZE);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||
// Copyright (C) 1998-2016 Marco Baye
|
||||
// Copyright (C) 1998-2020 Marco Baye
|
||||
// Have a look at "acme.c" for further info
|
||||
//
|
||||
// Dynamic buffer stuff
|
||||
|
@ -8,14 +8,14 @@
|
|||
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h> // for size_t
|
||||
|
||||
|
||||
// macros
|
||||
#define DYNABUF_CLEAR(db) do {db->size = 0;} while (0)
|
||||
#define DYNABUF_APPEND(db, byte) \
|
||||
do { \
|
||||
if (db->size == db->reserved) \
|
||||
DynaBuf_enlarge(db); \
|
||||
dynabuf_enlarge(db); \
|
||||
db->buffer[(db->size)++] = byte;\
|
||||
} while (0)
|
||||
// the next one is dangerous - the buffer location can change when a character
|
||||
|
@ -27,21 +27,28 @@ do { \
|
|||
// dynamic buffer structure
|
||||
struct dynabuf {
|
||||
char *buffer; // pointer to buffer
|
||||
int size; // size of buffer's used portion
|
||||
int reserved; // total size of buffer
|
||||
size_t size; // size of buffer's used portion
|
||||
size_t reserved; // total size of buffer
|
||||
};
|
||||
// new way of declaration/definition:
|
||||
// the small struct above is static, only the buffer itself gets malloc'd (on
|
||||
// first "clear").
|
||||
#define STRUCT_DYNABUF_REF(name, size) struct dynabuf name[1] = {{NULL, 0, size}}
|
||||
// the "[1]" makes sure the name refers to the address and not the struct
|
||||
// itself, so existing code where the name referred to a pointer does not need
|
||||
// to be changed.
|
||||
|
||||
|
||||
// variables
|
||||
extern struct dynabuf *GlobalDynaBuf; // global dynamic buffer
|
||||
extern struct dynabuf GlobalDynaBuf[1]; // global dynamic buffer
|
||||
// TODO - get rid of this, or move to global.c
|
||||
|
||||
|
||||
// create global DynaBuf (call once on program startup)
|
||||
extern void DynaBuf_init(void);
|
||||
// create (private) DynaBuf
|
||||
extern struct dynabuf *DynaBuf_create(int initial_size);
|
||||
// (ensure buffer is ready to use, then) clear dynamic buffer
|
||||
#define DYNABUF_CLEAR(db) dynabuf_clear(db) // TODO - remove old macro
|
||||
extern void dynabuf_clear(struct dynabuf *db);
|
||||
// call whenever buffer is too small
|
||||
extern void DynaBuf_enlarge(struct dynabuf *db);
|
||||
extern void dynabuf_enlarge(struct dynabuf *db);
|
||||
// return malloc'd copy of buffer contents
|
||||
extern char *DynaBuf_get_copy(struct dynabuf *db);
|
||||
// copy string to buffer (without terminator)
|
||||
|
|
|
@ -83,12 +83,12 @@ const struct encoder encoder_file = {
|
|||
|
||||
|
||||
// keywords for "!convtab" pseudo opcode
|
||||
static struct ronode *encoder_tree = NULL; // tree to hold encoders
|
||||
static struct ronode encoder_list[] = {
|
||||
static struct ronode encoder_tree[] = {
|
||||
PREDEF_START,
|
||||
//no! PREDEFNODE("file", &encoder_file), "!ct file" is not needed; just use {} after initial loading of table!
|
||||
PREDEFNODE(s_pet, &encoder_pet),
|
||||
PREDEFNODE(s_raw, &encoder_raw),
|
||||
PREDEFLAST(s_scr, &encoder_scr),
|
||||
PREDEFNODE("pet", &encoder_pet),
|
||||
PREDEFNODE("raw", &encoder_raw),
|
||||
PREDEF_END("scr", &encoder_scr),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
|
@ -120,9 +120,6 @@ const struct encoder *encoding_find(void)
|
|||
{
|
||||
void *node_body;
|
||||
|
||||
// make sure tree is initialised
|
||||
if (encoder_tree == NULL)
|
||||
Tree_add_table(&encoder_tree, encoder_list);
|
||||
// perform lookup
|
||||
if (!Tree_easy_scan(encoder_tree, &node_body, GlobalDynaBuf)) {
|
||||
Throw_error("Unknown encoding.");
|
||||
|
|
|
@ -46,7 +46,7 @@ boolean check_ifdef_condition(void)
|
|||
symbol = (struct symbol *) node->body;
|
||||
symbol->has_been_read = TRUE; // we did not really read the symbol's value, but checking for its existence still counts as "used it"
|
||||
if (symbol->object.type == NULL)
|
||||
Bug_found("ObjectHasNullType", 0); // FIXME - add to docs!
|
||||
Bug_found("ObjectHasNullType", 0);
|
||||
return symbol->object.type->is_defined(&symbol->object);
|
||||
}
|
||||
|
||||
|
@ -246,7 +246,6 @@ void flow_do_while(struct do_while *loop)
|
|||
// parse a whole source code file
|
||||
void flow_parse_and_close_file(FILE *fd, const char *filename)
|
||||
{
|
||||
//TODO - check for bogus/malformed BOM and ignore!
|
||||
// be verbose
|
||||
if (config.process_verbosity > 2)
|
||||
printf("Parsing source file '%s'\n", filename);
|
||||
|
|
91
src/global.c
91
src/global.c
|
@ -29,31 +29,21 @@
|
|||
|
||||
|
||||
// constants
|
||||
|
||||
const char s_and[] = "and";
|
||||
const char s_asl[] = "asl";
|
||||
const char s_asr[] = "asr";
|
||||
const char s_bra[] = "bra";
|
||||
const char s_brl[] = "brl";
|
||||
const char s_eor[] = "eor";
|
||||
const char s_error[] = "error";
|
||||
const char s_lsr[] = "lsr";
|
||||
const char s_scrxor[] = "scrxor";
|
||||
char s_untitled[] = "<untitled>"; // FIXME - this is actually const
|
||||
const char s_pet[] = "pet";
|
||||
const char s_raw[] = "raw";
|
||||
const char s_scr[] = "scr";
|
||||
|
||||
|
||||
// Exception messages during assembly
|
||||
const char exception_cannot_open_input_file[] = "Cannot open input file.";
|
||||
const char exception_missing_string[] = "No string given.";
|
||||
const char exception_negative_size[] = "Negative size argument.";
|
||||
const char exception_no_left_brace[] = "Missing '{'.";
|
||||
const char exception_no_memory_left[] = "Out of memory.";
|
||||
const char exception_no_right_brace[] = "Found end-of-file instead of '}'.";
|
||||
//const char exception_not_yet[] = "Sorry, feature not yet implemented.";
|
||||
// TODO - show actual value in error message
|
||||
const char exception_number_out_of_range[] = "Number out of range.";
|
||||
const char exception_number_out_of_8b_range[] = "Number does not fit in 8 bits.";
|
||||
static const char exception_number_out_of_16b_range[] = "Number does not fit in 16 bits.";
|
||||
static const char exception_number_out_of_24b_range[] = "Number does not fit in 24 bits.";
|
||||
const char exception_pc_undefined[] = "Program counter undefined.";
|
||||
const char exception_symbol_defined[] = "Symbol already defined.";
|
||||
const char exception_syntax[] = "Syntax error.";
|
||||
|
@ -491,7 +481,7 @@ void output_object(struct object *object, struct iter_context *iter)
|
|||
else if (object->u.number.ntype == NUMTYPE_FLOAT)
|
||||
iter->fn(object->u.number.val.fpval);
|
||||
else
|
||||
Bug_found("IllegalNumberType7", object->u.number.ntype); // FIXME - add to docs!
|
||||
Bug_found("IllegalNumberType0", object->u.number.ntype);
|
||||
} else if (object->type == &type_list) {
|
||||
// iterate over list
|
||||
item = object->u.listhead->next;
|
||||
|
@ -512,7 +502,7 @@ void output_object(struct object *object, struct iter_context *iter)
|
|||
Throw_error("There's more than one character."); // see alu.c for the original of this error
|
||||
}
|
||||
} else {
|
||||
Bug_found("IllegalObjectType9", 0); // FIXME - add to docs!
|
||||
Bug_found("IllegalObjectType", 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -520,86 +510,79 @@ void output_object(struct object *object, struct iter_context *iter)
|
|||
// output 8-bit value with range check
|
||||
void output_8(intval_t value)
|
||||
{
|
||||
if ((value <= 0xff) && (value >= -0x80))
|
||||
Output_byte(value);
|
||||
else
|
||||
Throw_error(exception_number_out_of_range);
|
||||
if ((value < -0x80) || (value > 0xff))
|
||||
Throw_error(exception_number_out_of_8b_range);
|
||||
Output_byte(value);
|
||||
}
|
||||
|
||||
|
||||
// output 16-bit value with range check big-endian
|
||||
void output_be16(intval_t value)
|
||||
{
|
||||
if ((value <= 0xffff) && (value >= -0x8000)) {
|
||||
Output_byte(value >> 8);
|
||||
Output_byte(value);
|
||||
} else {
|
||||
Throw_error(exception_number_out_of_range);
|
||||
}
|
||||
if ((value < -0x8000) || (value > 0xffff))
|
||||
Throw_error(exception_number_out_of_16b_range);
|
||||
Output_byte(value >> 8);
|
||||
Output_byte(value);
|
||||
}
|
||||
|
||||
|
||||
// output 16-bit value with range check little-endian
|
||||
void output_le16(intval_t value)
|
||||
{
|
||||
if ((value <= 0xffff) && (value >= -0x8000)) {
|
||||
Output_byte(value);
|
||||
Output_byte(value >> 8);
|
||||
} else {
|
||||
Throw_error(exception_number_out_of_range);
|
||||
}
|
||||
if ((value < -0x8000) || (value > 0xffff))
|
||||
Throw_error(exception_number_out_of_16b_range);
|
||||
Output_byte(value);
|
||||
Output_byte(value >> 8);
|
||||
}
|
||||
|
||||
|
||||
// output 24-bit value with range check big-endian
|
||||
void output_be24(intval_t value)
|
||||
{
|
||||
if ((value <= 0xffffff) && (value >= -0x800000)) {
|
||||
Output_byte(value >> 16);
|
||||
Output_byte(value >> 8);
|
||||
Output_byte(value);
|
||||
} else {
|
||||
Throw_error(exception_number_out_of_range);
|
||||
}
|
||||
if ((value < -0x800000) || (value > 0xffffff))
|
||||
Throw_error(exception_number_out_of_24b_range);
|
||||
Output_byte(value >> 16);
|
||||
Output_byte(value >> 8);
|
||||
Output_byte(value);
|
||||
}
|
||||
|
||||
|
||||
// output 24-bit value with range check little-endian
|
||||
void output_le24(intval_t value)
|
||||
{
|
||||
if ((value <= 0xffffff) && (value >= -0x800000)) {
|
||||
Output_byte(value);
|
||||
Output_byte(value >> 8);
|
||||
Output_byte(value >> 16);
|
||||
} else {
|
||||
Throw_error(exception_number_out_of_range);
|
||||
}
|
||||
if ((value < -0x800000) || (value > 0xffffff))
|
||||
Throw_error(exception_number_out_of_24b_range);
|
||||
Output_byte(value);
|
||||
Output_byte(value >> 8);
|
||||
Output_byte(value >> 16);
|
||||
}
|
||||
|
||||
|
||||
// FIXME - the range checks below are commented out because 32-bit
|
||||
// signed integers cannot exceed the range of 32-bit signed integers.
|
||||
// But now that 64-bit machines are the norm, "intval_t" might be a
|
||||
// 64-bit int. I need to address this problem one way or another.
|
||||
|
||||
|
||||
// output 32-bit value (without range check) big-endian
|
||||
void output_be32(intval_t value)
|
||||
{
|
||||
// if ((Value <= 0x7fffffff) && (Value >= -0x80000000)) {
|
||||
// if ((value < -0x80000000) || (value > 0xffffffff))
|
||||
// Throw_error(exception_number_out_of_32b_range);
|
||||
Output_byte(value >> 24);
|
||||
Output_byte(value >> 16);
|
||||
Output_byte(value >> 8);
|
||||
Output_byte(value);
|
||||
// } else {
|
||||
// Throw_error(exception_number_out_of_range);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
// output 32-bit value (without range check) little-endian
|
||||
void output_le32(intval_t value)
|
||||
{
|
||||
// if ((Value <= 0x7fffffff) && (Value >= -0x80000000)) {
|
||||
// if ((value < -0x80000000) || (value > 0xffffffff))
|
||||
// Throw_error(exception_number_out_of_32b_range);
|
||||
Output_byte(value);
|
||||
Output_byte(value >> 8);
|
||||
Output_byte(value >> 16);
|
||||
Output_byte(value >> 24);
|
||||
// } else {
|
||||
// Throw_error(exception_number_out_of_range);
|
||||
// }
|
||||
}
|
||||
|
|
14
src/global.h
14
src/global.h
|
@ -21,21 +21,8 @@
|
|||
|
||||
#define SF_FOUND_BLANK (1u << 0) // statement had space or tab
|
||||
#define SF_IMPLIED_LABEL (1u << 1) // statement had implied label def
|
||||
extern const char s_and[];
|
||||
extern const char s_asl[];
|
||||
extern const char s_asr[];
|
||||
extern const char s_bra[];
|
||||
extern const char s_brl[];
|
||||
extern const char s_eor[];
|
||||
extern const char s_error[];
|
||||
extern const char s_lsr[];
|
||||
extern const char s_scrxor[];
|
||||
extern char s_untitled[];
|
||||
extern const char s_pet[];
|
||||
extern const char s_raw[];
|
||||
extern const char s_scr[];
|
||||
// error messages during assembly
|
||||
extern const char exception_cannot_open_input_file[];
|
||||
extern const char exception_missing_string[];
|
||||
extern const char exception_negative_size[];
|
||||
extern const char exception_no_left_brace[];
|
||||
|
@ -43,6 +30,7 @@ extern const char exception_no_memory_left[];
|
|||
extern const char exception_no_right_brace[];
|
||||
//extern const char exception_not_yet[];
|
||||
extern const char exception_number_out_of_range[];
|
||||
extern const char exception_number_out_of_8b_range[];
|
||||
extern const char exception_pc_undefined[];
|
||||
extern const char exception_symbol_defined[];
|
||||
extern const char exception_syntax[];
|
||||
|
|
52
src/input.c
52
src/input.c
|
@ -48,7 +48,7 @@ void Input_new_file(const char *filename, FILE *fd)
|
|||
Input_now->original_filename = filename;
|
||||
Input_now->line_number = 1;
|
||||
Input_now->source = INPUTSRC_FILE;
|
||||
Input_now->state = INPUTSTATE_NORMAL;
|
||||
Input_now->state = INPUTSTATE_SOF;
|
||||
Input_now->src.fd = fd;
|
||||
}
|
||||
|
||||
|
@ -76,14 +76,15 @@ static void report_srcchar(char new_char)
|
|||
// show line number...
|
||||
fprintf(report->fd, "%6d ", Input_now->line_number - 1);
|
||||
// prepare outbytes' start address
|
||||
if (report->bin_used)
|
||||
if (report->bin_used) {
|
||||
#if _BSD_SOURCE || _XOPEN_SOURCE >= 500 || _ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L
|
||||
snprintf(hex_address, HEXBUFSIZE, "%04x", report->bin_address);
|
||||
#else
|
||||
sprintf(hex_address, "%04x", report->bin_address);
|
||||
#endif
|
||||
else
|
||||
} else {
|
||||
hex_address[0] = '\0';
|
||||
}
|
||||
// prepare outbytes
|
||||
hexdump[0] = '\0';
|
||||
for (ii = 0; ii < report->bin_used; ++ii)
|
||||
|
@ -117,6 +118,19 @@ static char get_processed_from_file(void)
|
|||
|
||||
for (;;) {
|
||||
switch (Input_now->state) {
|
||||
case INPUTSTATE_SOF:
|
||||
// fetch first byte from the current source file
|
||||
from_file = getc(Input_now->src.fd);
|
||||
IF_WANTED_REPORT_SRCCHAR(from_file);
|
||||
//TODO - check for bogus/malformed BOM and ignore?
|
||||
// check for hashbang line and ignore
|
||||
if (from_file == '#') {
|
||||
// remember to skip remainder of line
|
||||
Input_now->state = INPUTSTATE_COMMENT;
|
||||
return CHAR_EOS; // end of statement
|
||||
}
|
||||
Input_now->state = INPUTSTATE_AGAIN;
|
||||
break;
|
||||
case INPUTSTATE_NORMAL:
|
||||
// fetch a fresh byte from the current source file
|
||||
from_file = getc(Input_now->src.fd);
|
||||
|
@ -265,7 +279,7 @@ char GetByte(void)
|
|||
GotByte = get_processed_from_file();
|
||||
break;
|
||||
default:
|
||||
Bug_found("InvalidInputSrc", Input_now->source); // FIXME - add to docs
|
||||
Bug_found("IllegalInputSrc", Input_now->source);
|
||||
}
|
||||
// // if start-of-line was read, increment line counter and repeat
|
||||
// if (GotByte != CHAR_SOL)
|
||||
|
@ -316,7 +330,7 @@ static char GetQuotedByte(void)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
Bug_found("InvalidInputSrc", Input_now->source); // FIXME - add to docs!
|
||||
Bug_found("IllegalInputSrc", Input_now->source);
|
||||
}
|
||||
// now check for end of statement
|
||||
if (GotByte == CHAR_EOS)
|
||||
|
@ -416,7 +430,7 @@ int Input_unescape_dynabuf(int read_index)
|
|||
break;
|
||||
// TODO - 'a' to BEL? others?
|
||||
default:
|
||||
Throw_error("Unsupported backslash sequence."); // TODO - add to docs (and add unexpected character to error message?)
|
||||
Throw_error("Unsupported backslash sequence."); // TODO - add unexpected character to error message?
|
||||
}
|
||||
GLOBALDYNABUF_CURRENT[write_index++] = byte;
|
||||
escaped = FALSE;
|
||||
|
@ -429,7 +443,7 @@ int Input_unescape_dynabuf(int read_index)
|
|||
}
|
||||
}
|
||||
if (escaped)
|
||||
Bug_found("PartialEscapeSequence", 0); // FIXME - add to docs!
|
||||
Bug_found("PartialEscapeSequence", 0);
|
||||
GlobalDynaBuf->size = write_index;
|
||||
return 0; // ok
|
||||
}
|
||||
|
@ -672,18 +686,9 @@ struct ipi {
|
|||
*prev;
|
||||
const char *path;
|
||||
};
|
||||
static struct ipi ipi_head; // head element
|
||||
static struct dynabuf *pathbuf; // buffer to combine search path and file spec
|
||||
static struct ipi ipi_head = {&ipi_head, &ipi_head, NULL}; // head element
|
||||
static STRUCT_DYNABUF_REF(pathbuf, 256); // to combine search path and file spec
|
||||
|
||||
// init list
|
||||
void includepaths_init(void)
|
||||
{
|
||||
// init ring list
|
||||
ipi_head.next = &ipi_head;
|
||||
ipi_head.prev = &ipi_head;
|
||||
// init dynabuf
|
||||
pathbuf = DynaBuf_create(256);
|
||||
}
|
||||
// add entry
|
||||
void includepaths_add(const char *path)
|
||||
{
|
||||
|
@ -732,8 +737,15 @@ FILE *includepaths_open_ro(boolean uses_lib)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (stream == NULL)
|
||||
Throw_error(exception_cannot_open_input_file);
|
||||
if (stream == NULL) {
|
||||
// CAUTION, I'm re-using the path dynabuf to assemble the error message:
|
||||
DYNABUF_CLEAR(pathbuf);
|
||||
DynaBuf_add_string(pathbuf, "Cannot open input file \"");
|
||||
DynaBuf_add_string(pathbuf, GLOBALDYNABUF_CURRENT);
|
||||
DynaBuf_add_string(pathbuf, "\".");
|
||||
DynaBuf_append(pathbuf, '\0');
|
||||
Throw_error(pathbuf->buffer);
|
||||
}
|
||||
//fprintf(stderr, "File is [%s]\n", GLOBALDYNABUF_CURRENT);
|
||||
return stream;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
// values for input component "src.state"
|
||||
enum inputstate {
|
||||
INPUTSTATE_SOF, // start of file (check for hashbang)
|
||||
INPUTSTATE_NORMAL, // everything's fine
|
||||
INPUTSTATE_AGAIN, // re-process last byte
|
||||
INPUTSTATE_SKIPBLANKS, // shrink multiple spaces
|
||||
|
@ -125,8 +126,6 @@ extern bits Input_get_force_bit(void);
|
|||
|
||||
// include path stuff - should be moved to its own file:
|
||||
|
||||
// init list
|
||||
extern void includepaths_init(void);
|
||||
// add entry
|
||||
extern void includepaths_add(const char *path);
|
||||
// open file for reading (trying list entries as prefixes)
|
||||
|
|
19
src/macro.c
19
src/macro.c
|
@ -18,7 +18,7 @@
|
|||
|
||||
|
||||
// Constants
|
||||
#define MACRONAME_DYNABUF_INITIALSIZE 128
|
||||
#define NAME_INITIALSIZE 128
|
||||
#define ARG_SEPARATOR ' ' // separates macro title from arg types
|
||||
#define ARGTYPE_VALUE 'v'
|
||||
#define ARGTYPE_REF 'r'
|
||||
|
@ -46,8 +46,8 @@ union macro_arg_t {
|
|||
|
||||
|
||||
// Variables
|
||||
static struct dynabuf *user_macro_name; // original macro title
|
||||
static struct dynabuf *internal_name; // plus param type chars
|
||||
static STRUCT_DYNABUF_REF(user_macro_name, NAME_INITIALSIZE); // original macro title
|
||||
static STRUCT_DYNABUF_REF(internal_name, NAME_INITIALSIZE); // plus param type chars
|
||||
static struct rwnode *macro_forest[256]; // trees (because of 8b hash)
|
||||
// Dynamic argument table
|
||||
static union macro_arg_t *arg_table = NULL;
|
||||
|
@ -60,19 +60,12 @@ static int argtable_size = HALF_INITIAL_ARG_TABLE_SIZE;
|
|||
static void enlarge_arg_table(void)
|
||||
{
|
||||
argtable_size *= 2;
|
||||
//printf("Doubling arg table size to %d.\n", argtable_size);
|
||||
arg_table = realloc(arg_table, argtable_size * sizeof(*arg_table));
|
||||
if (arg_table == NULL)
|
||||
Throw_serious_error(exception_no_memory_left);
|
||||
}
|
||||
|
||||
// create dynamic buffers and arg table
|
||||
void Macro_init(void)
|
||||
{
|
||||
user_macro_name = DynaBuf_create(MACRONAME_DYNABUF_INITIALSIZE);
|
||||
internal_name = DynaBuf_create(MACRONAME_DYNABUF_INITIALSIZE);
|
||||
enlarge_arg_table();
|
||||
}
|
||||
|
||||
// Read macro scope and title. Title is read to GlobalDynaBuf and then copied
|
||||
// over to internal_name DynaBuf, where ARG_SEPARATOR is added.
|
||||
// In user_macro_name DynaBuf, the original name is reconstructed (even with
|
||||
|
@ -241,6 +234,10 @@ void Macro_parse_call(void) // Now GotByte = dot or first char of macro name
|
|||
int arg_count = 0;
|
||||
int outer_err_count;
|
||||
|
||||
// make sure arg_table is ready (if not yet initialised, do it now)
|
||||
if (arg_table == NULL)
|
||||
enlarge_arg_table();
|
||||
|
||||
// Enter deeper nesting level
|
||||
// Quit program if recursion too deep.
|
||||
if (--macro_recursions_left < 0)
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
// Prototypes
|
||||
|
||||
// create dynamic buffers and arg table
|
||||
extern void Macro_init(void); // create private dynabuf
|
||||
// only call once (during first pass)
|
||||
extern void Macro_parse_definition(void);
|
||||
// Parse macro call ("+MACROTITLE"). Has to be re-entrant.
|
||||
|
|
418
src/mnemo.c
418
src/mnemo.c
|
@ -15,9 +15,8 @@
|
|||
#include "typesystem.h"
|
||||
|
||||
|
||||
// Constants
|
||||
#define s_ror (s_error + 2) // Yes, I know I'm sick
|
||||
#define MNEMO_DYNABUF_INITIALSIZE 8 // 4 + terminator should suffice
|
||||
// constants
|
||||
#define MNEMO_INITIALSIZE 8 // 4 + terminator should suffice
|
||||
|
||||
// These values are needed to recognize addressing modes:
|
||||
// indexing:
|
||||
|
@ -55,7 +54,7 @@
|
|||
// only for m65:
|
||||
#define LONG_INDIRECT_Z_INDEXED_ADDRESSING (AMB_LONGINDIRECT | AMB_INDEX(INDEX_Z))
|
||||
|
||||
// Constant values, used to mark the possible parameter lengths of commands.
|
||||
// constant values, used to mark the possible parameter lengths of instructions.
|
||||
// Not all of the eight possible combinations are actually used, however (because of the supported CPUs).
|
||||
#define MAYBE______ 0
|
||||
#define MAYBE_1____ NUMBER_FORCES_8
|
||||
|
@ -72,10 +71,15 @@ enum mnemogroup {
|
|||
GROUP_BITBRANCH, // bbr0..7 and bbs0..7 Byte value = opcode
|
||||
GROUP_REL16_2, // 16bit relative to pc+2 Byte value = opcode
|
||||
GROUP_REL16_3, // 16bit relative to pc+3 Byte value = opcode
|
||||
GROUP_BOTHMOVES, // the "move" commands MVP and MVN Byte value = opcode
|
||||
GROUP_ZPONLY, // rmb0..7 and smb0..7 Byte value = opcode FIXME - use for IDXeDEW,IDXeINW as well!
|
||||
GROUP_BOTHMOVES, // the "move" instructions MVP and MVN Byte value = opcode
|
||||
GROUP_ZPONLY, // rmb0..7, smb0..7, inw, dew Byte value = opcode
|
||||
GROUP_PREFIX, // NOP on m65 (throws error) Byte value = opcode
|
||||
};
|
||||
// TODO: make sure groups like IMPLIEDONLY and ZPONLY output
|
||||
// "Mnemonic does not support this addressing mode" instead of
|
||||
// "Garbage data at end of statement".
|
||||
// TODO: maybe add GROUP_IMMEDIATEONLY?
|
||||
// (for RTN, REP, SEP, ANC, ALR, ARR, SBX, LXA, ANE, SAC, SIR)
|
||||
|
||||
// save some space
|
||||
#define SCB static const unsigned char
|
||||
|
@ -92,13 +96,13 @@ enum mnemogroup {
|
|||
enum { IDX_ORA,IDXcORA,IDX16ORA,IDXeORA,IDXmORA,IDXmORQ,IDX_AND,IDXcAND,IDX16AND,IDXeAND,IDXmAND,IDXmANDQ,IDX_EOR,IDXcEOR,IDX16EOR,IDXeEOR,IDXmEOR,IDXmEORQ,IDX_ADC,IDXcADC,IDX16ADC,IDXeADC,IDXmADC,IDXmADCQ,IDX_STA,IDXcSTA,IDX16STA,IDXeSTA,IDXmSTA,IDXmSTQ,IDX_LDA,IDXcLDA,IDX16LDA,IDXeLDA,IDXmLDA,IDXmLDQ,IDX_CMP,IDXcCMP,IDX16CMP,IDXeCMP,IDXmCMP,IDXmCPQ,IDX_SBC,IDXcSBC,IDX16SBC,IDXeSBC,IDXmSBC,IDXmSBCQ,IDX16PEI,IDXuSLO,IDXuRLA,IDXuSRE,IDXuRRA,IDXuSAX,IDXuLAX,IDXuDCP,IDXuISC,IDXuSHA};
|
||||
SCB accu_imm[] = { 0x09, 0x09, 0x09, 0x09, 0x09, 0, 0x29, 0x29, 0x29, 0x29, 0x29, 0, 0x49, 0x49, 0x49, 0x49, 0x49, 0, 0x69, 0x69, 0x69, 0x69, 0x69, 0, 0, 0, 0, 0, 0, 0, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // #$ff #$ffff
|
||||
SCL accu_abs[] = { 0x0d05, 0x0d05,0x0f0d05, 0x0d05, 0x0d05, 0x0d05, 0x2d25, 0x2d25,0x2f2d25, 0x2d25, 0x2d25, 0x2d25, 0x4d45, 0x4d45,0x4f4d45, 0x4d45, 0x4d45, 0x4d45, 0x6d65, 0x6d65,0x6f6d65, 0x6d65, 0x6d65, 0x6d65, 0x8d85, 0x8d85,0x8f8d85, 0x8d85, 0x8d85, 0x8d85, 0xada5, 0xada5,0xafada5, 0xada5, 0xada5, 0xada5, 0xcdc5, 0xcdc5,0xcfcdc5, 0xcdc5, 0xcdc5, 0xcdc5, 0xede5, 0xede5,0xefede5, 0xede5, 0xede5, 0xede5, 0, 0x0f07, 0x2f27, 0x4f47, 0x6f67, 0x8f87, 0xafa7, 0xcfc7, 0xefe7, 0}; // $ff $ffff $ffffff
|
||||
SCL accu_xabs[] = { 0x1d15, 0x1d15,0x1f1d15, 0x1d15, 0x1d15, 0x1d15, 0x3d35, 0x3d35,0x3f3d35, 0x3d35, 0x3d35, 0x3d35, 0x5d55, 0x5d55,0x5f5d55, 0x5d55, 0x5d55, 0x5d55, 0x7d75, 0x7d75,0x7f7d75, 0x7d75, 0x7d75, 0x7d75, 0x9d95, 0x9d95,0x9f9d95, 0x9d95, 0x9d95, 0x9d95, 0xbdb5, 0xbdb5,0xbfbdb5, 0xbdb5, 0xbdb5, 0xbdb5, 0xddd5, 0xddd5,0xdfddd5, 0xddd5, 0xddd5, 0xddd5, 0xfdf5, 0xfdf5,0xfffdf5, 0xfdf5, 0xfdf5, 0xfdf5, 0, 0x1f17, 0x3f37, 0x5f57, 0x7f77, 0, 0, 0xdfd7, 0xfff7, 0}; // $ff,x $ffff,x $ffffff,x
|
||||
SCS accu_yabs[] = { 0x1900, 0x1900, 0x1900, 0x1900, 0x1900, 0x1900, 0x3900, 0x3900, 0x3900, 0x3900, 0x3900, 0x3900, 0x5900, 0x5900, 0x5900, 0x5900, 0x5900, 0x5900, 0x7900, 0x7900, 0x7900, 0x7900, 0x7900, 0x7900, 0x9900, 0x9900, 0x9900, 0x9900, 0x9900, 0x9900, 0xb900, 0xb900, 0xb900, 0xb900, 0xb900, 0xb900, 0xd900, 0xd900, 0xd900, 0xd900, 0xd900, 0xd900, 0xf900, 0xf900, 0xf900, 0xf900, 0xf900, 0xf900, 0, 0x1b00, 0x3b00, 0x5b00, 0x7b00, 0x97, 0xbfb7, 0xdb00, 0xfb00, 0x9f00}; // $ff,y $ffff,y
|
||||
SCB accu_xind8[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0, 0x03, 0x23, 0x43, 0x63, 0x83, 0xa3, 0xc3, 0xe3, 0}; // ($ff,x)
|
||||
SCB accu_indy8[] = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0, 0x13, 0x33, 0x53, 0x73, 0, 0xb3, 0xd3, 0xf3, 0x93}; // ($ff),y
|
||||
SCL accu_xabs[] = { 0x1d15, 0x1d15,0x1f1d15, 0x1d15, 0x1d15, 0, 0x3d35, 0x3d35,0x3f3d35, 0x3d35, 0x3d35, 0, 0x5d55, 0x5d55,0x5f5d55, 0x5d55, 0x5d55, 0, 0x7d75, 0x7d75,0x7f7d75, 0x7d75, 0x7d75, 0, 0x9d95, 0x9d95,0x9f9d95, 0x9d95, 0x9d95, 0, 0xbdb5, 0xbdb5,0xbfbdb5, 0xbdb5, 0xbdb5, 0xbdb5, 0xddd5, 0xddd5,0xdfddd5, 0xddd5, 0xddd5, 0, 0xfdf5, 0xfdf5,0xfffdf5, 0xfdf5, 0xfdf5, 0, 0, 0x1f17, 0x3f37, 0x5f57, 0x7f77, 0, 0, 0xdfd7, 0xfff7, 0}; // $ff,x $ffff,x $ffffff,x
|
||||
SCS accu_yabs[] = { 0x1900, 0x1900, 0x1900, 0x1900, 0x1900, 0, 0x3900, 0x3900, 0x3900, 0x3900, 0x3900, 0, 0x5900, 0x5900, 0x5900, 0x5900, 0x5900, 0, 0x7900, 0x7900, 0x7900, 0x7900, 0x7900, 0, 0x9900, 0x9900, 0x9900, 0x9900, 0x9900, 0, 0xb900, 0xb900, 0xb900, 0xb900, 0xb900, 0xb900, 0xd900, 0xd900, 0xd900, 0xd900, 0xd900, 0, 0xf900, 0xf900, 0xf900, 0xf900, 0xf900, 0, 0, 0x1b00, 0x3b00, 0x5b00, 0x7b00, 0x97, 0xbfb7, 0xdb00, 0xfb00, 0x9f00}; // $ff,y $ffff,y
|
||||
SCB accu_xind8[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0, 0x21, 0x21, 0x21, 0x21, 0x21, 0, 0x41, 0x41, 0x41, 0x41, 0x41, 0, 0x61, 0x61, 0x61, 0x61, 0x61, 0, 0x81, 0x81, 0x81, 0x81, 0x81, 0, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0, 0, 0x03, 0x23, 0x43, 0x63, 0x83, 0xa3, 0xc3, 0xe3, 0}; // ($ff,x)
|
||||
SCB accu_indy8[] = { 0x11, 0x11, 0x11, 0x11, 0x11, 0, 0x31, 0x31, 0x31, 0x31, 0x31, 0, 0x51, 0x51, 0x51, 0x51, 0x51, 0, 0x71, 0x71, 0x71, 0x71, 0x71, 0, 0x91, 0x91, 0x91, 0x91, 0x91, 0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0, 0, 0x13, 0x33, 0x53, 0x73, 0, 0xb3, 0xd3, 0xf3, 0x93}; // ($ff),y
|
||||
SCB accu_ind8[] = { 0, 0x12, 0x12, 0, 0, 0x12, 0, 0x32, 0x32, 0, 0, 0x32, 0, 0x52, 0x52, 0, 0, 0x52, 0, 0x72, 0x72, 0, 0, 0x72, 0, 0x92, 0x92, 0, 0, 0x92, 0, 0xb2, 0xb2, 0, 0, 0xb2, 0, 0xd2, 0xd2, 0, 0, 0xd2, 0, 0xf2, 0xf2, 0, 0, 0xf2, 0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ($ff)
|
||||
SCB accu_sabs8[] = { 0, 0, 0x03, 0, 0, 0, 0, 0, 0x23, 0, 0, 0, 0, 0, 0x43, 0, 0, 0, 0, 0, 0x63, 0, 0, 0, 0, 0, 0x83, 0, 0, 0, 0, 0, 0xa3, 0, 0, 0, 0, 0, 0xc3, 0, 0, 0, 0, 0, 0xe3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // $ff,s
|
||||
SCB accu_sindy8[] = { 0, 0, 0x13, 0, 0, 0, 0, 0, 0x33, 0, 0, 0, 0, 0, 0x53, 0, 0, 0, 0, 0, 0x73, 0, 0, 0, 0, 0, 0x93, 0x82, 0x82, 0x82, 0, 0, 0xb3, 0xe2, 0xe2, 0xe2, 0, 0, 0xd3, 0, 0, 0, 0, 0, 0xf3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ($ff,s),y
|
||||
SCB accu_sindy8[] = { 0, 0, 0x13, 0, 0, 0, 0, 0, 0x33, 0, 0, 0, 0, 0, 0x53, 0, 0, 0, 0, 0, 0x73, 0, 0, 0, 0, 0, 0x93, 0x82, 0x82, 0, 0, 0, 0xb3, 0xe2, 0xe2, 0xe2, 0, 0, 0xd3, 0, 0, 0, 0, 0, 0xf3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ($ff,s),y
|
||||
SCB accu_lind8[] = { 0, 0, 0x07, 0, 0, 0x12, 0, 0, 0x27, 0, 0, 0x32, 0, 0, 0x47, 0, 0, 0x52, 0, 0, 0x67, 0, 0, 0x72, 0, 0, 0x87, 0, 0, 0x92, 0, 0, 0xa7, 0, 0, 0xb2, 0, 0, 0xc7, 0, 0, 0xd2, 0, 0, 0xe7, 0, 0, 0xf2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // [$ff]
|
||||
SCB accu_lindy8[] = { 0, 0, 0x17, 0, 0, 0, 0, 0, 0x37, 0, 0, 0, 0, 0, 0x57, 0, 0, 0, 0, 0, 0x77, 0, 0, 0, 0, 0, 0x97, 0, 0, 0, 0, 0, 0xb7, 0, 0, 0, 0, 0, 0xd7, 0, 0, 0, 0, 0, 0xf7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // [$ff],y
|
||||
SCB accu_indz8[] = { 0, 0, 0, 0x12, 0x12, 0, 0, 0, 0, 0x32, 0x32, 0, 0, 0, 0, 0x52, 0x52, 0, 0, 0, 0, 0x72, 0x72, 0, 0, 0, 0, 0x92, 0x92, 0, 0, 0, 0, 0xb2, 0xb2, 0, 0, 0, 0, 0xd2, 0xd2, 0, 0, 0, 0, 0xf2, 0xf2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // ($ff),z
|
||||
|
@ -110,13 +114,13 @@ SCB accu_lindz8[] = { 0, 0, 0, 0, 0x12, 0, 0,
|
|||
// mnemotable), the assembler finds out the column to use here. The row
|
||||
// depends on the used addressing mode. A zero entry in these tables means
|
||||
// that the combination of mnemonic and addressing mode is illegal.
|
||||
// | 6502 | 6502/65c02/65ce02 | 65c02 | 65ce02 | 65816 | NMOS 6502 undocumented opcodes | C64DTV2 |
|
||||
enum { IDX_ASL,IDX_ROL,IDX_LSR,IDX_ROR,IDX_LDY,IDX_LDX,IDX_CPY,IDX_CPX,IDX_BIT,IDXcBIT,IDX_STX,IDXeSTX,IDX_STY,IDXeSTY,IDX_DEC,IDXcDEC,IDX_INC,IDXcINC,IDXcTSB,IDXcTRB,IDXcSTZ,IDXeASR,IDXeASW,IDXeCPZ,IDXeDEW,IDXeINW,IDXeLDZ,IDXePHW,IDXeROW,IDXeRTN,IDX16COP,IDX16REP,IDX16SEP,IDX16PEA,IDXuANC,IDXuASR,IDXuARR,IDXuSBX,IDXuNOP,IDXuDOP,IDXuTOP,IDXuJAM,IDXuLXA,IDXuANE,IDXuLAS,IDXuTAS,IDXuSHX,IDXuSHY,IDX_SAC,IDX_SIR};
|
||||
SCB misc_impl[] = { 0x0a, 0x2a, 0x4a, 0x6a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3a, 0, 0x1a, 0, 0, 0, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xea, 0x80, 0x0c, 0x02, 0, 0, 0, 0, 0, 0, 0, 0}; // implied/accu
|
||||
SCB misc_imm[] = { 0, 0, 0, 0, 0xa0, 0xa2, 0xc0, 0xe0, 0, 0x89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc2, 0, 0, 0xa3, 0xf4, 0, 0x62, 0, 0xc2, 0xe2, 0, 0x0b, 0x4b, 0x6b, 0xcb, 0x80, 0x80, 0, 0, 0xab, 0x8b, 0, 0, 0, 0, 0x32, 0x42}; // #$ff #$ffff
|
||||
SCS misc_abs[] = { 0x0e06, 0x2e26, 0x4e46, 0x6e66, 0xaca4, 0xaea6, 0xccc4, 0xece4, 0x2c24, 0x2c24, 0x8e86, 0x8e86, 0x8c84, 0x8c84, 0xcec6, 0xcec6, 0xeee6, 0xeee6, 0x0c04, 0x1c14, 0x9c64, 0x44, 0xcb00, 0xdcd4, 0xc3, 0xe3, 0xab00, 0xfc00, 0xeb00, 0, 0x02, 0, 0, 0xf400, 0, 0, 0, 0, 0x0c04, 0x04, 0x0c00, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // $ff $ffff
|
||||
SCS misc_xabs[] = { 0x1e16, 0x3e36, 0x5e56, 0x7e76, 0xbcb4, 0, 0, 0, 0, 0x3c34, 0, 0, 0x94, 0x8b94, 0xded6, 0xded6, 0xfef6, 0xfef6, 0, 0, 0x9e74, 0x54, 0, 0, 0, 0, 0xbb00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1c14, 0x14, 0x1c00, 0, 0, 0, 0, 0, 0, 0x9c00, 0, 0}; // $ff,x $ffff,x
|
||||
SCS misc_yabs[] = { 0, 0, 0, 0, 0, 0xbeb6, 0, 0, 0, 0, 0x96, 0x9b96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xbb00, 0x9b00, 0x9e00, 0, 0, 0}; // $ff,y $ffff,y
|
||||
// | 6502 | 6502/65c02/65ce02/m65 | 65c02 | 65ce02 | 65816 | NMOS 6502 undocumented opcodes | C64DTV2 |
|
||||
enum { IDX_ASL,IDX_ROL,IDX_LSR,IDX_ROR,IDX_LDY,IDX_LDX,IDX_CPY,IDX_CPX,IDX_BIT,IDXcBIT,IDXmBITQ,IDX_STX,IDXeSTX,IDX_STY,IDXeSTY,IDX_DEC,IDXcDEC,IDX_INC,IDXcINC,IDXcTSB,IDXcTRB,IDXcSTZ,IDXeASR,IDXeASW,IDXeCPZ,IDXeLDZ,IDXePHW,IDXeROW,IDXeRTN,IDX16COP,IDX16REP,IDX16SEP,IDX16PEA,IDXuANC,IDXuALR,IDXuARR,IDXuSBX,IDXuNOP,IDXuDOP,IDXuTOP,IDXuLXA,IDXuANE,IDXuLAS,IDXuTAS,IDXuSHX,IDXuSHY,IDX_SAC,IDX_SIR};
|
||||
SCB misc_impl[] = { 0x0a, 0x2a, 0x4a, 0x6a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3a, 0, 0x1a, 0, 0, 0, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xea, 0x80, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0}; // implied/accu
|
||||
SCB misc_imm[] = { 0, 0, 0, 0, 0xa0, 0xa2, 0xc0, 0xe0, 0, 0x89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc2, 0xa3, 0xf4, 0, 0x62, /*2?*/0, 0xc2, 0xe2, 0, 0x0b, 0x4b, 0x6b, 0xcb, 0x80, 0x80, 0, 0xab, 0x8b, 0, 0, 0, 0, 0x32, 0x42}; // #$ff #$ffff
|
||||
SCS misc_abs[] = { 0x0e06, 0x2e26, 0x4e46, 0x6e66, 0xaca4, 0xaea6, 0xccc4, 0xece4, 0x2c24, 0x2c24, 0x2c24, 0x8e86, 0x8e86, 0x8c84, 0x8c84, 0xcec6, 0xcec6, 0xeee6, 0xeee6, 0x0c04, 0x1c14, 0x9c64, 0x44, 0xcb00, 0xdcd4, 0xab00, 0xfc00, 0xeb00, 0, 0x02, 0, 0, 0xf400, 0, 0, 0, 0, 0x0c04, 0x04, 0x0c00, 0, 0, 0, 0, 0, 0, 0, 0}; // $ff $ffff
|
||||
SCS misc_xabs[] = { 0x1e16, 0x3e36, 0x5e56, 0x7e76, 0xbcb4, 0, 0, 0, 0, 0x3c34, 0, 0, 0, 0x94, 0x8b94, 0xded6, 0xded6, 0xfef6, 0xfef6, 0, 0, 0x9e74, 0x54, 0, 0, 0xbb00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1c14, 0x14, 0x1c00, 0, 0, 0, 0, 0, 0x9c00, 0, 0}; // $ff,x $ffff,x
|
||||
SCS misc_yabs[] = { 0, 0, 0, 0, 0, 0xbeb6, 0, 0, 0, 0, 0, 0x96, 0x9b96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xbb00, 0x9b00, 0x9e00, 0, 0, 0}; // $ff,y $ffff,y
|
||||
|
||||
// Code tables for group GROUP_ALLJUMPS:
|
||||
// These tables are needed for finding out the correct code when the mnemonic
|
||||
|
@ -137,28 +141,15 @@ SCS jump_lind[] = { 0, 0, 0xdc00, 0, 0, 0, 0xdc00,
|
|||
#undef SCL
|
||||
|
||||
// error message strings
|
||||
static const char exception_illegal_combination[] = "Illegal combination of command and addressing mode.";
|
||||
static const char exception_illegal_combination[] = "CPU does not support this addressing mode for this mnemonic.";
|
||||
static const char exception_oversized_addrmode[] = "Using oversized addressing mode.";
|
||||
|
||||
|
||||
// Variables
|
||||
|
||||
static struct dynabuf *mnemo_dyna_buf; // dynamic buffer for mnemonics
|
||||
// predefined stuff
|
||||
static struct ronode *mnemo_6502_tree = NULL; // 6502 mnemonics
|
||||
static struct ronode *mnemo_6502undoc1_tree = NULL; // 6502 undocumented ("illegal") opcodes supported by DTV2
|
||||
static struct ronode *mnemo_6502undoc2_tree = NULL; // remaining 6502 undocumented ("illegal") opcodes (currently ANC only, maybe more will get moved)
|
||||
static struct ronode *mnemo_c64dtv2_tree = NULL; // C64DTV2 extensions (BRA/SAC/SIR)
|
||||
static struct ronode *mnemo_65c02_tree = NULL; // 65c02 extensions
|
||||
static struct ronode *mnemo_bitmanips_tree = NULL; // Rockwell's bit manipulation extensions
|
||||
static struct ronode *mnemo_stp_wai_tree = NULL; // WDC's "stp" and "wai" instructions
|
||||
static struct ronode *mnemo_65816_tree = NULL; // WDC 65816 extensions
|
||||
static struct ronode *mnemo_65ce02_tree = NULL; // CSG 65ce02/4502 extensions
|
||||
static struct ronode *mnemo_aug_tree = NULL; // CSG 65ce02's "aug" instruction
|
||||
static struct ronode *mnemo_map_eom_tree = NULL; // CSG 4502's "map" and "eom" instructions
|
||||
static struct ronode *mnemo_m65_tree = NULL; // MEGA65 extensions
|
||||
static STRUCT_DYNABUF_REF(mnemo_dyna_buf, MNEMO_INITIALSIZE); // for mnemonics
|
||||
|
||||
// Command's code, flags and group values are stored together in a single integer.
|
||||
// mnemonic's code, flags and group values are stored together in a single integer.
|
||||
// ("code" is either a table index or the opcode itself, depending on group value)
|
||||
// To extract the code, use "& CODEMASK".
|
||||
// To extract the flags, use "& FLAGSMASK".
|
||||
|
@ -177,20 +168,22 @@ static struct ronode *mnemo_m65_tree = NULL; // MEGA65 extensions
|
|||
#define MERGE(g, v) (((g) << 12) | (v))
|
||||
#define GROUP(v) ((v) >> 12)
|
||||
|
||||
static struct ronode mnemos_6502[] = {
|
||||
// 6502 mnemonics
|
||||
static struct ronode mnemo_6502_tree[] = {
|
||||
PREDEF_START,
|
||||
PREDEFNODE("ora", MERGE(GROUP_ACCU, IDX_ORA)),
|
||||
PREDEFNODE(s_and, MERGE(GROUP_ACCU, IDX_AND)),
|
||||
PREDEFNODE(s_eor, MERGE(GROUP_ACCU, IDX_EOR)),
|
||||
PREDEFNODE("and", MERGE(GROUP_ACCU, IDX_AND)),
|
||||
PREDEFNODE("eor", MERGE(GROUP_ACCU, IDX_EOR)),
|
||||
PREDEFNODE("adc", MERGE(GROUP_ACCU, IDX_ADC)),
|
||||
PREDEFNODE("sta", MERGE(GROUP_ACCU, IDX_STA)),
|
||||
PREDEFNODE("lda", MERGE(GROUP_ACCU, IDX_LDA)),
|
||||
PREDEFNODE("cmp", MERGE(GROUP_ACCU, IDX_CMP)),
|
||||
PREDEFNODE("sbc", MERGE(GROUP_ACCU, IDX_SBC)),
|
||||
PREDEFNODE("bit", MERGE(GROUP_MISC, IDX_BIT)),
|
||||
PREDEFNODE(s_asl, MERGE(GROUP_MISC, IDX_ASL)),
|
||||
PREDEFNODE("asl", MERGE(GROUP_MISC, IDX_ASL)),
|
||||
PREDEFNODE("rol", MERGE(GROUP_MISC, IDX_ROL)),
|
||||
PREDEFNODE(s_lsr, MERGE(GROUP_MISC, IDX_LSR)),
|
||||
PREDEFNODE(s_ror, MERGE(GROUP_MISC, IDX_ROR)),
|
||||
PREDEFNODE("lsr", MERGE(GROUP_MISC, IDX_LSR)),
|
||||
PREDEFNODE("ror", MERGE(GROUP_MISC, IDX_ROR)),
|
||||
PREDEFNODE("sty", MERGE(GROUP_MISC, IDX_STY)),
|
||||
PREDEFNODE("stx", MERGE(GROUP_MISC, IDX_STX)),
|
||||
PREDEFNODE("ldy", MERGE(GROUP_MISC, IDX_LDY)),
|
||||
|
@ -209,81 +202,87 @@ static struct ronode mnemos_6502[] = {
|
|||
PREDEFNODE("beq", MERGE(GROUP_RELATIVE8, 0xf0)),
|
||||
PREDEFNODE("jmp", MERGE(GROUP_ALLJUMPS, IDX_JMP)),
|
||||
PREDEFNODE("jsr", MERGE(GROUP_ALLJUMPS, IDX_JSR)),
|
||||
PREDEFNODE("brk", MERGE(GROUP_IMPLIEDONLY, 0)),
|
||||
PREDEFNODE("php", MERGE(GROUP_IMPLIEDONLY, 8)),
|
||||
PREDEFNODE("clc", MERGE(GROUP_IMPLIEDONLY, 24)),
|
||||
PREDEFNODE("plp", MERGE(GROUP_IMPLIEDONLY, 40)),
|
||||
PREDEFNODE("sec", MERGE(GROUP_IMPLIEDONLY, 56)),
|
||||
PREDEFNODE("rti", MERGE(GROUP_IMPLIEDONLY, 64)),
|
||||
PREDEFNODE("pha", MERGE(GROUP_IMPLIEDONLY, 72)),
|
||||
PREDEFNODE("cli", MERGE(GROUP_IMPLIEDONLY, 88)),
|
||||
PREDEFNODE("rts", MERGE(GROUP_IMPLIEDONLY, 96)),
|
||||
PREDEFNODE("pla", MERGE(GROUP_IMPLIEDONLY, 104)),
|
||||
PREDEFNODE("sei", MERGE(GROUP_IMPLIEDONLY, 120)),
|
||||
PREDEFNODE("dey", MERGE(GROUP_IMPLIEDONLY, 136)),
|
||||
PREDEFNODE("txa", MERGE(GROUP_IMPLIEDONLY, 138)),
|
||||
PREDEFNODE("tya", MERGE(GROUP_IMPLIEDONLY, 152)),
|
||||
PREDEFNODE("txs", MERGE(GROUP_IMPLIEDONLY, 154)),
|
||||
PREDEFNODE("tay", MERGE(GROUP_IMPLIEDONLY, 168)),
|
||||
PREDEFNODE("tax", MERGE(GROUP_IMPLIEDONLY, 170)),
|
||||
PREDEFNODE("clv", MERGE(GROUP_IMPLIEDONLY, 184)),
|
||||
PREDEFNODE("tsx", MERGE(GROUP_IMPLIEDONLY, 186)),
|
||||
PREDEFNODE("iny", MERGE(GROUP_IMPLIEDONLY, 200)),
|
||||
PREDEFNODE("dex", MERGE(GROUP_IMPLIEDONLY, 202)),
|
||||
PREDEFNODE("cld", MERGE(GROUP_IMPLIEDONLY, 216)),
|
||||
PREDEFNODE("inx", MERGE(GROUP_IMPLIEDONLY, 232)),
|
||||
PREDEFNODE("nop", MERGE(GROUP_IMPLIEDONLY, 234)),
|
||||
PREDEFLAST("sed", MERGE(GROUP_IMPLIEDONLY, 248)),
|
||||
PREDEFNODE("brk", MERGE(GROUP_IMPLIEDONLY, 0x00)),
|
||||
PREDEFNODE("php", MERGE(GROUP_IMPLIEDONLY, 0x08)),
|
||||
PREDEFNODE("clc", MERGE(GROUP_IMPLIEDONLY, 0x18)),
|
||||
PREDEFNODE("plp", MERGE(GROUP_IMPLIEDONLY, 0x28)),
|
||||
PREDEFNODE("sec", MERGE(GROUP_IMPLIEDONLY, 0x38)),
|
||||
PREDEFNODE("rti", MERGE(GROUP_IMPLIEDONLY, 0x40)),
|
||||
PREDEFNODE("pha", MERGE(GROUP_IMPLIEDONLY, 0x48)),
|
||||
PREDEFNODE("cli", MERGE(GROUP_IMPLIEDONLY, 0x58)),
|
||||
PREDEFNODE("rts", MERGE(GROUP_IMPLIEDONLY, 0x60)),
|
||||
PREDEFNODE("pla", MERGE(GROUP_IMPLIEDONLY, 0x68)),
|
||||
PREDEFNODE("sei", MERGE(GROUP_IMPLIEDONLY, 0x78)),
|
||||
PREDEFNODE("dey", MERGE(GROUP_IMPLIEDONLY, 0x88)),
|
||||
PREDEFNODE("txa", MERGE(GROUP_IMPLIEDONLY, 0x8a)),
|
||||
PREDEFNODE("tya", MERGE(GROUP_IMPLIEDONLY, 0x98)),
|
||||
PREDEFNODE("txs", MERGE(GROUP_IMPLIEDONLY, 0x9a)),
|
||||
PREDEFNODE("tay", MERGE(GROUP_IMPLIEDONLY, 0xa8)),
|
||||
PREDEFNODE("tax", MERGE(GROUP_IMPLIEDONLY, 0xaa)),
|
||||
PREDEFNODE("clv", MERGE(GROUP_IMPLIEDONLY, 0xb8)),
|
||||
PREDEFNODE("tsx", MERGE(GROUP_IMPLIEDONLY, 0xba)),
|
||||
PREDEFNODE("iny", MERGE(GROUP_IMPLIEDONLY, 0xc8)),
|
||||
PREDEFNODE("dex", MERGE(GROUP_IMPLIEDONLY, 0xca)),
|
||||
PREDEFNODE("cld", MERGE(GROUP_IMPLIEDONLY, 0xd8)),
|
||||
PREDEFNODE("inx", MERGE(GROUP_IMPLIEDONLY, 0xe8)),
|
||||
PREDEFNODE("nop", MERGE(GROUP_IMPLIEDONLY, 0xea)),
|
||||
PREDEF_END("sed", MERGE(GROUP_IMPLIEDONLY, 0xf8)),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
// undocumented opcodes of the NMOS 6502 that are also supported by c64dtv2:
|
||||
static struct ronode mnemos_6502undoc1[] = {
|
||||
static struct ronode mnemo_6502undoc1_tree[] = {
|
||||
PREDEF_START,
|
||||
PREDEFNODE("slo", MERGE(GROUP_ACCU, IDXuSLO)), // ASL + ORA (aka ASO)
|
||||
PREDEFNODE("rla", MERGE(GROUP_ACCU, IDXuRLA)), // ROL + AND
|
||||
PREDEFNODE("rla", MERGE(GROUP_ACCU, IDXuRLA)), // ROL + AND (aka RLN)
|
||||
PREDEFNODE("sre", MERGE(GROUP_ACCU, IDXuSRE)), // LSR + EOR (aka LSE)
|
||||
PREDEFNODE("rra", MERGE(GROUP_ACCU, IDXuRRA)), // ROR + ADC
|
||||
PREDEFNODE("sax", MERGE(GROUP_ACCU, IDXuSAX)), // STX + STA (aka AXS aka AAX)
|
||||
PREDEFNODE("rra", MERGE(GROUP_ACCU, IDXuRRA)), // ROR + ADC (aka RRD)
|
||||
PREDEFNODE("sax", MERGE(GROUP_ACCU, IDXuSAX)), // store A & X (aka AXS/AAX)
|
||||
PREDEFNODE("lax", MERGE(GROUP_ACCU, IDXuLAX)), // LDX + LDA
|
||||
PREDEFNODE("dcp", MERGE(GROUP_ACCU, IDXuDCP)), // DEC + CMP (aka DCM)
|
||||
PREDEFNODE("isc", MERGE(GROUP_ACCU, IDXuISC)), // INC + SBC (aka ISB aka INS)
|
||||
PREDEFNODE("las", MERGE(GROUP_MISC, IDXuLAS)), // A,X,S = {addr} & S (aka LAR aka LAE)
|
||||
PREDEFNODE("tas", MERGE(GROUP_MISC, IDXuTAS)), // S = A & X {addr} = A&X& {H+1} (aka SHS aka XAS)
|
||||
PREDEFNODE("sha", MERGE(GROUP_ACCU, IDXuSHA)), // {addr} = A & X & {H+1} (aka AXA aka AHX)
|
||||
PREDEFNODE("shx", MERGE(GROUP_MISC, IDXuSHX)), // {addr} = X & {H+1} (aka XAS aka SXA)
|
||||
PREDEFNODE("shy", MERGE(GROUP_MISC, IDXuSHY)), // {addr} = Y & {H+1} (aka SAY aka SYA)
|
||||
PREDEFNODE(s_asr, MERGE(GROUP_MISC, IDXuASR)), // LSR + EOR (aka ALR)
|
||||
PREDEFNODE("arr", MERGE(GROUP_MISC, IDXuARR)), // ROR + ADC
|
||||
PREDEFNODE("sbx", MERGE(GROUP_MISC, IDXuSBX)), // DEX + CMP (aka AXS aka SAX)
|
||||
PREDEFNODE("isc", MERGE(GROUP_ACCU, IDXuISC)), // INC + SBC (aka ISB/INS)
|
||||
PREDEFNODE("las", MERGE(GROUP_MISC, IDXuLAS)), // A,X,S = {addr} & S (aka LAR/LAE)
|
||||
PREDEFNODE("tas", MERGE(GROUP_MISC, IDXuTAS)), // S = A & X {addr} = A&X& {H+1} (aka SHS/XAS)
|
||||
PREDEFNODE("sha", MERGE(GROUP_ACCU, IDXuSHA)), // {addr} = A & X & {H+1} (aka AXA/AHX)
|
||||
PREDEFNODE("shx", MERGE(GROUP_MISC, IDXuSHX)), // {addr} = X & {H+1} (aka XAS/SXA)
|
||||
PREDEFNODE("shy", MERGE(GROUP_MISC, IDXuSHY)), // {addr} = Y & {H+1} (aka SAY/SYA)
|
||||
PREDEFNODE("alr", MERGE(GROUP_MISC, IDXuALR)), // A = A & arg, then LSR (aka ASR)
|
||||
PREDEFNODE("asr", MERGE(GROUP_MISC, IDXuALR)), // A = A & arg, then LSR (aka ALR)
|
||||
PREDEFNODE("arr", MERGE(GROUP_MISC, IDXuARR)), // A = A & arg, then ROR
|
||||
PREDEFNODE("sbx", MERGE(GROUP_MISC, IDXuSBX)), // X = (A & X) - arg (aka AXS/SAX)
|
||||
PREDEFNODE("nop", MERGE(GROUP_MISC, IDXuNOP)), // combines documented $ea and the undocumented dop/top below
|
||||
PREDEFNODE("dop", MERGE(GROUP_MISC, IDXuDOP)), // "double nop" (skip next byte)
|
||||
PREDEFNODE("top", MERGE(GROUP_MISC, IDXuTOP)), // "triple nop" (skip next word)
|
||||
PREDEFNODE("jam", MERGE(GROUP_MISC, IDXuJAM)), // jam/crash/kill/halt-and-catch-fire
|
||||
PREDEFNODE("ane", MERGE(GROUP_MISC, IDXuANE)), // A = (A | ??) & X & arg (aka XAA)
|
||||
PREDEFLAST("lxa", MERGE(GROUP_MISC, IDXuLXA)), // A,X = (A | ??) & arg (aka OAL aka ATX)
|
||||
PREDEFNODE("ane", MERGE(GROUP_MISC, IDXuANE)), // A = (A | ??) & X & arg (aka XAA/AXM)
|
||||
PREDEFNODE("lxa", MERGE(GROUP_MISC, IDXuLXA)), // A,X = (A | ??) & arg (aka LAX/ATX/OAL)
|
||||
PREDEF_END("jam", MERGE(GROUP_IMPLIEDONLY, 0x02)), // jam/crash/kill/halt-and-catch-fire
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
// undocumented opcodes of the NMOS 6502 that are _not_ supported by c64dtv2:
|
||||
static struct ronode mnemos_6502undoc2[] = {
|
||||
PREDEFLAST("anc", MERGE(GROUP_MISC, IDXuANC)), // ROL + AND, ASL + ORA (aka AAC)
|
||||
// (currently ANC only, maybe more will get moved)
|
||||
static struct ronode mnemo_6502undoc2_tree[] = {
|
||||
PREDEF_START,
|
||||
PREDEF_END("anc", MERGE(GROUP_MISC, IDXuANC)), // A = A & arg, then C=N (aka ANA, ANB)
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
// additional opcodes of c64dtv2:
|
||||
static struct ronode mnemos_c64dtv2[] = {
|
||||
PREDEFNODE(s_bra, MERGE(GROUP_RELATIVE8, 0x12)), // branch always
|
||||
static struct ronode mnemo_c64dtv2_tree[] = {
|
||||
PREDEF_START,
|
||||
PREDEFNODE("bra", MERGE(GROUP_RELATIVE8, 0x12)), // branch always
|
||||
PREDEFNODE("sac", MERGE(GROUP_MISC, IDX_SAC)), // set accumulator mapping
|
||||
PREDEFLAST("sir", MERGE(GROUP_MISC, IDX_SIR)), // set index register mapping
|
||||
PREDEF_END("sir", MERGE(GROUP_MISC, IDX_SIR)), // set index register mapping
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
// new stuff in CMOS re-design:
|
||||
static struct ronode mnemos_65c02[] = {
|
||||
static struct ronode mnemo_65c02_tree[] = {
|
||||
PREDEF_START,
|
||||
// more addressing modes for some mnemonics:
|
||||
PREDEFNODE("ora", MERGE(GROUP_ACCU, IDXcORA)),
|
||||
PREDEFNODE(s_and, MERGE(GROUP_ACCU, IDXcAND)),
|
||||
PREDEFNODE(s_eor, MERGE(GROUP_ACCU, IDXcEOR)),
|
||||
PREDEFNODE("and", MERGE(GROUP_ACCU, IDXcAND)),
|
||||
PREDEFNODE("eor", MERGE(GROUP_ACCU, IDXcEOR)),
|
||||
PREDEFNODE("adc", MERGE(GROUP_ACCU, IDXcADC)),
|
||||
PREDEFNODE("sta", MERGE(GROUP_ACCU, IDXcSTA)),
|
||||
PREDEFNODE("lda", MERGE(GROUP_ACCU, IDXcLDA)),
|
||||
|
@ -294,19 +293,20 @@ static struct ronode mnemos_65c02[] = {
|
|||
PREDEFNODE("dec", MERGE(GROUP_MISC, IDXcDEC)),
|
||||
PREDEFNODE("inc", MERGE(GROUP_MISC, IDXcINC)),
|
||||
// and eight new mnemonics:
|
||||
PREDEFNODE(s_bra, MERGE(GROUP_RELATIVE8, 0x80)),
|
||||
PREDEFNODE("phy", MERGE(GROUP_IMPLIEDONLY, 90)),
|
||||
PREDEFNODE("ply", MERGE(GROUP_IMPLIEDONLY, 122)),
|
||||
PREDEFNODE("phx", MERGE(GROUP_IMPLIEDONLY, 218)),
|
||||
PREDEFNODE("plx", MERGE(GROUP_IMPLIEDONLY, 250)),
|
||||
PREDEFNODE("bra", MERGE(GROUP_RELATIVE8, 0x80)),
|
||||
PREDEFNODE("phy", MERGE(GROUP_IMPLIEDONLY, 0x5a)),
|
||||
PREDEFNODE("ply", MERGE(GROUP_IMPLIEDONLY, 0x7a)),
|
||||
PREDEFNODE("phx", MERGE(GROUP_IMPLIEDONLY, 0xda)),
|
||||
PREDEFNODE("plx", MERGE(GROUP_IMPLIEDONLY, 0xfa)),
|
||||
PREDEFNODE("tsb", MERGE(GROUP_MISC, IDXcTSB)),
|
||||
PREDEFNODE("trb", MERGE(GROUP_MISC, IDXcTRB)),
|
||||
PREDEFLAST("stz", MERGE(GROUP_MISC, IDXcSTZ)),
|
||||
PREDEF_END("stz", MERGE(GROUP_MISC, IDXcSTZ)),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
// bit-manipulation extensions (by Rockwell?)
|
||||
static struct ronode mnemos_bitmanips[] = {
|
||||
static struct ronode mnemo_bitmanips_tree[] = {
|
||||
PREDEF_START,
|
||||
PREDEFNODE("rmb0", MERGE(GROUP_ZPONLY, 0x07)),
|
||||
PREDEFNODE("rmb1", MERGE(GROUP_ZPONLY, 0x17)),
|
||||
PREDEFNODE("rmb2", MERGE(GROUP_ZPONLY, 0x27)),
|
||||
|
@ -338,19 +338,21 @@ static struct ronode mnemos_bitmanips[] = {
|
|||
PREDEFNODE("bbs4", MERGE(GROUP_BITBRANCH, 0xcf)),
|
||||
PREDEFNODE("bbs5", MERGE(GROUP_BITBRANCH, 0xdf)),
|
||||
PREDEFNODE("bbs6", MERGE(GROUP_BITBRANCH, 0xef)),
|
||||
PREDEFLAST("bbs7", MERGE(GROUP_BITBRANCH, 0xff)),
|
||||
PREDEF_END("bbs7", MERGE(GROUP_BITBRANCH, 0xff)),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
// "stp" and "wai" extensions by WDC:
|
||||
static struct ronode mnemos_stp_wai[] = {
|
||||
PREDEFNODE("stp", MERGE(GROUP_IMPLIEDONLY, 219)),
|
||||
PREDEFLAST("wai", MERGE(GROUP_IMPLIEDONLY, 203)),
|
||||
static struct ronode mnemo_stp_wai_tree[] = {
|
||||
PREDEF_START,
|
||||
PREDEFNODE("wai", MERGE(GROUP_IMPLIEDONLY, 0xcb)),
|
||||
PREDEF_END("stp", MERGE(GROUP_IMPLIEDONLY, 0xdb)),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
// most of the 65816 stuff
|
||||
static struct ronode mnemos_65816[] = {
|
||||
// the 65816 stuff
|
||||
static struct ronode mnemo_65816_tree[] = {
|
||||
PREDEF_START,
|
||||
// CAUTION - these use 6502/65c02 indices, because the opcodes are the same - but I need flags for immediate mode!
|
||||
PREDEFNODE("ldy", MERGE(GROUP_MISC, IDX_LDY | IM_INDEXREGS)),
|
||||
PREDEFNODE("ldx", MERGE(GROUP_MISC, IDX_LDX | IM_INDEXREGS)),
|
||||
|
@ -359,8 +361,8 @@ static struct ronode mnemos_65816[] = {
|
|||
PREDEFNODE("bit", MERGE(GROUP_MISC, IDXcBIT | IM_ACCUMULATOR)),
|
||||
// more addressing modes for some mnemonics:
|
||||
PREDEFNODE("ora", MERGE(GROUP_ACCU, IDX16ORA | IM_ACCUMULATOR)),
|
||||
PREDEFNODE(s_and, MERGE(GROUP_ACCU, IDX16AND | IM_ACCUMULATOR)),
|
||||
PREDEFNODE(s_eor, MERGE(GROUP_ACCU, IDX16EOR | IM_ACCUMULATOR)),
|
||||
PREDEFNODE("and", MERGE(GROUP_ACCU, IDX16AND | IM_ACCUMULATOR)),
|
||||
PREDEFNODE("eor", MERGE(GROUP_ACCU, IDX16EOR | IM_ACCUMULATOR)),
|
||||
PREDEFNODE("adc", MERGE(GROUP_ACCU, IDX16ADC | IM_ACCUMULATOR)),
|
||||
PREDEFNODE("sta", MERGE(GROUP_ACCU, IDX16STA)),
|
||||
PREDEFNODE("lda", MERGE(GROUP_ACCU, IDX16LDA | IM_ACCUMULATOR)),
|
||||
|
@ -374,36 +376,39 @@ static struct ronode mnemos_65816[] = {
|
|||
PREDEFNODE("jsl", MERGE(GROUP_ALLJUMPS, IDX16JSL)),
|
||||
PREDEFNODE("mvp", MERGE(GROUP_BOTHMOVES, 0x44)),
|
||||
PREDEFNODE("mvn", MERGE(GROUP_BOTHMOVES, 0x54)),
|
||||
PREDEFNODE("per", MERGE(GROUP_REL16_3, 98)),
|
||||
PREDEFNODE(s_brl, MERGE(GROUP_REL16_3, 130)),
|
||||
PREDEFNODE("per", MERGE(GROUP_REL16_3, 0x62)),
|
||||
PREDEFNODE("brl", MERGE(GROUP_REL16_3, 0x82)),
|
||||
PREDEFNODE("cop", MERGE(GROUP_MISC, IDX16COP)),
|
||||
PREDEFNODE("rep", MERGE(GROUP_MISC, IDX16REP)),
|
||||
PREDEFNODE("sep", MERGE(GROUP_MISC, IDX16SEP)),
|
||||
PREDEFNODE("pea", MERGE(GROUP_MISC, IDX16PEA)),
|
||||
PREDEFNODE("phd", MERGE(GROUP_IMPLIEDONLY, 11)),
|
||||
PREDEFNODE("tcs", MERGE(GROUP_IMPLIEDONLY, 27)),
|
||||
PREDEFNODE("pld", MERGE(GROUP_IMPLIEDONLY, 43)),
|
||||
PREDEFNODE("tsc", MERGE(GROUP_IMPLIEDONLY, 59)),
|
||||
PREDEFNODE("wdm", MERGE(GROUP_IMPLIEDONLY, 66)),
|
||||
PREDEFNODE("phk", MERGE(GROUP_IMPLIEDONLY, 75)),
|
||||
PREDEFNODE("tcd", MERGE(GROUP_IMPLIEDONLY, 91)),
|
||||
PREDEFNODE("rtl", MERGE(GROUP_IMPLIEDONLY, 107)),
|
||||
PREDEFNODE("tdc", MERGE(GROUP_IMPLIEDONLY, 123)),
|
||||
PREDEFNODE("phb", MERGE(GROUP_IMPLIEDONLY, 139)),
|
||||
PREDEFNODE("txy", MERGE(GROUP_IMPLIEDONLY, 155)),
|
||||
PREDEFNODE("plb", MERGE(GROUP_IMPLIEDONLY, 171)),
|
||||
PREDEFNODE("tyx", MERGE(GROUP_IMPLIEDONLY, 187)),
|
||||
PREDEFNODE("xba", MERGE(GROUP_IMPLIEDONLY, 235)),
|
||||
PREDEFLAST("xce", MERGE(GROUP_IMPLIEDONLY, 251)),
|
||||
PREDEFNODE("phd", MERGE(GROUP_IMPLIEDONLY, 0x0b)),
|
||||
PREDEFNODE("tcs", MERGE(GROUP_IMPLIEDONLY, 0x1b)),
|
||||
PREDEFNODE("pld", MERGE(GROUP_IMPLIEDONLY, 0x2b)),
|
||||
PREDEFNODE("tsc", MERGE(GROUP_IMPLIEDONLY, 0x3b)),
|
||||
PREDEFNODE("phk", MERGE(GROUP_IMPLIEDONLY, 0x4b)),
|
||||
PREDEFNODE("tcd", MERGE(GROUP_IMPLIEDONLY, 0x5b)),
|
||||
PREDEFNODE("rtl", MERGE(GROUP_IMPLIEDONLY, 0x6b)),
|
||||
PREDEFNODE("tdc", MERGE(GROUP_IMPLIEDONLY, 0x7b)),
|
||||
PREDEFNODE("phb", MERGE(GROUP_IMPLIEDONLY, 0x8b)),
|
||||
PREDEFNODE("txy", MERGE(GROUP_IMPLIEDONLY, 0x9b)),
|
||||
PREDEFNODE("plb", MERGE(GROUP_IMPLIEDONLY, 0xab)),
|
||||
PREDEFNODE("tyx", MERGE(GROUP_IMPLIEDONLY, 0xbb)),
|
||||
// 0xcb is WAI
|
||||
// 0xdb is STP
|
||||
PREDEFNODE("xba", MERGE(GROUP_IMPLIEDONLY, 0xeb)),
|
||||
PREDEFNODE("xce", MERGE(GROUP_IMPLIEDONLY, 0xfb)),
|
||||
PREDEF_END("wdm", MERGE(GROUP_IMPLIEDONLY, 0x42)),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
// 65ce02 has 46 new opcodes and a few changes:
|
||||
static struct ronode mnemos_65ce02[] = {
|
||||
static struct ronode mnemo_65ce02_tree[] = {
|
||||
PREDEF_START,
|
||||
// 65ce02 changes (zp) addressing of 65c02 to (zp),z addressing:
|
||||
PREDEFNODE("ora", MERGE(GROUP_ACCU, IDXeORA)),
|
||||
PREDEFNODE(s_and, MERGE(GROUP_ACCU, IDXeAND)),
|
||||
PREDEFNODE(s_eor, MERGE(GROUP_ACCU, IDXeEOR)),
|
||||
PREDEFNODE("and", MERGE(GROUP_ACCU, IDXeAND)),
|
||||
PREDEFNODE("eor", MERGE(GROUP_ACCU, IDXeEOR)),
|
||||
PREDEFNODE("adc", MERGE(GROUP_ACCU, IDXeADC)),
|
||||
PREDEFNODE("sta", MERGE(GROUP_ACCU, IDXeSTA)), // +1 for (8,s),y
|
||||
PREDEFNODE("lda", MERGE(GROUP_ACCU, IDXeLDA)), // +1 for (8,s),y
|
||||
|
@ -430,8 +435,8 @@ static struct ronode mnemos_65ce02[] = {
|
|||
PREDEFNODE("asr", MERGE(GROUP_MISC, IDXeASR)),
|
||||
PREDEFNODE("asw", MERGE(GROUP_MISC, IDXeASW)),
|
||||
PREDEFNODE("cpz", MERGE(GROUP_MISC, IDXeCPZ)),
|
||||
PREDEFNODE("dew", MERGE(GROUP_MISC, IDXeDEW)),
|
||||
PREDEFNODE("inw", MERGE(GROUP_MISC, IDXeINW)),
|
||||
PREDEFNODE("dew", MERGE(GROUP_ZPONLY, 0xc3)),
|
||||
PREDEFNODE("inw", MERGE(GROUP_ZPONLY, 0xe3)),
|
||||
PREDEFNODE("ldz", MERGE(GROUP_MISC, IDXeLDZ)),
|
||||
PREDEFNODE("phw", MERGE(GROUP_MISC, IDXePHW | IM_FORCE16)), // when using immediate addressing, arg is 16 bit
|
||||
PREDEFNODE("row", MERGE(GROUP_MISC, IDXeROW)),
|
||||
|
@ -448,25 +453,28 @@ static struct ronode mnemos_65ce02[] = {
|
|||
PREDEFNODE("tza", MERGE(GROUP_IMPLIEDONLY, 0x6b)),
|
||||
PREDEFNODE("tba", MERGE(GROUP_IMPLIEDONLY, 0x7b)),
|
||||
PREDEFNODE("phz", MERGE(GROUP_IMPLIEDONLY, 0xdb)),
|
||||
PREDEFLAST("plz", MERGE(GROUP_IMPLIEDONLY, 0xfb)),
|
||||
PREDEF_END("plz", MERGE(GROUP_IMPLIEDONLY, 0xfb)),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
// 65ce02's "aug" opcode:
|
||||
static struct ronode mnemos_aug[] = {
|
||||
PREDEFLAST("aug", MERGE(GROUP_IMPLIEDONLY, 0x5c)), // actually a "4-byte NOP reserved for future expansion"
|
||||
static struct ronode mnemo_aug_tree[] = {
|
||||
PREDEF_START,
|
||||
PREDEF_END("aug", MERGE(GROUP_IMPLIEDONLY, 0x5c)), // actually a "4-byte NOP reserved for future expansion"
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
// 4502's "map" and "eom" opcodes:
|
||||
static struct ronode mnemos_map_eom[] = {
|
||||
static struct ronode mnemo_map_eom_tree[] = {
|
||||
PREDEF_START,
|
||||
PREDEFNODE("map", MERGE(GROUP_IMPLIEDONLY, 0x5c)), // change memory mapping
|
||||
PREDEFLAST("eom", MERGE(GROUP_IMPLIEDONLY, 0xea)), // actually the NOP opcode
|
||||
PREDEF_END("eom", MERGE(GROUP_IMPLIEDONLY, 0xea)), // actually the NOP opcode
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
// m65 has a few extensions using prefix codes:
|
||||
static struct ronode mnemos_m65[] = {
|
||||
static struct ronode mnemo_m65_tree[] = {
|
||||
PREDEF_START,
|
||||
// extension 1:
|
||||
// a NOP prefix changes ($ff),z addressing from using 16-bit pointers to
|
||||
// using 32-bit pointers. I chose "[$ff],z" to indicate this.
|
||||
|
@ -481,7 +489,11 @@ static struct ronode mnemos_m65[] = {
|
|||
// ...now ASLQ/LSRQ/ROLQ/RORQ
|
||||
// INC/DEC
|
||||
// ...now INQ/DEQ
|
||||
// it works with all addressing modes (beware of index register usage!)
|
||||
// BIT
|
||||
// ...now BITQ
|
||||
// ASR
|
||||
// ...now ASRQ
|
||||
// it works with most addressing modes (beware of index register usage!)
|
||||
// except for immediate addressing and "($ff),z", which becomes "($ff)"
|
||||
// extension 3:
|
||||
// extensions 1 and 2 can be combined (NEG:NEG:NOP prefix), then
|
||||
|
@ -509,39 +521,21 @@ static struct ronode mnemos_m65[] = {
|
|||
PREDEFNODE("rorq", MERGE(GROUP_MISC, IDX_ROR | PREFIX_NEGNEG)),
|
||||
PREDEFNODE("inq", MERGE(GROUP_MISC, IDXcINC | PREFIX_NEGNEG)),
|
||||
PREDEFNODE("deq", MERGE(GROUP_MISC, IDXcDEC | PREFIX_NEGNEG)),
|
||||
PREDEFNODE("bitq", MERGE(GROUP_MISC, IDXmBITQ | PREFIX_NEGNEG)),
|
||||
PREDEFNODE("asrq", MERGE(GROUP_MISC, IDXeASR | PREFIX_NEGNEG)),
|
||||
// because the NOP opcode is used as a prefix code, the mnemonic was disabled:
|
||||
PREDEFLAST("nop", MERGE(GROUP_PREFIX, 0xea)),
|
||||
PREDEF_END("nop", MERGE(GROUP_PREFIX, 0xea)),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
// Functions
|
||||
|
||||
// create dynamic buffer, build keyword trees
|
||||
void Mnemo_init(void)
|
||||
{
|
||||
mnemo_dyna_buf = DynaBuf_create(MNEMO_DYNABUF_INITIALSIZE);
|
||||
Tree_add_table(&mnemo_6502_tree, mnemos_6502);
|
||||
Tree_add_table(&mnemo_6502undoc1_tree, mnemos_6502undoc1);
|
||||
Tree_add_table(&mnemo_6502undoc2_tree, mnemos_6502undoc2);
|
||||
Tree_add_table(&mnemo_c64dtv2_tree, mnemos_c64dtv2);
|
||||
Tree_add_table(&mnemo_65c02_tree, mnemos_65c02);
|
||||
Tree_add_table(&mnemo_bitmanips_tree, mnemos_bitmanips);
|
||||
Tree_add_table(&mnemo_stp_wai_tree, mnemos_stp_wai);
|
||||
Tree_add_table(&mnemo_65816_tree, mnemos_65816);
|
||||
Tree_add_table(&mnemo_65ce02_tree, mnemos_65ce02);
|
||||
Tree_add_table(&mnemo_aug_tree, mnemos_aug);
|
||||
Tree_add_table(&mnemo_map_eom_tree, mnemos_map_eom);
|
||||
Tree_add_table(&mnemo_m65_tree, mnemos_m65);
|
||||
}
|
||||
|
||||
|
||||
// Address mode parsing
|
||||
|
||||
// utility function for parsing indices. result must be processed via AMB_PREINDEX() or AMB_INDEX() macro!
|
||||
static int get_index(boolean next)
|
||||
// TODO: add pointer arg for result, use return value to indicate parse error!
|
||||
static int get_index(void)
|
||||
{
|
||||
if (next)
|
||||
GetByte();
|
||||
if (!Input_accept_comma())
|
||||
return INDEX_NONE;
|
||||
|
||||
|
@ -592,6 +586,7 @@ static void get_int_arg(struct number *result, boolean complain_about_indirect)
|
|||
|
||||
// wrapper function to detect addressing mode, and, if not IMPLIED, read arg.
|
||||
// argument is stored in given result structure, addressing mode is returned.
|
||||
// TODO: add pointer arg for result, use return value to indicate parse error!
|
||||
static bits get_addr_mode(struct number *result)
|
||||
{
|
||||
struct expression expression;
|
||||
|
@ -612,13 +607,15 @@ static bits get_addr_mode(struct number *result)
|
|||
GetByte(); // proceed with next char
|
||||
get_int_arg(result, FALSE);
|
||||
typesystem_want_addr(result);
|
||||
if (GotByte == ']')
|
||||
address_mode_bits = AMB_LONGINDIRECT | AMB_INDEX(get_index(TRUE));
|
||||
else
|
||||
if (GotByte == ']') {
|
||||
GetByte();
|
||||
address_mode_bits = AMB_LONGINDIRECT | AMB_INDEX(get_index());
|
||||
} else {
|
||||
Throw_error(exception_syntax);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ALU_addrmode_int(&expression, 1); // direct call instead of wrapper, to allow for "(...,"
|
||||
ALU_addrmode_int(&expression, 1); // direct call instead of wrapper, to allow for "(EXPR,x)" where parsing stops at comma
|
||||
*result = expression.result.u.number;
|
||||
typesystem_want_addr(result);
|
||||
// check for indirect addressing
|
||||
|
@ -628,14 +625,15 @@ static bits get_addr_mode(struct number *result)
|
|||
if (expression.open_parentheses) {
|
||||
// in case there are still open parentheses,
|
||||
// read internal index
|
||||
address_mode_bits |= AMB_PREINDEX(get_index(FALSE));
|
||||
if (GotByte == ')')
|
||||
address_mode_bits |= AMB_PREINDEX(get_index());
|
||||
if (GotByte == ')') {
|
||||
GetByte(); // go on with next char
|
||||
else
|
||||
} else {
|
||||
Throw_error(exception_syntax);
|
||||
}
|
||||
}
|
||||
// check for external index (after closing parenthesis)
|
||||
address_mode_bits |= AMB_INDEX(get_index(FALSE));
|
||||
address_mode_bits |= AMB_INDEX(get_index());
|
||||
}
|
||||
// ensure end of line
|
||||
Input_ensure_EOS();
|
||||
|
@ -672,6 +670,7 @@ static bits check_oversize(bits size_bit, struct number *argument)
|
|||
// argument value and flags of parameter
|
||||
// addressing_modes adressing modes (8b, 16b, 24b or any combination)
|
||||
// Return value = force bit for number of parameter bytes to send (0 = error)
|
||||
// TODO: add pointer arg for result, use return value to indicate error ONLY!
|
||||
static bits calc_arg_size(bits force_bit, struct number *argument, bits addressing_modes)
|
||||
{
|
||||
// if there are no possible addressing modes, complain
|
||||
|
@ -679,18 +678,18 @@ static bits calc_arg_size(bits force_bit, struct number *argument, bits addressi
|
|||
Throw_error(exception_illegal_combination);
|
||||
return 0;
|
||||
}
|
||||
// if command has force bit, act upon it
|
||||
// if a force bit postfix was given, act upon it
|
||||
if (force_bit) {
|
||||
// if command allows this force bit, return it
|
||||
// if mnemonic supports this force bit, return it
|
||||
if (addressing_modes & force_bit)
|
||||
return force_bit;
|
||||
|
||||
// if not, complain
|
||||
Throw_error("Illegal combination of command and postfix.");
|
||||
Throw_error("CPU does not support this postfix for this mnemonic.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Command has no force bit. Check whether value has one
|
||||
// mnemonic did not have a force bit postfix.
|
||||
// if value has force bit, act upon it
|
||||
if (argument->flags & NUMBER_FORCEBITS) {
|
||||
// Value has force bit set, so return this or bigger size
|
||||
|
@ -711,26 +710,30 @@ static bits calc_arg_size(bits force_bit, struct number *argument, bits addressi
|
|||
// if only one addressing mode, use that
|
||||
if ((addressing_modes == NUMBER_FORCES_8)
|
||||
|| (addressing_modes == NUMBER_FORCES_16)
|
||||
|| (addressing_modes == NUMBER_FORCES_24))
|
||||
|| (addressing_modes == NUMBER_FORCES_24)) {
|
||||
return addressing_modes; // There's only one, so use it
|
||||
}
|
||||
|
||||
// There's more than one addressing mode. Check whether value is sure
|
||||
// if value is unsure, use default size
|
||||
if (argument->flags & NUMBER_EVER_UNDEFINED) {
|
||||
// if there is an 8-bit addressing mode *and* the value
|
||||
// is sure to fit into 8 bits, use the 8-bit mode
|
||||
if ((addressing_modes & NUMBER_FORCES_8) && (argument->flags & NUMBER_FITS_BYTE))
|
||||
if ((addressing_modes & NUMBER_FORCES_8) && (argument->flags & NUMBER_FITS_BYTE)) {
|
||||
return NUMBER_FORCES_8;
|
||||
}
|
||||
|
||||
// if there is a 16-bit addressing, use that
|
||||
// call helper function for "oversized addr mode" warning
|
||||
if (NUMBER_FORCES_16 & addressing_modes)
|
||||
if (NUMBER_FORCES_16 & addressing_modes) {
|
||||
return check_oversize(NUMBER_FORCES_16, argument);
|
||||
}
|
||||
|
||||
// if there is a 24-bit addressing, use that
|
||||
// call helper function for "oversized addr mode" warning
|
||||
if (NUMBER_FORCES_24 & addressing_modes)
|
||||
if (NUMBER_FORCES_24 & addressing_modes) {
|
||||
return check_oversize(NUMBER_FORCES_24, argument);
|
||||
}
|
||||
|
||||
// otherwise, use 8-bit-addressing, which will raise an
|
||||
// error later on if the value won't fit
|
||||
|
@ -746,17 +749,20 @@ static bits calc_arg_size(bits force_bit, struct number *argument, bits addressi
|
|||
|
||||
// Value is positive or zero. Check size ranges
|
||||
// if there is an 8-bit addressing mode and value fits, use 8 bits
|
||||
if ((addressing_modes & NUMBER_FORCES_8) && (argument->val.intval < 256))
|
||||
if ((addressing_modes & NUMBER_FORCES_8) && (argument->val.intval < 256)) {
|
||||
return NUMBER_FORCES_8;
|
||||
}
|
||||
|
||||
// if there is a 16-bit addressing mode and value fits, use 16 bits
|
||||
if ((addressing_modes & NUMBER_FORCES_16) && (argument->val.intval < 65536))
|
||||
if ((addressing_modes & NUMBER_FORCES_16) && (argument->val.intval < 65536)) {
|
||||
return NUMBER_FORCES_16;
|
||||
}
|
||||
|
||||
// if there is a 24-bit addressing mode, use that. In case the
|
||||
// value doesn't fit, the output function will do the complaining.
|
||||
if (addressing_modes & NUMBER_FORCES_24)
|
||||
if (addressing_modes & NUMBER_FORCES_24) {
|
||||
return NUMBER_FORCES_24;
|
||||
}
|
||||
|
||||
// Value is too big for all possible addressing modes
|
||||
Throw_error(exception_number_out_of_range);
|
||||
|
@ -766,8 +772,10 @@ static bits calc_arg_size(bits force_bit, struct number *argument, bits addressi
|
|||
// Mnemonics using only implied addressing.
|
||||
static void group_only_implied_addressing(int opcode)
|
||||
{
|
||||
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
|
||||
// TODO - accept argument and complain about it? error message should tell more than "garbage data at end of line"!
|
||||
// for 65ce02 and 4502, warn about buggy decimal mode
|
||||
if ((opcode == 248) && (CPU_state.type->flags & CPUFLAG_DECIMALSUBTRACTBUGGY))
|
||||
if ((opcode == 0xf8) && (CPU_state.type->flags & CPUFLAG_DECIMALSUBTRACTBUGGY))
|
||||
Throw_first_pass_warning("Found SED instruction for CPU with known decimal SBC bug.");
|
||||
Output_byte(opcode);
|
||||
Input_ensure_EOS();
|
||||
|
@ -841,7 +849,7 @@ static void far_branch(int preoffset)
|
|||
|
||||
// set addressing mode bits depending on which opcodes exist, then calculate
|
||||
// argument size and output both opcode and argument
|
||||
static void make_command(bits force_bit, struct number *result, unsigned long opcodes)
|
||||
static void make_instruction(bits force_bit, struct number *result, unsigned long opcodes)
|
||||
{
|
||||
int addressing_modes = MAYBE______;
|
||||
|
||||
|
@ -922,52 +930,52 @@ static void group_main(int index, bits flags)
|
|||
immediate_opcodes = imm_ops(&force_bit, accu_imm[index], flags & IMMASK);
|
||||
// CAUTION - do not incorporate the line above into the line
|
||||
// below - "force_bit" might be undefined (depends on compiler).
|
||||
make_command(force_bit, &result, immediate_opcodes);
|
||||
make_instruction(force_bit, &result, immediate_opcodes);
|
||||
break;
|
||||
case ABSOLUTE_ADDRESSING: // $ff, $ffff, $ffffff
|
||||
make_command(force_bit, &result, accu_abs[index]);
|
||||
make_instruction(force_bit, &result, accu_abs[index]);
|
||||
break;
|
||||
case X_INDEXED_ADDRESSING: // $ff,x, $ffff,x, $ffffff,x
|
||||
make_command(force_bit, &result, accu_xabs[index]);
|
||||
make_instruction(force_bit, &result, accu_xabs[index]);
|
||||
break;
|
||||
case Y_INDEXED_ADDRESSING: // $ffff,y (in theory, "$ff,y" as well)
|
||||
make_command(force_bit, &result, accu_yabs[index]);
|
||||
make_instruction(force_bit, &result, accu_yabs[index]);
|
||||
break;
|
||||
case STACK_INDEXED_ADDRESSING: // $ff,s
|
||||
make_command(force_bit, &result, accu_sabs8[index]);
|
||||
make_instruction(force_bit, &result, accu_sabs8[index]);
|
||||
break;
|
||||
case X_INDEXED_INDIRECT_ADDRESSING: // ($ff,x)
|
||||
make_command(force_bit, &result, accu_xind8[index]);
|
||||
make_instruction(force_bit, &result, accu_xind8[index]);
|
||||
break;
|
||||
case INDIRECT_ADDRESSING: // ($ff)
|
||||
make_command(force_bit, &result, accu_ind8[index]);
|
||||
make_instruction(force_bit, &result, accu_ind8[index]);
|
||||
check_zp_wraparound(&result);
|
||||
break;
|
||||
case INDIRECT_Y_INDEXED_ADDRESSING: // ($ff),y
|
||||
make_command(force_bit, &result, accu_indy8[index]);
|
||||
make_instruction(force_bit, &result, accu_indy8[index]);
|
||||
check_zp_wraparound(&result);
|
||||
break;
|
||||
case INDIRECT_Z_INDEXED_ADDRESSING: // ($ff),z only for 65ce02/4502/m65
|
||||
make_command(force_bit, &result, accu_indz8[index]);
|
||||
make_instruction(force_bit, &result, accu_indz8[index]);
|
||||
check_zp_wraparound(&result);
|
||||
break;
|
||||
case LONG_INDIRECT_ADDRESSING: // [$ff] for 65816 and m65
|
||||
// if in quad mode, m65 encodes this as NOP + ($ff),z
|
||||
if (flags & LI_PREFIX_NOP)
|
||||
Output_byte(234);
|
||||
make_command(force_bit, &result, accu_lind8[index]);
|
||||
Output_byte(0xea);
|
||||
make_instruction(force_bit, &result, accu_lind8[index]);
|
||||
break;
|
||||
case LONG_INDIRECT_Y_INDEXED_ADDRESSING: // [$ff],y only for 65816
|
||||
make_command(force_bit, &result, accu_lindy8[index]);
|
||||
make_instruction(force_bit, &result, accu_lindy8[index]);
|
||||
break;
|
||||
case STACK_INDEXED_INDIRECT_Y_INDEXED_ADDRESSING: // ($ff,s),y only for 65816 and 65ce02/4502/m65
|
||||
make_command(force_bit, &result, accu_sindy8[index]);
|
||||
make_instruction(force_bit, &result, accu_sindy8[index]);
|
||||
break;
|
||||
case LONG_INDIRECT_Z_INDEXED_ADDRESSING: // [$ff],z only for m65
|
||||
// if not in quad mode, m65 encodes this as NOP + ($ff),z
|
||||
if (flags & LI_PREFIX_NOP)
|
||||
Output_byte(234);
|
||||
make_command(force_bit, &result, accu_lindz8[index]);
|
||||
Output_byte(0xea);
|
||||
make_instruction(force_bit, &result, accu_lindz8[index]);
|
||||
break;
|
||||
default: // other combinations are illegal
|
||||
Throw_error(exception_illegal_combination);
|
||||
|
@ -992,7 +1000,7 @@ static void group_misc(int index, bits immediate_mode)
|
|||
immediate_opcodes = imm_ops(&force_bit, misc_imm[index], immediate_mode);
|
||||
// CAUTION - do not incorporate the line above into the line
|
||||
// below - "force_bit" might be undefined (depends on compiler).
|
||||
make_command(force_bit, &result, immediate_opcodes);
|
||||
make_instruction(force_bit, &result, immediate_opcodes);
|
||||
// warn about unstable ANE/LXA (undocumented opcode of NMOS 6502)?
|
||||
if ((CPU_state.type->flags & CPUFLAG_8B_AND_AB_NEED_0_ARG)
|
||||
&& (result.ntype == NUMTYPE_INT)
|
||||
|
@ -1004,13 +1012,13 @@ static void group_misc(int index, bits immediate_mode)
|
|||
}
|
||||
break;
|
||||
case ABSOLUTE_ADDRESSING: // $ff or $ffff
|
||||
make_command(force_bit, &result, misc_abs[index]);
|
||||
make_instruction(force_bit, &result, misc_abs[index]);
|
||||
break;
|
||||
case X_INDEXED_ADDRESSING: // $ff,x or $ffff,x
|
||||
make_command(force_bit, &result, misc_xabs[index]);
|
||||
make_instruction(force_bit, &result, misc_xabs[index]);
|
||||
break;
|
||||
case Y_INDEXED_ADDRESSING: // $ff,y or $ffff,y
|
||||
make_command(force_bit, &result, misc_yabs[index]);
|
||||
make_instruction(force_bit, &result, misc_yabs[index]);
|
||||
break;
|
||||
default: // other combinations are illegal
|
||||
Throw_error(exception_illegal_combination);
|
||||
|
@ -1020,6 +1028,7 @@ static void group_misc(int index, bits immediate_mode)
|
|||
// mnemonics using only 8bit relative addressing (short branch instructions).
|
||||
static void group_std_branches(int opcode)
|
||||
{
|
||||
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
|
||||
Output_byte(opcode);
|
||||
near_branch(2);
|
||||
}
|
||||
|
@ -1028,6 +1037,7 @@ static void group_std_branches(int opcode)
|
|||
static void group_bbr_bbs(int opcode)
|
||||
{
|
||||
struct number zpmem;
|
||||
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
|
||||
|
||||
get_int_arg(&zpmem, TRUE);
|
||||
typesystem_want_addr(&zpmem);
|
||||
|
@ -1043,6 +1053,7 @@ static void group_bbr_bbs(int opcode)
|
|||
// mnemonics using only 16bit relative addressing (BRL and PER of 65816, and the long branches of 65ce02)
|
||||
static void group_relative16(int opcode, int preoffset)
|
||||
{
|
||||
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
|
||||
Output_byte(opcode);
|
||||
far_branch(preoffset);
|
||||
}
|
||||
|
@ -1054,6 +1065,7 @@ static void group_mvn_mvp(int opcode)
|
|||
boolean unmatched_hash = FALSE;
|
||||
struct number source,
|
||||
target;
|
||||
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
|
||||
|
||||
// assembler syntax: "mnemonic source, target" or "mnemonic #source, #target"
|
||||
// machine language order: "opcode target source"
|
||||
|
@ -1090,6 +1102,7 @@ static void group_mvn_mvp(int opcode)
|
|||
// "rmb0..7" and "smb0..7"
|
||||
static void group_only_zp(int opcode)
|
||||
{
|
||||
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
|
||||
struct number target;
|
||||
|
||||
get_int_arg(&target, TRUE);
|
||||
|
@ -1102,9 +1115,10 @@ static void group_only_zp(int opcode)
|
|||
// NOP on m65 cpu (FIXME - "!align" outputs NOPs, what about that? what if user writes NEG:NEG?)
|
||||
static void group_prefix(int opcode)
|
||||
{
|
||||
//bits force_bit = Input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
|
||||
char buffer[100]; // 640K should be enough for anybody
|
||||
|
||||
sprintf(buffer, "The chosen CPU uses opcode 0x%02x as a prefix code, do not use this mnemonic!", opcode); // FIXME - add to docs!
|
||||
sprintf(buffer, "The chosen CPU uses opcode 0x%02x as a prefix code, do not use this mnemonic!", opcode);
|
||||
Throw_error(buffer);
|
||||
}
|
||||
|
||||
|
@ -1116,10 +1130,10 @@ static void group_jump(int index)
|
|||
|
||||
switch (get_addr_mode(&result)) {
|
||||
case ABSOLUTE_ADDRESSING: // absolute16 or absolute24
|
||||
make_command(force_bit, &result, jump_abs[index]);
|
||||
make_instruction(force_bit, &result, jump_abs[index]);
|
||||
break;
|
||||
case INDIRECT_ADDRESSING: // ($ffff)
|
||||
make_command(force_bit, &result, jump_ind[index]);
|
||||
make_instruction(force_bit, &result, jump_ind[index]);
|
||||
// check whether to warn about 6502's JMP() bug
|
||||
if ((result.ntype == NUMTYPE_INT)
|
||||
&& ((result.val.intval & 0xff) == 0xff)
|
||||
|
@ -1127,10 +1141,10 @@ static void group_jump(int index)
|
|||
Throw_warning("Assembling buggy JMP($xxff) instruction");
|
||||
break;
|
||||
case X_INDEXED_INDIRECT_ADDRESSING: // ($ffff,x)
|
||||
make_command(force_bit, &result, jump_xind[index]);
|
||||
make_instruction(force_bit, &result, jump_xind[index]);
|
||||
break;
|
||||
case LONG_INDIRECT_ADDRESSING: // [$ffff]
|
||||
make_command(force_bit, &result, jump_lind[index]);
|
||||
make_instruction(force_bit, &result, jump_lind[index]);
|
||||
break;
|
||||
default: // other combinations are illegal
|
||||
Throw_error(exception_illegal_combination);
|
||||
|
@ -1182,7 +1196,7 @@ static boolean check_mnemo_tree(struct ronode *tree, struct dynabuf *dyna_buf)
|
|||
case GROUP_BOTHMOVES: // "mvp" and "mvn"
|
||||
group_mvn_mvp(code);
|
||||
break;
|
||||
case GROUP_ZPONLY: // "rmb0..7" and "smb0..7"
|
||||
case GROUP_ZPONLY: // "rmb0..7", "smb0..7", "inw", "dew"
|
||||
group_only_zp(code);
|
||||
break;
|
||||
case GROUP_PREFIX: // NOP for m65 cpu
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
#include "config.h"
|
||||
|
||||
|
||||
// create dynamic buffer, build keyword trees
|
||||
extern void Mnemo_init(void);
|
||||
// check whether mnemonic in GlobalDynaBuf is supported by standard 6502 cpu.
|
||||
extern boolean keyword_is_6502_mnemo(int length);
|
||||
// check whether mnemonic in GlobalDynaBuf is supported by NMOS 6502 cpu (includes undocumented opcodes).
|
||||
|
|
59
src/output.c
59
src/output.c
|
@ -24,7 +24,6 @@
|
|||
|
||||
|
||||
// constants
|
||||
#define OUTBUFFERSIZE 65536
|
||||
#define NO_SEGMENT_START (-1) // invalid value to signal "not in a segment"
|
||||
|
||||
|
||||
|
@ -39,6 +38,7 @@ struct segment {
|
|||
// structure for all output stuff:
|
||||
struct output {
|
||||
// output buffer stuff
|
||||
intval_t bufsize; // either 64 KiB or 16 MiB
|
||||
char *buffer; // holds assembled code
|
||||
intval_t write_idx; // index of next write
|
||||
intval_t lowest_written; // smallest address used
|
||||
|
@ -72,13 +72,14 @@ enum output_format {
|
|||
OUTPUT_FORMAT_PLAIN // code only
|
||||
};
|
||||
// predefined stuff
|
||||
static struct ronode *file_format_tree = NULL; // tree to hold output formats (FIXME - a tree for three items, really?)
|
||||
static struct ronode file_format_list[] = {
|
||||
// tree to hold output formats (FIXME - a tree for three items, really?)
|
||||
static struct ronode file_format_tree[] = {
|
||||
PREDEF_START,
|
||||
#define KNOWN_FORMATS "'plain', 'cbm', 'apple'" // shown in CLI error message for unknown formats
|
||||
PREDEFNODE("apple", OUTPUT_FORMAT_APPLE),
|
||||
PREDEFNODE("cbm", OUTPUT_FORMAT_CBM),
|
||||
// PREDEFNODE("o65", OUTPUT_FORMAT_O65),
|
||||
PREDEFLAST("plain", OUTPUT_FORMAT_PLAIN),
|
||||
PREDEF_END("plain", OUTPUT_FORMAT_PLAIN),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
// chosen file format
|
||||
|
@ -110,7 +111,7 @@ static void find_segment_max(intval_t new_pc)
|
|||
while (test_segment->start <= new_pc)
|
||||
test_segment = test_segment->next;
|
||||
if (test_segment == &out->segment.list_head)
|
||||
out->segment.max = OUTBUFFERSIZE - 1;
|
||||
out->segment.max = out->bufsize - 1;
|
||||
else
|
||||
out->segment.max = test_segment->start - 1; // last free address available
|
||||
}
|
||||
|
@ -119,8 +120,9 @@ static void find_segment_max(intval_t new_pc)
|
|||
//
|
||||
static void border_crossed(int current_offset)
|
||||
{
|
||||
if (current_offset >= OUTBUFFERSIZE)
|
||||
if (current_offset >= out->bufsize)
|
||||
Throw_serious_error("Produced too much code.");
|
||||
// TODO - get rid of FIRST_PASS condition, because user can suppress these warnings if they want
|
||||
if (FIRST_PASS) {
|
||||
// TODO: make warn/err an arg for a general "Throw" function
|
||||
if (config.segment_warning_is_error)
|
||||
|
@ -139,7 +141,9 @@ void (*Output_byte)(intval_t byte);
|
|||
// send low byte to output buffer, automatically increasing program counter
|
||||
static void real_output(intval_t byte)
|
||||
{
|
||||
// did we reach segment limit?
|
||||
// CAUTION - there are two copies of these checks!
|
||||
// TODO - add additional check for current segment's "limit" value
|
||||
// did we reach next segment?
|
||||
if (out->write_idx > out->segment.max)
|
||||
border_crossed(out->write_idx);
|
||||
// new minimum address?
|
||||
|
@ -182,7 +186,9 @@ void output_skip(int size)
|
|||
Output_byte(0); // trigger error with a dummy byte
|
||||
--size; // fix amount to cater for dummy byte
|
||||
}
|
||||
// did we reach segment limit?
|
||||
// CAUTION - there are two copies of these checks!
|
||||
// TODO - add additional check for current segment's "limit" value
|
||||
// did we reach next segment?
|
||||
if (out->write_idx + size - 1 > out->segment.max)
|
||||
border_crossed(out->write_idx + size - 1);
|
||||
// new minimum address?
|
||||
|
@ -200,7 +206,7 @@ void output_skip(int size)
|
|||
// fill output buffer with given byte value
|
||||
static void fill_completely(char value)
|
||||
{
|
||||
memset(out->buffer, value, OUTBUFFERSIZE);
|
||||
memset(out->buffer, value, out->bufsize);
|
||||
}
|
||||
|
||||
|
||||
|
@ -234,9 +240,6 @@ int outputfile_set_format(void)
|
|||
{
|
||||
void *node_body;
|
||||
|
||||
// make sure tree is initialised
|
||||
if (file_format_tree == NULL)
|
||||
Tree_add_table(&file_format_tree, file_format_list);
|
||||
// perform lookup
|
||||
if (!Tree_easy_scan(file_format_tree, &node_body, GlobalDynaBuf))
|
||||
return 1;
|
||||
|
@ -251,6 +254,7 @@ int outputfile_prefer_cbm_format(void)
|
|||
{
|
||||
if (output_format != OUTPUT_FORMAT_UNSPECIFIED)
|
||||
return 0;
|
||||
|
||||
output_format = OUTPUT_FORMAT_CBM;
|
||||
return 1;
|
||||
}
|
||||
|
@ -272,9 +276,10 @@ int outputfile_set_filename(void)
|
|||
|
||||
|
||||
// init output struct (done later)
|
||||
void Output_init(signed long fill_value)
|
||||
void Output_init(signed long fill_value, boolean use_large_buf)
|
||||
{
|
||||
out->buffer = safe_malloc(OUTBUFFERSIZE);
|
||||
out->bufsize = use_large_buf ? 0x1000000 : 0x10000;
|
||||
out->buffer = safe_malloc(out->bufsize);
|
||||
if (fill_value == MEMINIT_USE_DEFAULT) {
|
||||
fill_value = FILLVALUE_INITIAL;
|
||||
out->initvalue_set = FALSE;
|
||||
|
@ -358,7 +363,7 @@ static void link_segment(intval_t start, intval_t length)
|
|||
|
||||
|
||||
// check whether given PC is inside segment.
|
||||
// only call in first pass, otherwise too many warnings might be thrown
|
||||
// only call in first pass, otherwise too many warnings might be thrown (TODO - still?)
|
||||
static void check_segment(intval_t new_pc)
|
||||
{
|
||||
struct segment *test_segment = out->segment.list_head.next;
|
||||
|
@ -389,7 +394,7 @@ void Output_passinit(void)
|
|||
|
||||
//FIXME - why clear ring list in every pass?
|
||||
// Because later pass shouldn't complain about overwriting the same segment from earlier pass!
|
||||
// Currently this does not happen because segment checks are only done in first pass. FIXME!
|
||||
// Currently this does not happen because segment warnings are only generated in first pass. FIXME!
|
||||
// delete segment list (and free blocks)
|
||||
// while ((temp = segment_list)) {
|
||||
// segment_list = segment_list->next;
|
||||
|
@ -397,13 +402,13 @@ void Output_passinit(void)
|
|||
// }
|
||||
|
||||
// invalidate start and end (first byte actually written will fix them)
|
||||
out->lowest_written = OUTBUFFERSIZE - 1;
|
||||
out->lowest_written = out->bufsize - 1;
|
||||
out->highest_written = 0;
|
||||
// deactivate output - any byte written will trigger error:
|
||||
Output_byte = no_output;
|
||||
out->write_idx = 0; // same as pc on pass init!
|
||||
out->segment.start = NO_SEGMENT_START; // TODO - "no active segment" could be made a segment flag!
|
||||
out->segment.max = OUTBUFFERSIZE - 1;
|
||||
out->segment.max = out->bufsize - 1; // TODO - use end of bank?
|
||||
out->segment.flags = 0;
|
||||
out->xor = 0;
|
||||
|
||||
|
@ -455,18 +460,20 @@ void Output_end_segment(void)
|
|||
|
||||
|
||||
// change output pointer and enable output
|
||||
// TODO - this only gets called from vcpu_set_pc so could be made static!
|
||||
void Output_start_segment(intval_t address_change, bits segment_flags)
|
||||
{
|
||||
// properly finalize previous segment (link to list, announce)
|
||||
Output_end_segment();
|
||||
|
||||
// calculate start of new segment
|
||||
out->write_idx = (out->write_idx + address_change) & 0xffff;
|
||||
out->write_idx = (out->write_idx + address_change) & (out->bufsize - 1);
|
||||
out->segment.start = out->write_idx;
|
||||
out->segment.flags = segment_flags;
|
||||
// allow writing to output buffer
|
||||
Output_byte = real_output;
|
||||
// in first pass, check for other segments and maybe issue warning
|
||||
// TODO - remove FIRST_PASS condition
|
||||
if (FIRST_PASS) {
|
||||
if (!(segment_flags & SEGMENT_FLAG_OVERLAY))
|
||||
check_segment(out->segment.start);
|
||||
|
@ -490,7 +497,7 @@ void output_set_xor(char xor)
|
|||
// in addition to that, it will be called on each "*= VALUE".
|
||||
void vcpu_set_pc(intval_t new_pc, bits segment_flags)
|
||||
{
|
||||
intval_t new_offset;
|
||||
intval_t pc_change;
|
||||
|
||||
// support stupidly bad, old, ancient, deprecated, obsolete behaviour:
|
||||
if (pseudopc_current_context != NULL) {
|
||||
|
@ -506,12 +513,12 @@ void vcpu_set_pc(intval_t new_pc, bits segment_flags)
|
|||
// stuff happens! i see no reason to try to mimic that.
|
||||
}
|
||||
}
|
||||
new_offset = (new_pc - CPU_state.pc.val.intval) & 0xffff;
|
||||
CPU_state.pc.val.intval = new_pc;
|
||||
pc_change = new_pc - CPU_state.pc.val.intval;
|
||||
CPU_state.pc.val.intval = new_pc; // FIXME - oversized values are accepted without error and will be wrapped at end of statement!
|
||||
CPU_state.pc.ntype = NUMTYPE_INT; // FIXME - remove when allowing undefined!
|
||||
CPU_state.pc.addr_refs = 1; // yes, PC counts as address
|
||||
// now tell output buffer to start a new segment
|
||||
Output_start_segment(new_offset, segment_flags);
|
||||
Output_start_segment(pc_change, segment_flags);
|
||||
}
|
||||
/*
|
||||
TODO - overhaul program counter and memory pointer stuff:
|
||||
|
@ -560,7 +567,7 @@ int vcpu_get_statement_size(void)
|
|||
// adjust program counter (called at end of each statement)
|
||||
void vcpu_end_statement(void)
|
||||
{
|
||||
CPU_state.pc.val.intval = (CPU_state.pc.val.intval + CPU_state.add_to_pc) & 0xffff;
|
||||
CPU_state.pc.val.intval = (CPU_state.pc.val.intval + CPU_state.add_to_pc) & (out->bufsize - 1);
|
||||
CPU_state.add_to_pc = 0;
|
||||
}
|
||||
|
||||
|
@ -599,7 +606,7 @@ void pseudopc_end(void)
|
|||
if (config.wanted_version >= VER_DISABLED_OBSOLETE_STUFF)
|
||||
Bug_found("ClosingUnopenedPseudopcBlock", 0);
|
||||
} else {
|
||||
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - pseudopc_current_context->offset) & 0xffff; // pc might have wrapped around
|
||||
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - pseudopc_current_context->offset) & (out->bufsize - 1); // pc might have wrapped around
|
||||
CPU_state.pc.ntype = pseudopc_current_context->ntype;
|
||||
pseudopc_current_context = pseudopc_current_context->outer; // go back to outer block
|
||||
}
|
||||
|
@ -623,7 +630,7 @@ int pseudopc_unpseudo(struct number *target, struct pseudopc *context, unsigned
|
|||
return 1; // error
|
||||
}
|
||||
// FIXME - in future, check both target and context for NUMTYPE_UNDEFINED!
|
||||
target->val.intval = (target->val.intval - context->offset) & 0xffff; // FIXME - is masking really needed?
|
||||
target->val.intval = (target->val.intval - context->offset) & (out->bufsize - 1); // FIXME - is masking really needed? TODO
|
||||
context = context->outer;
|
||||
}
|
||||
return 0; // ok
|
||||
|
|
|
@ -42,7 +42,7 @@ extern void Output_passinit(void);
|
|||
// outbuf stuff:
|
||||
|
||||
// alloc and init mem buffer (done later)
|
||||
extern void Output_init(signed long fill_value);
|
||||
extern void Output_init(signed long fill_value, boolean use_large_buf);
|
||||
// skip over some bytes in output buffer without starting a new segment
|
||||
// (used by "!skip", and also called by "!binary" if really calling
|
||||
// Output_byte would be a waste of time)
|
||||
|
|
|
@ -32,17 +32,9 @@ enum eos {
|
|||
};
|
||||
|
||||
// constants
|
||||
static const char s_08[] = "08";
|
||||
#define s_8 (s_08 + 1) // Yes, I know I'm sick
|
||||
#define s_sl (s_asl + 1) // Yes, I know I'm sick
|
||||
#define s_rl (s_brl + 1) // Yes, I know I'm sick
|
||||
static const char exception_unknown_pseudo_opcode[] = "Unknown pseudo opcode.";
|
||||
|
||||
|
||||
// variables
|
||||
static struct ronode *pseudo_opcode_tree = NULL; // tree to hold pseudo opcodes
|
||||
|
||||
|
||||
// this is not really a pseudo opcode, but similar enough to be put here:
|
||||
// called when "*= EXPRESSION" is parsed, to set the program counter
|
||||
void notreallypo_setpc(void) // GotByte is '*'
|
||||
|
@ -105,8 +97,8 @@ static enum eos po_initmem(void)
|
|||
|
||||
// get value
|
||||
ALU_defined_int(&intresult);
|
||||
if ((intresult.val.intval > 0xff) || (intresult.val.intval < -0x80))
|
||||
Throw_error(exception_number_out_of_range);
|
||||
if ((intresult.val.intval > 255) || (intresult.val.intval < -128))
|
||||
Throw_error(exception_number_out_of_8b_range);
|
||||
if (output_initmem(intresult.val.intval & 0xff))
|
||||
return SKIP_REMAINDER;
|
||||
return ENSURE_EOS;
|
||||
|
@ -121,8 +113,8 @@ static enum eos po_xor(void)
|
|||
|
||||
old_value = output_get_xor();
|
||||
ALU_any_int(&change);
|
||||
if ((change > 0xff) || (change < -0x80)) {
|
||||
Throw_error(exception_number_out_of_range);
|
||||
if ((change > 255) || (change < -128)) {
|
||||
Throw_error(exception_number_out_of_8b_range);
|
||||
change = 0;
|
||||
}
|
||||
output_set_xor(old_value ^ change);
|
||||
|
@ -195,7 +187,7 @@ static enum eos iterate(void (*fn)(intval_t))
|
|||
}
|
||||
|
||||
|
||||
// Insert 8-bit values ("!08" / "!8" / "!by" / "!byte" pseudo opcode)
|
||||
// insert 8-bit values ("!8" / "!08" / "!by" / "!byte" pseudo opcode)
|
||||
static enum eos po_byte(void)
|
||||
{
|
||||
return iterate(output_8);
|
||||
|
@ -329,7 +321,7 @@ static enum eos user_defined_encoding(FILE *stream)
|
|||
}
|
||||
encoder_current = &encoder_file; // activate new encoding
|
||||
encoding_loaded_table = local_table; // activate local table
|
||||
// If there's a block, parse that and then restore old values
|
||||
// if there's a block, parse that and then restore old values
|
||||
if (Parse_optional_block()) {
|
||||
encoder_current = buffered_encoder;
|
||||
} else {
|
||||
|
@ -457,7 +449,7 @@ static enum eos po_scrxor(void)
|
|||
return encode_string(&encoder_scr, xor);
|
||||
}
|
||||
|
||||
// Include binary file ("!binary" pseudo opcode)
|
||||
// include binary file ("!binary" pseudo opcode)
|
||||
// FIXME - split this into "parser" and "worker" fn and move worker fn somewhere else.
|
||||
static enum eos po_binary(void)
|
||||
{
|
||||
|
@ -760,13 +752,12 @@ static enum eos po_set(void) // now GotByte = illegal char
|
|||
return SKIP_REMAINDER;
|
||||
}
|
||||
|
||||
// TODO: in versions before 0.97, force bit handling was broken
|
||||
// in both "!set" and "!for":
|
||||
// trying to change a force bit correctly raised an error, but
|
||||
// in any case, ALL FORCE BITS WERE CLEARED in symbol. only
|
||||
// cases like !set N=N+1 worked, because the force bit was
|
||||
// taken from result.
|
||||
// maybe support this behaviour via --dialect?
|
||||
// TODO: in versions before 0.97, force bit handling was broken in both
|
||||
// "!set" and "!for":
|
||||
// trying to change a force bit raised an error (which is correct), but
|
||||
// in any case, ALL FORCE BITS WERE CLEARED in symbol. only cases like
|
||||
// !set N=N+1 worked, because the force bit was taken from result.
|
||||
// maybe support this behaviour via --dialect? I'd rather not...
|
||||
parse_assignment(scope, force_bit, POWER_CHANGE_VALUE | POWER_CHANGE_OBJTYPE);
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
@ -814,10 +805,10 @@ static enum eos po_zone(void)
|
|||
// set default values in case there is no valid title
|
||||
new_title = s_untitled;
|
||||
allocated = FALSE;
|
||||
// Check whether a zone title is given. If yes and it can be read,
|
||||
// check whether a zone title is given. if yes and it can be read,
|
||||
// get copy, remember pointer and remember to free it later on.
|
||||
if (BYTE_CONTINUES_KEYWORD(GotByte)) {
|
||||
// Because we know of one character for sure,
|
||||
// because we know of one character for sure,
|
||||
// there's no need to check the return value.
|
||||
Input_read_keyword();
|
||||
new_title = DynaBuf_get_copy(GlobalDynaBuf);
|
||||
|
@ -827,7 +818,7 @@ static enum eos po_zone(void)
|
|||
// section type is "subzone", just in case a block follows
|
||||
section_new(section_now, "Subzone", new_title, allocated);
|
||||
if (Parse_optional_block()) {
|
||||
// Block has been parsed, so it was a SUBzone.
|
||||
// block has been parsed, so it was a SUBzone.
|
||||
section_finalize(section_now); // end inner zone
|
||||
*section_now = entry_values; // restore entry values
|
||||
} else {
|
||||
|
@ -1157,13 +1148,67 @@ static enum eos po_macro(void) // now GotByte = illegal char
|
|||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
/*
|
||||
// trace/watch
|
||||
#define TRACEWATCH_LOAD (1u << 0)
|
||||
#define TRACEWATCH_STORE (1u << 1)
|
||||
#define TRACEWATCH_EXEC (1u << 2)
|
||||
#define TRACEWATCH_DEFAULT (TRACEWATCH_LOAD | TRACEWATCH_STORE | TRACEWATCH_EXEC)
|
||||
#define TRACEWATCH_BREAK (1u << 3)
|
||||
static enum eos tracewatch(boolean enter_monitor)
|
||||
{
|
||||
struct number pc;
|
||||
bits flags = 0;
|
||||
|
||||
vcpu_read_pc(&pc);
|
||||
SKIPSPACE();
|
||||
// check for flags
|
||||
if (GotByte != CHAR_EOS) {
|
||||
do {
|
||||
// parse flag. if no keyword given, give up
|
||||
if (Input_read_and_lower_keyword() == 0)
|
||||
return SKIP_REMAINDER; // fail (error has been reported)
|
||||
|
||||
if (strcmp(GlobalDynaBuf->buffer, "load") == 0) {
|
||||
flags |= TRACEWATCH_LOAD;
|
||||
} else if (strcmp(GlobalDynaBuf->buffer, "store") == 0) {
|
||||
flags |= TRACEWATCH_STORE;
|
||||
} else if (strcmp(GlobalDynaBuf->buffer, "exec") == 0) {
|
||||
flags |= TRACEWATCH_EXEC;
|
||||
} else {
|
||||
Throw_error("Unknown flag (known are: load, store, exec)."); // FIXME - add to docs!
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
} while (Input_accept_comma());
|
||||
}
|
||||
// shortcut: no flags at all -> set all flags!
|
||||
if (!flags)
|
||||
flags = TRACEWATCH_DEFAULT;
|
||||
if (enter_monitor)
|
||||
flags |= TRACEWATCH_BREAK;
|
||||
if (pc.ntype != NUMTYPE_UNDEFINED) {
|
||||
//FIXME - store pc and flags!
|
||||
}
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
// make next byte a trace point (for VICE debugging)
|
||||
static enum eos po_trace(void)
|
||||
{
|
||||
return tracewatch(FALSE); // do not enter monitor, just output
|
||||
}
|
||||
// make next byte a watch point (for VICE debugging)
|
||||
static enum eos po_watch(void)
|
||||
{
|
||||
return tracewatch(TRUE); // break into monitor
|
||||
}
|
||||
*/
|
||||
|
||||
// constants
|
||||
#define USERMSG_DYNABUF_INITIALSIZE 80
|
||||
#define USERMSG_INITIALSIZE 80
|
||||
|
||||
|
||||
// variables
|
||||
static struct dynabuf *user_message; // dynamic buffer (!warn/error/serious)
|
||||
static STRUCT_DYNABUF_REF(user_message, USERMSG_INITIALSIZE); // for !warn/error/serious
|
||||
|
||||
|
||||
// helper function to show user-defined messages
|
||||
|
@ -1246,14 +1291,15 @@ static enum eos po_endoffile(void)
|
|||
}
|
||||
|
||||
// pseudo opcode table
|
||||
static struct ronode pseudo_opcode_list[] = {
|
||||
static struct ronode pseudo_opcode_tree[] = {
|
||||
PREDEF_START,
|
||||
PREDEFNODE("initmem", po_initmem),
|
||||
PREDEFNODE("xor", po_xor),
|
||||
PREDEFNODE("to", po_to),
|
||||
PREDEFNODE(s_8, po_byte),
|
||||
PREDEFNODE(s_08, po_byte),
|
||||
PREDEFNODE("by", po_byte),
|
||||
PREDEFNODE("byte", po_byte),
|
||||
PREDEFNODE("8", po_byte),
|
||||
PREDEFNODE("08", po_byte), // legacy alias, don't ask...
|
||||
PREDEFNODE("wo", po_16),
|
||||
PREDEFNODE("word", po_16),
|
||||
PREDEFNODE("16", po_16),
|
||||
|
@ -1272,10 +1318,10 @@ static struct ronode pseudo_opcode_list[] = {
|
|||
PREDEFNODE("convtab", po_convtab),
|
||||
PREDEFNODE("tx", po_text),
|
||||
PREDEFNODE("text", po_text),
|
||||
PREDEFNODE(s_raw, po_raw),
|
||||
PREDEFNODE(s_pet, po_pet),
|
||||
PREDEFNODE(s_scr, po_scr),
|
||||
PREDEFNODE(s_scrxor, po_scrxor),
|
||||
PREDEFNODE("raw", po_raw),
|
||||
PREDEFNODE("pet", po_pet),
|
||||
PREDEFNODE("scr", po_scr),
|
||||
PREDEFNODE("scrxor", po_scrxor),
|
||||
PREDEFNODE("bin", po_binary),
|
||||
PREDEFNODE("binary", po_binary),
|
||||
PREDEFNODE("fi", po_fill),
|
||||
|
@ -1287,13 +1333,13 @@ static struct ronode pseudo_opcode_list[] = {
|
|||
PREDEFNODE("cpu", po_cpu),
|
||||
PREDEFNODE("al", po_al),
|
||||
PREDEFNODE("as", po_as),
|
||||
PREDEFNODE(s_rl, po_rl),
|
||||
PREDEFNODE("rl", po_rl),
|
||||
PREDEFNODE("rs", po_rs),
|
||||
PREDEFNODE("addr", po_address),
|
||||
PREDEFNODE("address", po_address),
|
||||
// PREDEFNODE("enum", po_enum),
|
||||
PREDEFNODE("set", po_set),
|
||||
PREDEFNODE(s_sl, po_symbollist),
|
||||
PREDEFNODE("sl", po_symbollist),
|
||||
PREDEFNODE("symbollist", po_symbollist),
|
||||
PREDEFNODE("zn", po_zone),
|
||||
PREDEFNODE("zone", po_zone),
|
||||
|
@ -1308,25 +1354,19 @@ static struct ronode pseudo_opcode_list[] = {
|
|||
PREDEFNODE("do", po_do),
|
||||
PREDEFNODE("while", po_while),
|
||||
PREDEFNODE("macro", po_macro),
|
||||
/* PREDEFNODE("trace", po_trace),
|
||||
PREDEFNODE("watch", po_watch), */
|
||||
// PREDEFNODE("debug", po_debug),
|
||||
// PREDEFNODE("info", po_info),
|
||||
PREDEFNODE("warn", po_warn),
|
||||
PREDEFNODE(s_error, po_error),
|
||||
PREDEFNODE("error", po_error),
|
||||
PREDEFNODE("serious", po_serious),
|
||||
PREDEFNODE("eof", po_endoffile),
|
||||
PREDEFLAST("endoffile", po_endoffile),
|
||||
PREDEF_END("endoffile", po_endoffile),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
|
||||
// register pseudo opcodes and create dynamic buffer
|
||||
void pseudoopcodes_init(void)
|
||||
{
|
||||
user_message = DynaBuf_create(USERMSG_DYNABUF_INITIALSIZE);
|
||||
Tree_add_table(&pseudo_opcode_tree, pseudo_opcode_list);
|
||||
}
|
||||
|
||||
|
||||
// parse a pseudo opcode. has to be re-entrant.
|
||||
void pseudoopcode_parse(void) // now GotByte = "!"
|
||||
{
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
// call when "*= EXPRESSION" is parsed
|
||||
extern void notreallypo_setpc(void);
|
||||
// register pseudo opcodes
|
||||
extern void pseudoopcodes_init(void);
|
||||
// parse pseudo opcode. has to be re-entrant.
|
||||
extern void pseudoopcode_parse(void);
|
||||
|
||||
|
|
|
@ -232,6 +232,7 @@ void symbols_vicelabels(FILE *fd)
|
|||
fputc('\n', fd);
|
||||
// dump address symbols
|
||||
Tree_dump_forest(symbols_forest, SCOPE_GLOBAL, dump_vice_address, fd);
|
||||
// TODO - add trace points and watch points with load/store/exec args!
|
||||
}
|
||||
|
||||
|
||||
|
|
21
src/tree.c
21
src/tree.c
|
@ -28,14 +28,15 @@ hash_t make_hash(struct ronode *node) {
|
|||
}
|
||||
|
||||
// Link a predefined data set to a tree
|
||||
void add_node_to_tree(struct ronode **tree, struct ronode *node_to_add)
|
||||
static void add_node_to_tree(struct ronode **tree, struct ronode *node_to_add)
|
||||
{
|
||||
hash_t hash;
|
||||
|
||||
// compute hash value
|
||||
hash = make_hash(node_to_add);
|
||||
// search for NULL pointer to replace
|
||||
while (*tree) {
|
||||
// compare HashValue
|
||||
// decide which way to go
|
||||
if (hash > (*tree)->hash_value)
|
||||
tree = &((*tree)->greater_than);
|
||||
else
|
||||
|
@ -48,10 +49,11 @@ void add_node_to_tree(struct ronode **tree, struct ronode *node_to_add)
|
|||
// fields.
|
||||
}
|
||||
|
||||
// Add predefined tree items to given tree. The PREDEF* macros set HashValue
|
||||
// to 1 in all entries but the last. The last entry contains 0.
|
||||
void Tree_add_table(struct ronode **tree, struct ronode *table_to_add)
|
||||
// Add predefined tree items to given tree. The PREDEF* macros set the hash
|
||||
// to 1 in all entries but the last, and to 0 in the last entry.
|
||||
static void tree_from_list(struct ronode **tree, struct ronode *table_to_add)
|
||||
{
|
||||
//printf("Building tree from list.\n");
|
||||
// Caution when trying to optimise this. :)
|
||||
while (table_to_add->hash_value)
|
||||
add_node_to_tree(tree, table_to_add++);
|
||||
|
@ -72,6 +74,15 @@ int Tree_easy_scan(struct ronode *tree, void **node_body, struct dynabuf *dyna_b
|
|||
b2;
|
||||
hash_t hash;
|
||||
|
||||
// check if tree is actually ready to use. if not, build it from list.
|
||||
// (list's first item does not contain real data, so "greater_than" is
|
||||
// used to hold pointer to tree root)
|
||||
if (tree->greater_than == NULL)
|
||||
tree_from_list(&tree->greater_than, tree + 1); // real data starts at next list item
|
||||
tree = tree->greater_than; // go from list head to tree root
|
||||
// ok, we're done with this setup stuff.
|
||||
// from now on, "greater_than" really means "greater_than"!
|
||||
|
||||
wanted.id_string = dyna_buf->buffer;
|
||||
hash = make_hash(&wanted);
|
||||
while (tree) {
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
|
||||
|
||||
// macros for pre-defining tree node tables
|
||||
#define PREDEF_START {NULL, NULL, 0, NULL, NULL} // this is used to determine if list has been made into tree yet
|
||||
#define PREDEFNODE(s, v) {NULL, NULL, 1, s, (void *) (v)}
|
||||
#define PREDEFLAST(s, v) {NULL, NULL, 0, s, (void *) (v)}
|
||||
|
||||
#define PREDEF_END(s, v) {NULL, NULL, 0, s, (void *) (v)}
|
||||
|
||||
// type definitions
|
||||
|
||||
|
@ -42,8 +42,6 @@ struct rwnode {
|
|||
|
||||
// prototypes
|
||||
|
||||
// Add predefined tree items to given tree.
|
||||
extern void Tree_add_table(struct ronode **tree, struct ronode *table_to_add);
|
||||
// Search for a given ID string in a given tree. Store "body" component in
|
||||
// node_body and return TRUE. Return FALSE if no matching item found.
|
||||
struct dynabuf;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#define RELEASE "0.97" // update before release FIXME
|
||||
#define CODENAME "Zem" // update before release
|
||||
#define CHANGE_DATE "28 June" // update before release FIXME
|
||||
#define CHANGE_DATE "24 Aug" // update before release FIXME
|
||||
#define CHANGE_YEAR "2020" // update before release
|
||||
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
|
||||
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
||||
|
|
8
testing/cpus/check-all-cpus.sh
Executable file
8
testing/cpus/check-all-cpus.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
for CPU in 6502 65c02 r65c02 w65c02 nmos6502 c64dtv2 65ce02 4502 m65 65816 ; do
|
||||
acme -v0 test-"$CPU".a || exit
|
||||
cmp out-"$CPU".o expected-"$CPU".o || exit
|
||||
done
|
||||
echo
|
||||
echo "All CPU tests passed successfully."
|
||||
echo
|
BIN
testing/cpus/expected-4502.o
Normal file
BIN
testing/cpus/expected-4502.o
Normal file
Binary file not shown.
BIN
testing/cpus/expected-6502.o
Normal file
BIN
testing/cpus/expected-6502.o
Normal file
Binary file not shown.
BIN
testing/cpus/expected-65816.o
Normal file
BIN
testing/cpus/expected-65816.o
Normal file
Binary file not shown.
BIN
testing/cpus/expected-65c02.o
Normal file
BIN
testing/cpus/expected-65c02.o
Normal file
Binary file not shown.
BIN
testing/cpus/expected-65ce02.o
Normal file
BIN
testing/cpus/expected-65ce02.o
Normal file
Binary file not shown.
BIN
testing/cpus/expected-c64dtv2.o
Normal file
BIN
testing/cpus/expected-c64dtv2.o
Normal file
Binary file not shown.
BIN
testing/cpus/expected-m65.o
Normal file
BIN
testing/cpus/expected-m65.o
Normal file
Binary file not shown.
BIN
testing/cpus/expected-nmos6502.o
Normal file
BIN
testing/cpus/expected-nmos6502.o
Normal file
Binary file not shown.
BIN
testing/cpus/expected-r65c02.o
Normal file
BIN
testing/cpus/expected-r65c02.o
Normal file
Binary file not shown.
BIN
testing/cpus/expected-w65c02.o
Normal file
BIN
testing/cpus/expected-w65c02.o
Normal file
Binary file not shown.
155
testing/cpus/include-6502.a
Normal file
155
testing/cpus/include-6502.a
Normal file
|
@ -0,0 +1,155 @@
|
|||
;ACME 0.97
|
||||
; all the standard 6502 instructions:
|
||||
brk ; 00
|
||||
ora ($01, x) ; 01
|
||||
ora $05 ; 05
|
||||
asl $05 ; 06
|
||||
php ; 08
|
||||
ora #$09 ; 09
|
||||
asl ; 0a
|
||||
ora $0d0e ; 0d
|
||||
asl $0d0e ; 0e
|
||||
bpl * + 2 ; 10
|
||||
ora ($11), y ; 11
|
||||
ora $15, x ; 15
|
||||
asl $15, x ; 16
|
||||
clc ; 18
|
||||
ora $1919, y ; 19
|
||||
ora $1d1e, x ; 1d
|
||||
asl $1d1e, x ; 1e
|
||||
jsr $0d0e ; 20
|
||||
and ($01, x) ; 21
|
||||
bit $05 ; 24
|
||||
and $05 ; 25
|
||||
rol $05 ; 26
|
||||
plp ; 28
|
||||
and #$09 ; 29
|
||||
rol ; 2a
|
||||
bit $0d0e ; 2c
|
||||
and $0d0e ; 2d
|
||||
rol $0d0e ; 2e
|
||||
bmi * + 2 ; 30
|
||||
and ($11), y ; 31
|
||||
and $15, x ; 35
|
||||
rol $15, x ; 36
|
||||
sec ; 38
|
||||
and $1919, y ; 39
|
||||
and $1d1e, x ; 3d
|
||||
rol $1d1e, x ; 3e
|
||||
rti ; 40
|
||||
eor ($01, x) ; 41
|
||||
eor $05 ; 45
|
||||
lsr $05 ; 46
|
||||
pha ; 48
|
||||
eor #$09 ; 49
|
||||
lsr ; 4a
|
||||
jmp $0d0e ; 4c
|
||||
eor $0d0e ; 4d
|
||||
lsr $0d0e ; 4e
|
||||
bvc * + 2 ; 50
|
||||
eor ($11), y ; 51
|
||||
eor $15, x ; 55
|
||||
lsr $15, x ; 56
|
||||
cli ; 58
|
||||
eor $1919, y ; 59
|
||||
eor $1d1e, x ; 5d
|
||||
lsr $1d1e, x ; 5e
|
||||
rts ; 60
|
||||
adc ($01, x) ; 61
|
||||
adc $05 ; 65
|
||||
ror $05 ; 66
|
||||
pla ; 68
|
||||
adc #$09 ; 69
|
||||
ror ; 6a
|
||||
jmp ($6c6c) ; 6c
|
||||
adc $0d0e ; 6d
|
||||
ror $0d0e ; 6e
|
||||
bvs * + 2 ; 70
|
||||
adc ($11), y ; 71
|
||||
adc $15, x ; 75
|
||||
ror $15, x ; 76
|
||||
sei ; 78
|
||||
adc $1919, y ; 79
|
||||
adc $1d1e, x ; 7d
|
||||
ror $1d1e, x ; 7e
|
||||
sta ($01, x) ; 81
|
||||
sty $05 ; 84
|
||||
sta $05 ; 85
|
||||
stx $05 ; 86
|
||||
dey ; 88
|
||||
txa ; 8a
|
||||
sty $0d0e ; 8c
|
||||
sta $0d0e ; 8d
|
||||
stx $0d0e ; 8e
|
||||
bcc * + 2 ; 90
|
||||
sta ($11), y ; 91
|
||||
sty $15, x ; 94
|
||||
sta $15, x ; 95
|
||||
stx $96, y ; 96
|
||||
tya ; 98
|
||||
sta $1919, y ; 99
|
||||
txs ; 9a
|
||||
sta $1d1e, x ; 9d
|
||||
ldy #$09 ; a0
|
||||
lda ($01, x) ; a1
|
||||
ldx #$09 ; a2
|
||||
ldy $05 ; a4
|
||||
lda $05 ; a5
|
||||
ldx $05 ; a6
|
||||
tay ; a8
|
||||
lda #$09 ; a9
|
||||
tax ; aa
|
||||
ldy $0d0e ; ac
|
||||
lda $0d0e ; ad
|
||||
ldx $0d0e ; ae
|
||||
bcs * + 2 ; b0
|
||||
lda ($11), y ; b1
|
||||
ldy $15, x ; b4
|
||||
lda $15, x ; b5
|
||||
ldx $96, y ; b6
|
||||
clv ; b8
|
||||
lda $1919, y ; b9
|
||||
tsx ; ba
|
||||
ldy $1d1e, x ; bc
|
||||
lda $1d1e, x ; bd
|
||||
ldx $1919, y ; be
|
||||
cpy #$09 ; c0
|
||||
cmp ($01, x) ; c1
|
||||
cpy $05 ; c4
|
||||
cmp $05 ; c5
|
||||
dec $05 ; c6
|
||||
iny ; c8
|
||||
cmp #$09 ; c9
|
||||
dex ; ca
|
||||
cpy $0d0e ; cc
|
||||
cmp $0d0e ; cd
|
||||
dec $0d0e ; ce
|
||||
bne * + 2 ; d0
|
||||
cmp ($11), y ; d1
|
||||
cmp $15, x ; d5
|
||||
dec $15, x ; d6
|
||||
cld ; d8
|
||||
cmp $1919, y ; d9
|
||||
cmp $1d1e, x ; dd
|
||||
dec $1d1e, x ; de
|
||||
cpx #$09 ; e0
|
||||
sbc ($01, x) ; e1
|
||||
cpx $05 ; e4
|
||||
sbc $05 ; e5
|
||||
inc $05 ; e6
|
||||
inx ; e8
|
||||
sbc #$09 ; e9
|
||||
!ifndef M65 {
|
||||
nop ; ea (m65 re-uses this opcode as a prefix)
|
||||
}
|
||||
cpx $0d0e ; ec
|
||||
sbc $0d0e ; ed
|
||||
inc $0d0e ; ee
|
||||
beq * + 2 ; f0
|
||||
sbc ($11), y ; f1
|
||||
sbc $15, x ; f5
|
||||
inc $15, x ; f6
|
||||
sed ; f8
|
||||
sbc $1919, y ; f9
|
||||
sbc $1d1e, x ; fd
|
||||
inc $1d1e, x ; fe
|
29
testing/cpus/include-65c02.a
Normal file
29
testing/cpus/include-65c02.a
Normal file
|
@ -0,0 +1,29 @@
|
|||
;ACME 0.97
|
||||
; extensions in CMOS re-design (65c02):
|
||||
tsb $04 ; 04
|
||||
tsb $0c0c ; 0c
|
||||
ora ($12) ; 12
|
||||
trb $04 ; 14
|
||||
inc ; 1a
|
||||
trb $0c0c ; 1c
|
||||
and ($12) ; 32
|
||||
bit $34, x ; 34
|
||||
dec ; 3a
|
||||
bit $3c3c, x ; 3c
|
||||
eor ($12) ; 52
|
||||
phy ; 5a
|
||||
stz $04 ; 64
|
||||
adc ($12) ; 72
|
||||
stz $34, x ; 74
|
||||
ply ; 7a
|
||||
jmp ($7c7c, x) ; 7c
|
||||
bra * + 2 ; 80
|
||||
bit #$89 ; 89
|
||||
sta ($12) ; 92
|
||||
stz $0c0c ; 9c
|
||||
stz $3c3c, x ; 9e
|
||||
lda ($12) ; b2
|
||||
cmp ($12) ; d2
|
||||
phx ; da
|
||||
sbc ($12) ; f2
|
||||
plx ; fa
|
76
testing/cpus/include-65ce02.a
Normal file
76
testing/cpus/include-65ce02.a
Normal file
|
@ -0,0 +1,76 @@
|
|||
;ACME 0.97
|
||||
; extensions of CMOS re-design (65c02), but with Z reg of 65ce02:
|
||||
tsb $04 ; 04
|
||||
tsb $0c0c ; 0c
|
||||
ora ($12), z ; 12 !
|
||||
trb $04 ; 14
|
||||
inc ; 1a
|
||||
trb $0c0c ; 1c
|
||||
and ($12), z ; 32 !
|
||||
bit $34, x ; 34
|
||||
dec ; 3a
|
||||
bit $3c3c, x ; 3c
|
||||
eor ($12), z ; 52 !
|
||||
phy ; 5a
|
||||
stz $04 ; 64
|
||||
adc ($12), z ; 72 !
|
||||
stz $34, x ; 74
|
||||
ply ; 7a
|
||||
jmp ($7c7c, x) ; 7c
|
||||
bra * + 2 ; 80
|
||||
bit #$89 ; 89
|
||||
sta ($12), z ; 92 !
|
||||
stz $0c0c ; 9c
|
||||
stz $3c3c, x ; 9e
|
||||
lda ($12), z ; b2 !
|
||||
cmp ($12), z ; d2 !
|
||||
phx ; da
|
||||
sbc ($12), z ; f2 !
|
||||
plx ; fa
|
||||
; extensions of 65ce02:
|
||||
cle ; 02
|
||||
see ; 03
|
||||
tsy ; 0b
|
||||
lbpl * + 2 ; 13
|
||||
inz ; 1b
|
||||
jsr ($2222) ; 22
|
||||
jsr ($2323, x) ; 23
|
||||
tys ; 2b
|
||||
lbmi * + 2 ; 33
|
||||
dez ; 3b
|
||||
neg ; 42
|
||||
asr ; 43
|
||||
asr $44 ; 44
|
||||
taz ; 4b
|
||||
lbvc * + 2 ; 53
|
||||
asr $54, x ; 54
|
||||
tab ; 5b
|
||||
; aug ; 5c this is different between 65ce02 and 4502
|
||||
rtn #$62 ; 62
|
||||
bsr * + 2 ; 63
|
||||
tza ; 6b
|
||||
lbvs * + 2 ; 73
|
||||
tba ; 7b
|
||||
sta ($82, s), y ; 82
|
||||
lbra * + 2 ; 83
|
||||
sty $8b8b, x ; 8b
|
||||
lbcc * + 2 ; 93
|
||||
stx $9b9b, y ; 9b
|
||||
ldz #$62 ; a3
|
||||
ldz $abab ; ab
|
||||
lbcs * + 2 ; b3
|
||||
ldz $8b8b, x ; bb
|
||||
cpz #$62 ; c2
|
||||
dew $44 ; c3
|
||||
asw $abab ; cb
|
||||
lbne * + 2 ; d3
|
||||
cpz $44 ; d4
|
||||
phz ; db
|
||||
cpz $abab ; dc
|
||||
lda ($82, s), y ; e2
|
||||
inw $44 ; e3
|
||||
row $abab ; eb
|
||||
lbeq * + 2 ; f3
|
||||
phw #$f4f4 ; f4
|
||||
plz ; fb
|
||||
phw $abab ; fc
|
34
testing/cpus/include-bitmanips.a
Normal file
34
testing/cpus/include-bitmanips.a
Normal file
|
@ -0,0 +1,34 @@
|
|||
;ACME 0.97
|
||||
; bit-manipulation instructions:
|
||||
rmb0 $07 ; 07
|
||||
bbr0 $0f, * + 3 ; 0f
|
||||
rmb1 $07 ; 17
|
||||
bbr1 $0f, * + 3 ; 1f
|
||||
rmb2 $07 ; 27
|
||||
bbr2 $0f, * + 3 ; 2f
|
||||
rmb3 $07 ; 37
|
||||
bbr3 $0f, * + 3 ; 3f
|
||||
rmb4 $07 ; 47
|
||||
bbr4 $0f, * + 3 ; 4f
|
||||
rmb5 $07 ; 57
|
||||
bbr5 $0f, * + 3 ; 5f
|
||||
rmb6 $07 ; 67
|
||||
bbr6 $0f, * + 3 ; 6f
|
||||
rmb7 $07 ; 77
|
||||
bbr7 $0f, * + 3 ; 7f
|
||||
smb0 $07 ; 87
|
||||
bbs0 $0f, * + 3 ; 8f
|
||||
smb1 $07 ; 97
|
||||
bbs1 $0f, * + 3 ; 9f
|
||||
smb2 $07 ; a7
|
||||
bbs2 $0f, * + 3 ; af
|
||||
smb3 $07 ; b7
|
||||
bbs3 $0f, * + 3 ; bf
|
||||
smb4 $07 ; c7
|
||||
bbs4 $0f, * + 3 ; cf
|
||||
smb5 $07 ; d7
|
||||
bbs5 $0f, * + 3 ; df
|
||||
smb6 $07 ; e7
|
||||
bbs6 $0f, * + 3 ; ef
|
||||
smb7 $07 ; f7
|
||||
bbs7 $0f, * + 3 ; ff
|
82
testing/cpus/include-undoc.a
Normal file
82
testing/cpus/include-undoc.a
Normal file
|
@ -0,0 +1,82 @@
|
|||
;ACME 0.97
|
||||
; undocumented opcodes of NMOS 6502:
|
||||
jam ; 02
|
||||
slo ($03, x) ; 03
|
||||
dop $04 ; 04
|
||||
nop $04 ; 04
|
||||
slo $04 ; 07
|
||||
!ifndef C64DTV2 {
|
||||
anc #$0b ; 0b (dtv does not support this)
|
||||
}
|
||||
top ; 0c
|
||||
top $0c0f ; 0c
|
||||
nop $0c0f ; 0c
|
||||
slo $0c0f ; 0f
|
||||
slo ($13), y ; 13
|
||||
dop $14, x ; 14
|
||||
nop $14, x ; 14
|
||||
slo $14, x ; 17
|
||||
slo $1b1b, y ; 1b
|
||||
top $1c1f, x ; 1c
|
||||
nop $1c1f, x ; 1c
|
||||
slo $1c1f, x ; 1f
|
||||
rla ($03, x) ; 23
|
||||
rla $04 ; 27
|
||||
rla $0c0f ; 2f
|
||||
rla ($13), y ; 33
|
||||
rla $14, x ; 37
|
||||
rla $1b1b, y ; 3b
|
||||
rla $1c1f, x ; 3f
|
||||
sre ($03, x) ; 43
|
||||
sre $04 ; 47
|
||||
alr #$0b ; 4b
|
||||
asr #$0b ; 4b
|
||||
sre $0c0f ; 4f
|
||||
sre ($13), y ; 53
|
||||
sre $14, x ; 57
|
||||
sre $1b1b, y ; 5b
|
||||
sre $1c1f, x ; 5f
|
||||
rra ($03, x) ; 63
|
||||
rra $04 ; 67
|
||||
arr #$0b ; 6b
|
||||
rra $0c0f ; 6f
|
||||
rra ($13), y ; 73
|
||||
rra $14, x ; 77
|
||||
rra $1b1b, y ; 7b
|
||||
rra $1c1f, x ; 7f
|
||||
dop ; 80
|
||||
dop #$0b ; 80
|
||||
nop #$0b ; 80
|
||||
sax ($03, x) ; 83
|
||||
sax $04 ; 87
|
||||
ane #0 ; 8b (anything non-zero gives a warning)
|
||||
sax $0c0f ; 8f
|
||||
sha ($13), y ; 93
|
||||
sax $97, y ; 97
|
||||
tas $1b1b, y ; 9b
|
||||
shy $1c1f, x ; 9c
|
||||
shx $1b1b, y ; 9e
|
||||
sha $1b1b, y ; 9f
|
||||
lax ($03, x) ; a3
|
||||
lax $04 ; a7
|
||||
lxa #0 ; ab (anything non-zero gives a warning)
|
||||
lax $0c0f ; af
|
||||
lax ($13), y ; b3
|
||||
lax $97, y ; b7
|
||||
las $1b1b, y ; bb
|
||||
lax $1b1b, y ; bf
|
||||
dcp ($03, x) ; c3
|
||||
dcp $04 ; c7
|
||||
sbx #$0b ; cb
|
||||
dcp $0c0f ; cf
|
||||
dcp ($13), y ; d3
|
||||
dcp $14, x ; d7
|
||||
dcp $1b1b, y ; db
|
||||
dcp $1c1f, x ; df
|
||||
isc ($03, x) ; e3
|
||||
isc $04 ; e7
|
||||
isc $0c0f ; ef
|
||||
isc ($13), y ; f3
|
||||
isc $14, x ; f7
|
||||
isc $1b1b, y ; fb
|
||||
isc $1c1f, x ; ff
|
12
testing/cpus/test-4502.a
Normal file
12
testing/cpus/test-4502.a
Normal file
|
@ -0,0 +1,12 @@
|
|||
;ACME 0.97
|
||||
!cpu 4502
|
||||
!to "out-4502.o", plain
|
||||
*=$1000
|
||||
!src "include-6502.a"
|
||||
; !src "include-65c02.a" ; not used, because 65ce02 changes "(zp)" to "(zp), z"
|
||||
!src "include-bitmanips.a"
|
||||
!src "include-65ce02.a"
|
||||
; this differs between 65ce02 and 4502:
|
||||
map ; $5c
|
||||
; this is an alias for NOP:
|
||||
eom ; $ea, "end of mapping"
|
5
testing/cpus/test-6502.a
Normal file
5
testing/cpus/test-6502.a
Normal file
|
@ -0,0 +1,5 @@
|
|||
;ACME 0.97
|
||||
!cpu 6502
|
||||
!to "out-6502.o", plain
|
||||
*=$1000
|
||||
!src "include-6502.a"
|
118
testing/cpus/test-65816.a
Normal file
118
testing/cpus/test-65816.a
Normal file
|
@ -0,0 +1,118 @@
|
|||
;ACME 0.97
|
||||
!cpu 65816
|
||||
!to "out-65816.o", plain
|
||||
*=$1000
|
||||
!src "include-6502.a"
|
||||
!src "include-65c02.a"
|
||||
; !src "include-bitmanips.a" 65816 does not support these
|
||||
|
||||
; new instructions of 65816:
|
||||
cop $02 ; 02
|
||||
ora $03, s ; 03
|
||||
ora [$07] ; 07
|
||||
phd ; 0b
|
||||
ora $0f0f0f ; 0f
|
||||
ora ($13, s), y ; 13
|
||||
ora [$17], y ; 17
|
||||
tcs ; 1b
|
||||
ora $1f1f1f, x ; 1f
|
||||
jsr $0f0f0f ; 22
|
||||
and $03, s ; 23
|
||||
and [$07] ; 27
|
||||
pld ; 2b
|
||||
and $0f0f0f ; 2f
|
||||
and ($13, s), y ; 33
|
||||
and [$17], y ; 37
|
||||
tsc ; 3b
|
||||
and $1f1f1f, x ; 3f
|
||||
wdm ; 42
|
||||
eor $03, s ; 43
|
||||
mvp $44, $54 ; 44
|
||||
eor [$07] ; 47
|
||||
phk ; 4b
|
||||
eor $0f0f0f ; 4f
|
||||
eor ($13, s), y ; 53
|
||||
mvn $44, $54 ; 54
|
||||
eor [$17], y ; 57
|
||||
tcd ; 5b
|
||||
jmp $0f0f0f ; 5c
|
||||
eor $1f1f1f, x ; 5f
|
||||
per * + 3 ; 62
|
||||
adc $03, s ; 63
|
||||
adc [$07] ; 67
|
||||
rtl ; 6b
|
||||
adc $0f0f0f ; 6f
|
||||
adc ($13, s), y ; 73
|
||||
adc [$17], y ; 77
|
||||
tdc ; 7b
|
||||
adc $1f1f1f, x ; 7f
|
||||
brl * + 3 ; 82
|
||||
sta $03, s ; 83
|
||||
sta [$07] ; 87
|
||||
phb ; 8b
|
||||
sta $0f0f0f ; 8f
|
||||
sta ($13, s), y ; 93
|
||||
sta [$17], y ; 97
|
||||
txy ; 9b
|
||||
sta $1f1f1f, x ; 9f
|
||||
lda $03, s ; a3
|
||||
lda [$07] ; a7
|
||||
plb ; ab
|
||||
lda $0f0f0f ; af
|
||||
lda ($13, s), y ; b3
|
||||
lda [$17], y ; b7
|
||||
tyx ; bb
|
||||
lda $1f1f1f, x ; bf
|
||||
rep #$c2 ; c2, see below
|
||||
cmp $03, s ; c3
|
||||
cmp [$07] ; c7
|
||||
wai ; cb
|
||||
cmp $0f0f0f ; cf
|
||||
cmp ($13, s), y ; d3
|
||||
pei ($d4) ; d4
|
||||
cmp [$17], y ; d7
|
||||
stp ; db
|
||||
jmp [$dcdc] ; dc
|
||||
cmp $1f1f1f, x ; df
|
||||
sep #$e2 ; e2, see below
|
||||
sbc $03, s ; e3
|
||||
sbc [$07] ; e7
|
||||
xba ; eb
|
||||
sbc $0f0f0f ; ef
|
||||
sbc ($13, s), y ; f3
|
||||
pea $f4f4 ; f4
|
||||
sbc [$17], y ; f7
|
||||
xce ; fb
|
||||
jsr ($fcfc, x) ; fc
|
||||
sbc $1f1f1f, x ; ff
|
||||
|
||||
; check sizes of immediate arguments:
|
||||
!macro immediates {
|
||||
; arg size depends on:
|
||||
; from 6502:
|
||||
ora #$09 ; 09 accumulator size
|
||||
and #$09 ; 29 accumulator size
|
||||
eor #$09 ; 49 accumulator size
|
||||
adc #$09 ; 69 accumulator size
|
||||
ldy #$09 ; a0 index register size
|
||||
ldx #$09 ; a2 index register size
|
||||
lda #$09 ; a9 accumulator size
|
||||
cpy #$09 ; c0 index register size
|
||||
cmp #$09 ; c9 accumulator size
|
||||
cpx #$09 ; e0 index register size
|
||||
sbc #$09 ; e9 accumulator size
|
||||
; from 65c02:
|
||||
bit #$89 ; 89 accumulator size
|
||||
; from 65816:
|
||||
rep #$c2 ; c2 always 8 bits
|
||||
sep #$e2 ; e2 always 8 bits
|
||||
}
|
||||
; before this, all sizes were 8 bits
|
||||
!al
|
||||
+immediates ; now repeat immediates with long accumulator
|
||||
!as
|
||||
!rl
|
||||
+immediates ; repeat immediates with short A and long index regs
|
||||
!al
|
||||
!rl
|
||||
+immediates ; repeat immediates with long A and long index regs
|
6
testing/cpus/test-65c02.a
Normal file
6
testing/cpus/test-65c02.a
Normal file
|
@ -0,0 +1,6 @@
|
|||
;ACME 0.97
|
||||
!cpu 65c02
|
||||
!to "out-65c02.o", plain
|
||||
*=$1000
|
||||
!src "include-6502.a"
|
||||
!src "include-65c02.a"
|
10
testing/cpus/test-65ce02.a
Normal file
10
testing/cpus/test-65ce02.a
Normal file
|
@ -0,0 +1,10 @@
|
|||
;ACME 0.97
|
||||
!cpu 65ce02
|
||||
!to "out-65ce02.o", plain
|
||||
*=$1000
|
||||
!src "include-6502.a"
|
||||
; !src "include-65c02.a" ; not used, because 65ce02 changes "(zp)" to "(zp), z"
|
||||
!src "include-bitmanips.a"
|
||||
!src "include-65ce02.a"
|
||||
; this differs between 65ce02 and 4502:
|
||||
aug ; $5c ("4-byte NOP reserved for future expansion")
|
11
testing/cpus/test-c64dtv2.a
Normal file
11
testing/cpus/test-c64dtv2.a
Normal file
|
@ -0,0 +1,11 @@
|
|||
;ACME 0.97
|
||||
!cpu c64dtv2
|
||||
!to "out-c64dtv2.o", plain
|
||||
*=$1000
|
||||
!src "include-6502.a"
|
||||
C64DTV2 = 1 ; make next include skip the ANC instruction (not supported by C64DTV2)
|
||||
!src "include-undoc.a"
|
||||
; additional instructions of C64DTV2:
|
||||
bra * + 2 ; 12, branch always
|
||||
sac #$32 ; 32, set accumulator mapping
|
||||
sir #$42 ; 42, set index register mapping
|
137
testing/cpus/test-m65.a
Normal file
137
testing/cpus/test-m65.a
Normal file
|
@ -0,0 +1,137 @@
|
|||
;ACME 0.97
|
||||
!cpu m65
|
||||
!to "out-m65.o", plain
|
||||
*=$1000
|
||||
M65 = 1 ; make next include skip the NOP mnemonic (re-used as prefix code by M65)
|
||||
!src "include-6502.a"
|
||||
; !src "include-65c02.a" ; not used, because 65ce02 changes "(zp)" to "(zp), z"
|
||||
!src "include-bitmanips.a"
|
||||
!src "include-65ce02.a"
|
||||
; this differs between 65ce02 and 4502:
|
||||
map ; $5c
|
||||
; this is an alias for NOP:
|
||||
eom ; $ea, "end of mapping"
|
||||
|
||||
; "quad mode" m65 extension using NEG:NEG prefix:
|
||||
; (instructions that are commented out might be re-purposed later)
|
||||
;orq ($01, x) ; 01
|
||||
orq $05 ; 05
|
||||
aslq $05 ; 06
|
||||
aslq ; 0a
|
||||
orq $0d0e ; 0d
|
||||
aslq $0d0e ; 0e
|
||||
;orq ($11), y ; 11
|
||||
orq ($12) ; 12
|
||||
;orq $15, x ; 15
|
||||
aslq $15, x ; 16
|
||||
;orq $1919, y ; 19
|
||||
inq ; 1a
|
||||
;orq $1d1e, x ; 1d
|
||||
aslq $1d1e, x ; 1e
|
||||
;andq ($01, x) ; 21
|
||||
bitq $05 ; 24
|
||||
andq $05 ; 25
|
||||
rolq $05 ; 26
|
||||
rolq ; 2a
|
||||
bitq $0d0e ; 2c
|
||||
andq $0d0e ; 2d
|
||||
rolq $0d0e ; 2e
|
||||
;andq ($11), y ; 31
|
||||
andq ($12) ; 32
|
||||
;bitq $15, x ; 34
|
||||
;andq $15, x ; 35
|
||||
rolq $15, x ; 36
|
||||
;andq $1919, y ; 39
|
||||
deq ; 3a
|
||||
;bitq $1d1e, x ; 3c
|
||||
;andq $1d1e, x ; 3d
|
||||
rolq $1d1e, x ; 3e
|
||||
;eorq ($01, x) ; 41
|
||||
asrq ; 43
|
||||
asrq $05 ; 44
|
||||
eorq $05 ; 45
|
||||
lsrq $05 ; 46
|
||||
lsrq ; 4a
|
||||
eorq $0d0e ; 4d
|
||||
lsrq $0d0e ; 4e
|
||||
;eorq ($11), y ; 51
|
||||
eorq ($12) ; 52
|
||||
asrq $15, x ; 54
|
||||
;eorq $15, x ; 55
|
||||
lsrq $15, x ; 56
|
||||
;eorq $1919, y ; 59
|
||||
;eorq $1d1e, x ; 5d
|
||||
lsrq $1d1e, x ; 5e
|
||||
;adcq ($01, x) ; 61
|
||||
adcq $05 ; 65
|
||||
rorq $05 ; 66
|
||||
rorq ; 6a
|
||||
adcq $0d0e ; 6d
|
||||
rorq $0d0e ; 6e
|
||||
;adcq ($11), y ; 71
|
||||
adcq ($12) ; 72
|
||||
;adcq $15, x ; 75
|
||||
rorq $15, x ; 76
|
||||
;adcq $1919, y ; 79
|
||||
;adcq $1d1e, x ; 7d
|
||||
rorq $1d1e, x ; 7e
|
||||
;stq ($01, x) ; 81
|
||||
;stq ($82, s), y ; 82
|
||||
stq $05 ; 85
|
||||
stq $0d0e ; 8d
|
||||
;stq ($11), y ; 91
|
||||
stq ($12) ; 92
|
||||
;stq $15, x ; 95
|
||||
;stq $1919, y ; 99
|
||||
;stq $1d1e, x ; 9d
|
||||
;ldq ($01, x) ; a1
|
||||
ldq $05 ; a5
|
||||
ldq $0d0e ; ad
|
||||
ldq ($11), y ; b1
|
||||
ldq ($12) ; b2
|
||||
ldq $15, x ; b5
|
||||
ldq $1919, y ; b9
|
||||
ldq $1d1e, x ; bd
|
||||
;cpq ($01, x) ; c1
|
||||
cpq $05 ; c5
|
||||
deq $05 ; c6
|
||||
cpq $0d0e ; cd
|
||||
deq $0d0e ; ce
|
||||
;cpq ($11), y ; d1
|
||||
cpq ($12) ; d2
|
||||
;cpq $15, x ; d5
|
||||
deq $15, x ; d6
|
||||
;cpq $1919, y ; d9
|
||||
;cpq $1d1e, x ; dd
|
||||
deq $1d1e, x ; de
|
||||
;sbcq ($01, x) ; e1
|
||||
ldq ($e2, s), y ; e2
|
||||
sbcq $05 ; e5
|
||||
inq $05 ; e6
|
||||
sbcq $0d0e ; ed
|
||||
inq $0d0e ; ee
|
||||
;sbcq ($11), y ; f1
|
||||
sbcq ($12) ; f2
|
||||
;sbcq $15, x ; f5
|
||||
inq $15, x ; f6
|
||||
;sbcq $1919, y ; f9
|
||||
;sbcq $1d1e, x ; fd
|
||||
inq $1d1e, x ; fe
|
||||
; "long mode" m65 extension using NOP prefix:
|
||||
ora [$12], z ; 12
|
||||
and [$12], z ; 32
|
||||
eor [$12], z ; 52
|
||||
adc [$12], z ; 72
|
||||
sta [$12], z ; 92
|
||||
lda [$12], z ; b2
|
||||
cmp [$12], z ; d2
|
||||
sbc [$12], z ; f2
|
||||
; "quad mode" and "long mode" combined using NEG:NEG:NOP prefix:
|
||||
orq [$12] ; 12
|
||||
andq [$12] ; 32
|
||||
eorq [$12] ; 52
|
||||
adcq [$12] ; 72
|
||||
stq [$12] ; 92
|
||||
ldq [$12] ; b2
|
||||
cpq [$12] ; d2
|
||||
sbcq [$12] ; f2
|
6
testing/cpus/test-nmos6502.a
Normal file
6
testing/cpus/test-nmos6502.a
Normal file
|
@ -0,0 +1,6 @@
|
|||
;ACME 0.97
|
||||
!cpu nmos6502
|
||||
!to "out-nmos6502.o", plain
|
||||
*=$1000
|
||||
!src "include-6502.a"
|
||||
!src "include-undoc.a"
|
7
testing/cpus/test-r65c02.a
Normal file
7
testing/cpus/test-r65c02.a
Normal file
|
@ -0,0 +1,7 @@
|
|||
;ACME 0.97
|
||||
!cpu r65c02
|
||||
!to "out-r65c02.o", plain
|
||||
*=$1000
|
||||
!src "include-6502.a"
|
||||
!src "include-65c02.a"
|
||||
!src "include-bitmanips.a"
|
10
testing/cpus/test-w65c02.a
Normal file
10
testing/cpus/test-w65c02.a
Normal file
|
@ -0,0 +1,10 @@
|
|||
;ACME 0.97
|
||||
!cpu w65c02
|
||||
!to "out-w65c02.o", plain
|
||||
*=$1000
|
||||
!src "include-6502.a"
|
||||
!src "include-65c02.a"
|
||||
!src "include-bitmanips.a"
|
||||
; WDC extensions:
|
||||
wai ; cb
|
||||
stp ; db
|
3
testing/errors/alreadydefined6.a
Normal file
3
testing/errors/alreadydefined6.a
Normal file
|
@ -0,0 +1,3 @@
|
|||
;ACME 0.97
|
||||
a = "somestring"
|
||||
a = "someotherstring" ; -> "already defined" (value has changed)
|
14
testing/errors/outofrange.a
Normal file
14
testing/errors/outofrange.a
Normal file
|
@ -0,0 +1,14 @@
|
|||
;ACME 0.97
|
||||
*=$1000
|
||||
; these must throw errors:
|
||||
!by -129, 256
|
||||
!wo -32769, 65536
|
||||
!24 -0x800001, 16777216
|
||||
; 32-bit values are not range checked atm:
|
||||
!32 -0x80000001, 0x100000000
|
||||
|
||||
; these must work:
|
||||
!by -128, 255
|
||||
!wo -32768, 65535
|
||||
!24 -0x800000, 16777215
|
||||
!32 -0x80000000, 0xffffffff
|
4
testing/warnings/binlen.a
Normal file
4
testing/warnings/binlen.a
Normal file
|
@ -0,0 +1,4 @@
|
|||
;ACME 0.97
|
||||
a = %........ ; eight digits
|
||||
a = %.......
|
||||
a = %.........
|
Loading…
Reference in New Issue
Block a user