From 7a9a0cb41f969f96d68cdd5a2628ac4d3dac6a0b Mon Sep 17 00:00:00 2001 From: Zellyn Hunter Date: Thu, 5 May 2016 21:18:29 -0400 Subject: [PATCH] First (wrong) pass at as65 - Renamed "oldschool" to "common" - plan to base as65 and acme on it too. - Renamed opcode.Flavor to opcode.Set - too many uses of the word "flavor". - First implementation of as65: simply based it on common core. No tests yet demonstrate that that is incorrect :-) --- asm/cmd/a2as/a2as.go | 14 +- asm/flavors/as65/as65.go | 111 ++++++++++----- .../oldschool.go => common/base.go} | 8 +- asm/flavors/common/{common.go => decodeop.go} | 15 ++ asm/flavors/merlin/merlin.go | 22 +-- asm/flavors/redbook/redbook.go | 28 ++-- asm/flavors/scma/scma.go | 18 +-- asm/flavors/tests/assemble_test.go | 6 +- asm/flavors/tests/simple_parse_test.go | 130 +++++++++--------- asm/inst/instruction.go | 5 + opcodes/opcodes.go | 8 +- 11 files changed, 213 insertions(+), 152 deletions(-) rename asm/flavors/{oldschool/oldschool.go => common/base.go} (99%) rename asm/flavors/common/{common.go => decodeop.go} (93%) diff --git a/asm/cmd/a2as/a2as.go b/asm/cmd/a2as/a2as.go index 5e82f2f..11bc163 100644 --- a/asm/cmd/a2as/a2as.go +++ b/asm/cmd/a2as/a2as.go @@ -57,21 +57,21 @@ func main() { } var f flavors.F - var flavor opcodes.Flavor + var set opcodes.Set if *sweet16 { - flavor |= opcodes.FlavorSweet16 + set |= opcodes.SetSweet16 } switch *flavorName { case "merlin": - f = merlin.New(flavor) + f = merlin.New(set) case "scma": - f = scma.New(flavor) + f = scma.New(set) case "redbooka": - f = redbook.NewRedbookA(flavor) + f = redbook.NewRedbookA(set) case "redbookb": - f = redbook.NewRedbookB(flavor) + f = redbook.NewRedbookB(set) default: - fmt.Fprintf(os.Stderr, "invalid flavor: '%s'\n", flavor) + fmt.Fprintf(os.Stderr, "invalid flavor: %q\n", *flavorName) os.Exit(1) } diff --git a/asm/flavors/as65/as65.go b/asm/flavors/as65/as65.go index cecf0b3..a3bcb0b 100644 --- a/asm/flavors/as65/as65.go +++ b/asm/flavors/as65/as65.go @@ -1,56 +1,95 @@ package as65 import ( - "errors" + "fmt" "github.com/zellyn/go6502/asm/context" - "github.com/zellyn/go6502/asm/flavors" + "github.com/zellyn/go6502/asm/expr" + "github.com/zellyn/go6502/asm/flavors/common" "github.com/zellyn/go6502/asm/inst" "github.com/zellyn/go6502/asm/lines" "github.com/zellyn/go6502/opcodes" ) -// AS65 implements the AS65-compatible assembler flavor. -// See http://www.kingswood-consulting.co.uk/assemblers/ - -type AS65 struct { - OpcodesByName map[string]opcodes.OpSummary +// As65 implements an as65-compatible assembler flavor. +type As65 struct { + common.Base } -func New(flavors opcodes.Flavor) *AS65 { - return &AS65{ - OpcodesByName: opcodes.ByName(flavors), +func New(sets opcodes.Set) *As65 { + a := &As65{} + a.Name = "as65" + a.OpcodesByName = opcodes.ByName(sets) + a.LabelChars = common.Letters + common.Digits + "." + a.LabelColons = common.ReqOptional + a.ExplicitARegister = common.ReqRequired + a.StringEndOptional = true + a.CommentChar = ';' + a.MsbChars = "/" + a.ImmediateChars = "#" + a.HexCommas = common.ReqOptional + a.DefaultOriginVal = 0x0800 + + a.Directives = map[string]common.DirectiveInfo{ + "ORG": {inst.TypeOrg, a.ParseOrg, 0}, + "OBJ": {inst.TypeNone, nil, 0}, + "ENDASM": {inst.TypeEnd, a.ParseNoArgDir, 0}, + "EQU": {inst.TypeEqu, a.ParseEquate, inst.VarEquNormal}, + "EPZ": {inst.TypeEqu, a.ParseEquate, inst.VarEquPageZero}, + "DFB": {inst.TypeData, a.ParseData, inst.VarBytes}, + "DW": {inst.TypeData, a.ParseData, inst.VarWordsLe}, + "DDB": {inst.TypeData, a.ParseData, inst.VarWordsBe}, + "ASC": {inst.TypeData, a.ParseAscii, inst.VarAscii}, + "DCI": {inst.TypeData, a.ParseAscii, inst.VarAsciiFlip}, + "HEX": {inst.TypeData, a.ParseHexString, inst.VarBytes}, + "PAGE": {inst.TypeNone, nil, 0}, // New page + "TITLE": {inst.TypeNone, nil, 0}, // Title + "SBTL": {inst.TypeNone, nil, 0}, // Subtitle + "SKP": {inst.TypeNone, nil, 0}, // Skip lines + "REP": {inst.TypeNone, nil, 0}, // Repeat character + "CHR": {inst.TypeNone, nil, 0}, // Set repeated character } -} -// Parse an entire instruction, or return an appropriate error. -func (a *AS65) ParseInstr(ctx context.Context, line lines.Line, mode flavors.ParseMode) (inst.I, error) { - return inst.I{}, nil -} + a.EquateDirectives = map[string]bool{ + "EQU": true, + "EPZ": true, + } -func (a *AS65) Zero() (uint16, error) { - return 0, errors.New("Division by zero.") -} + a.Operators = map[string]expr.Operator{ + "*": expr.OpMul, + "/": expr.OpDiv, + "+": expr.OpPlus, + "-": expr.OpMinus, + "<": expr.OpLt, + ">": expr.OpGt, + "=": expr.OpEq, + } -func (a *AS65) DefaultOrigin() uint16 { - return 0 -} + a.InitContextFunc = func(ctx context.Context) { + ctx.SetOnOffDefaults(map[string]bool{ + "MSB": true, // MSB defaults to true, as per manual + "LST": true, // Display listing: not used + }) + } -func (a *AS65) ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error) { - panic("AS65.ReplaceMacroArgs not implemented yet.") -} + a.SetAsciiVariation = func(ctx context.Context, in *inst.I, lp *lines.Parse) { + if in.Command == "ASC" { + if ctx.Setting("MSB") { + in.Var = inst.VarAsciiHi + } else { + in.Var = inst.VarAscii + } + return + } + if in.Command == "DCI" { + in.Var = inst.VarAsciiFlip + } else { + panic(fmt.Sprintf("Unknown ascii directive: '%s'", in.Command)) + } + } -func (a *AS65) IsNewParentLabel(label string) bool { - return label != "" && label[0] != '.' -} + a.FixLabel = a.DefaultFixLabel + a.IsNewParentLabel = a.DefaultIsNewParentLabel -func (a *AS65) LocalMacroLabels() bool { - return false -} - -func (a *AS65) String() string { - return "as65" -} - -func (a *AS65) InitContext(ctx context.Context) { + return a } diff --git a/asm/flavors/oldschool/oldschool.go b/asm/flavors/common/base.go similarity index 99% rename from asm/flavors/oldschool/oldschool.go rename to asm/flavors/common/base.go index 2ce89b7..498eee9 100644 --- a/asm/flavors/oldschool/oldschool.go +++ b/asm/flavors/common/base.go @@ -1,4 +1,4 @@ -package oldschool +package common import ( "encoding/hex" @@ -11,7 +11,6 @@ import ( "github.com/zellyn/go6502/asm/context" "github.com/zellyn/go6502/asm/expr" "github.com/zellyn/go6502/asm/flavors" - "github.com/zellyn/go6502/asm/flavors/common" "github.com/zellyn/go6502/asm/inst" "github.com/zellyn/go6502/asm/lines" "github.com/zellyn/go6502/opcodes" @@ -240,7 +239,8 @@ func (a *Base) parseCmd(ctx context.Context, in inst.I, lp *lines.Parse, mode fl return a.parseSetting(ctx, in, lp) } - if summary, ok := a.OpcodesByName[in.Command]; ok { + upperCmd := strings.ToUpper(in.Command) + if summary, ok := a.OpcodesByName[upperCmd]; ok { in.Type = inst.TypeOp return a.parseOpArgs(ctx, in, lp, summary, false) } @@ -416,7 +416,7 @@ func (a *Base) parseOpArgs(ctx context.Context, in inst.I, lp *lines.Parse, summ } } - return common.DecodeOp(ctx, in, summary, indirect, xy, forceWide) + return DecodeOp(ctx, in, summary, indirect, xy, forceWide) } func (a *Base) ParseOrg(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) { diff --git a/asm/flavors/common/common.go b/asm/flavors/common/decodeop.go similarity index 93% rename from asm/flavors/common/common.go rename to asm/flavors/common/decodeop.go index 036708b..b0c86c8 100644 --- a/asm/flavors/common/common.go +++ b/asm/flavors/common/decodeop.go @@ -29,6 +29,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect in.Op = op.Byte in.Width = 2 in.Var = inst.VarOpByte + in.ModeStr = "indx" if valKnown { in.Final = true in.Data = []byte{in.Op, byte(val)} @@ -45,6 +46,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect in.Width = 2 in.Op = op.Byte in.Var = inst.VarOpByte + in.ModeStr = "indy" if valKnown { in.Final = true in.Data = []byte{in.Op, byte(val)} @@ -58,6 +60,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect in.Op = op.Byte in.Width = 3 in.Var = inst.VarOpWord + in.ModeStr = "ind" if valKnown { in.Final = true in.Data = []byte{in.Op, byte(val), byte(val >> 8)} @@ -99,6 +102,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect in.Op = op.Byte in.Width = 2 in.Var = inst.VarOpByte + in.ModeStr = "imm" if valKnown { in.Data = []byte{in.Op, byte(val)} in.Final = true @@ -108,16 +112,20 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect var zp, wide opcodes.AddressingMode var zpS, wideS string + var zpM, wideM string // ModeStr - for debug printing switch xy { case 'x': zp, wide = opcodes.MODE_ZP_X, opcodes.MODE_ABS_X zpS, wideS = "ZeroPage,X", "Absolute,X" + zpM, wideM = "zpx", "absx" case 'y': zp, wide = opcodes.MODE_ZP_Y, opcodes.MODE_ABS_Y zpS, wideS = "ZeroPage,Y", "Absolute,Y" + zpM, wideM = "zpy", "absy" default: zp, wide = opcodes.MODE_ZP, opcodes.MODE_ABSOLUTE zpS, wideS = "ZeroPage", "Absolute" + zpM, wideM = "zp", "abs" } opWide, wideOk := summary.OpForMode(wide) @@ -131,6 +139,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect in.Op = opWide.Byte in.Width = 3 in.Var = inst.VarOpWord + in.ModeStr = wideM if valKnown { in.Data = []byte{in.Op, byte(val), byte(val >> 8)} in.Final = true @@ -144,6 +153,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect in.Op = opZp.Byte in.Width = 2 in.Var = inst.VarOpByte + in.ModeStr = zpM if valKnown { in.Data = []byte{in.Op, byte(val)} in.Final = true @@ -155,6 +165,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect in.Op = opWide.Byte in.Width = 3 in.Var = inst.VarOpWord + in.ModeStr = wideM if valKnown { in.Data = []byte{in.Op, byte(val), byte(val >> 8)} in.Final = true @@ -168,6 +179,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect in.Data = []byte{in.Op, byte(val)} in.Width = 2 in.Var = inst.VarOpByte + in.ModeStr = zpM in.Final = true return in, nil } @@ -175,6 +187,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect in.Data = []byte{in.Op, byte(val), byte(val >> 8)} in.Width = 3 in.Var = inst.VarOpWord + in.ModeStr = wideM in.Final = true return in, nil } @@ -183,12 +196,14 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect in.Op = opZp.Byte in.Width = 2 in.Var = inst.VarOpByte + in.ModeStr = zpM return in, nil } in.Op = opWide.Byte in.Width = 3 in.Var = inst.VarOpWord + in.ModeStr = wideM return in, nil } diff --git a/asm/flavors/merlin/merlin.go b/asm/flavors/merlin/merlin.go index 5dbb144..e90c69d 100644 --- a/asm/flavors/merlin/merlin.go +++ b/asm/flavors/merlin/merlin.go @@ -6,7 +6,7 @@ import ( "github.com/zellyn/go6502/asm/context" "github.com/zellyn/go6502/asm/expr" - "github.com/zellyn/go6502/asm/flavors/oldschool" + "github.com/zellyn/go6502/asm/flavors/common" "github.com/zellyn/go6502/asm/inst" "github.com/zellyn/go6502/asm/lines" "github.com/zellyn/go6502/opcodes" @@ -16,26 +16,26 @@ import ( // See http://en.wikipedia.org/wiki/Merlin_(assembler) and // http://www.apple-iigs.info/doc/fichiers/merlin816.pdf‎ type Merlin struct { - oldschool.Base + common.Base } const whitespace = " \t" -const macroNameChars = oldschool.Letters + oldschool.Digits + "_" +const macroNameChars = common.Letters + common.Digits + "_" -func New(flavors opcodes.Flavor) *Merlin { +func New(sets opcodes.Set) *Merlin { m := &Merlin{} m.Name = "merlin" - m.OpcodesByName = opcodes.ByName(flavors) - m.LabelChars = oldschool.Letters + oldschool.Digits + ":" - m.LabelColons = oldschool.ReqDisallowed - m.ExplicitARegister = oldschool.ReqOptional + m.OpcodesByName = opcodes.ByName(sets) + m.LabelChars = common.Letters + common.Digits + ":" + m.LabelColons = common.ReqDisallowed + m.ExplicitARegister = common.ReqOptional m.StringEndOptional = false m.CommentChar = ';' m.BinaryChar = '%' m.LsbChars = "<" m.MsbChars = ">/" m.ImmediateChars = "#" - m.HexCommas = oldschool.ReqOptional + m.HexCommas = common.ReqOptional m.CharChars = "'" m.InvCharChars = `"` m.MacroArgSep = ";" @@ -43,7 +43,7 @@ func New(flavors opcodes.Flavor) *Merlin { m.LocalMacroLabelsVal = true m.DefaultOriginVal = 0x8000 - m.Directives = map[string]oldschool.DirectiveInfo{ + m.Directives = map[string]common.DirectiveInfo{ "ORG": {inst.TypeOrg, m.ParseOrg, 0}, "OBJ": {inst.TypeNone, nil, 0}, "ENDASM": {inst.TypeEnd, m.ParseNoArgDir, 0}, @@ -131,7 +131,7 @@ func New(flavors opcodes.Flavor) *Merlin { } in.Type = inst.TypeMacroCall - lp.IgnoreRun(oldschool.Whitespace) + lp.IgnoreRun(common.Whitespace) if !byName { if !lp.AcceptRun(macroNameChars) { c := lp.Next() diff --git a/asm/flavors/redbook/redbook.go b/asm/flavors/redbook/redbook.go index 48afb0b..d0ff9c0 100644 --- a/asm/flavors/redbook/redbook.go +++ b/asm/flavors/redbook/redbook.go @@ -5,7 +5,7 @@ import ( "github.com/zellyn/go6502/asm/context" "github.com/zellyn/go6502/asm/expr" - "github.com/zellyn/go6502/asm/flavors/oldschool" + "github.com/zellyn/go6502/asm/flavors/common" "github.com/zellyn/go6502/asm/inst" "github.com/zellyn/go6502/asm/lines" "github.com/zellyn/go6502/opcodes" @@ -13,36 +13,36 @@ import ( // RedBook implements a Redbook-listing-compatible-ish assembler flavor. type RedBook struct { - oldschool.Base + common.Base } -func NewRedbookA(flavors opcodes.Flavor) *RedBook { - r := newRedbook("redbook-a", flavors) +func NewRedbookA(sets opcodes.Set) *RedBook { + r := newRedbook("redbook-a", sets) return r } -func NewRedbookB(flavors opcodes.Flavor) *RedBook { - r := newRedbook("redbook-b", flavors) - r.ExplicitARegister = oldschool.ReqRequired +func NewRedbookB(sets opcodes.Set) *RedBook { + r := newRedbook("redbook-b", sets) + r.ExplicitARegister = common.ReqRequired r.SpacesForComment = 3 return r } -func newRedbook(name string, flavors opcodes.Flavor) *RedBook { +func newRedbook(name string, sets opcodes.Set) *RedBook { r := &RedBook{} r.Name = name - r.OpcodesByName = opcodes.ByName(flavors) - r.LabelChars = oldschool.Letters + oldschool.Digits + "." - r.LabelColons = oldschool.ReqOptional - r.ExplicitARegister = oldschool.ReqRequired + r.OpcodesByName = opcodes.ByName(sets) + r.LabelChars = common.Letters + common.Digits + "." + r.LabelColons = common.ReqOptional + r.ExplicitARegister = common.ReqRequired r.StringEndOptional = true r.CommentChar = ';' r.MsbChars = "/" r.ImmediateChars = "#" - r.HexCommas = oldschool.ReqOptional + r.HexCommas = common.ReqOptional r.DefaultOriginVal = 0x0800 - r.Directives = map[string]oldschool.DirectiveInfo{ + r.Directives = map[string]common.DirectiveInfo{ "ORG": {inst.TypeOrg, r.ParseOrg, 0}, "OBJ": {inst.TypeNone, nil, 0}, "ENDASM": {inst.TypeEnd, r.ParseNoArgDir, 0}, diff --git a/asm/flavors/scma/scma.go b/asm/flavors/scma/scma.go index 096c6ac..8bd001f 100644 --- a/asm/flavors/scma/scma.go +++ b/asm/flavors/scma/scma.go @@ -5,7 +5,7 @@ import ( "github.com/zellyn/go6502/asm/context" "github.com/zellyn/go6502/asm/expr" - "github.com/zellyn/go6502/asm/flavors/oldschool" + "github.com/zellyn/go6502/asm/flavors/common" "github.com/zellyn/go6502/asm/inst" "github.com/zellyn/go6502/asm/lines" "github.com/zellyn/go6502/opcodes" @@ -17,16 +17,16 @@ const commentWhitespacePrefix = " " // SCMA implements the S-C Macro Assembler-compatible assembler flavor. // See http://www.txbobsc.com/scsc/ and http://stjarnhimlen.se/apple2/ type SCMA struct { - oldschool.Base + common.Base } -func New(flavors opcodes.Flavor) *SCMA { +func New(sets opcodes.Set) *SCMA { a := &SCMA{} a.Name = "scma" - a.OpcodesByName = opcodes.ByName(flavors) - a.LabelChars = oldschool.Letters + oldschool.Digits + ".:" - a.LabelColons = oldschool.ReqDisallowed - a.ExplicitARegister = oldschool.ReqDisallowed + a.OpcodesByName = opcodes.ByName(sets) + a.LabelChars = common.Letters + common.Digits + ".:" + a.LabelColons = common.ReqDisallowed + a.ExplicitARegister = common.ReqDisallowed a.SpacesForComment = 2 a.MsbChars = "/" a.ImmediateChars = "#" @@ -36,7 +36,7 @@ func New(flavors opcodes.Flavor) *SCMA { divZeroVal := uint16(0xffff) a.DivZeroVal = &divZeroVal - a.Directives = map[string]oldschool.DirectiveInfo{ + a.Directives = map[string]common.DirectiveInfo{ ".IN": {inst.TypeInclude, a.ParseInclude, 0}, ".OR": {inst.TypeOrg, a.ParseOrg, 0}, ".TA": {inst.TypeTarget, a.ParseNotImplemented, 0}, @@ -107,7 +107,7 @@ func New(flavors opcodes.Flavor) *SCMA { in.Type = inst.TypeMacroCall in.Command = in.Command[1:] - lp.Consume(oldschool.Whitespace) + lp.Consume(common.Whitespace) for { s, err := a.ParseMacroArg(in, lp) diff --git a/asm/flavors/tests/assemble_test.go b/asm/flavors/tests/assemble_test.go index 608e92f..95466e9 100644 --- a/asm/flavors/tests/assemble_test.go +++ b/asm/flavors/tests/assemble_test.go @@ -30,13 +30,13 @@ func TestMultiline(t *testing.T) { o := lines.NewTestOpener() ss := asmFactory(func() *asm.Assembler { - return asm.NewAssembler(scma.New(opcodes.FlavorSweet16), o) + return asm.NewAssembler(scma.New(opcodes.SetSweet16), o) }) ra := asmFactory(func() *asm.Assembler { - return asm.NewAssembler(redbook.NewRedbookA(opcodes.FlavorSweet16), o) + return asm.NewAssembler(redbook.NewRedbookA(opcodes.SetSweet16), o) }) mm := asmFactory(func() *asm.Assembler { - return asm.NewAssembler(merlin.New(opcodes.FlavorSweet16), o) + return asm.NewAssembler(merlin.New(opcodes.SetSweet16), o) }) tests := []struct { diff --git a/asm/flavors/tests/simple_parse_test.go b/asm/flavors/tests/simple_parse_test.go index ff06463..838566b 100644 --- a/asm/flavors/tests/simple_parse_test.go +++ b/asm/flavors/tests/simple_parse_test.go @@ -16,11 +16,11 @@ import ( ) func TestSimpleCommonFunctions(t *testing.T) { - ss := scma.New(opcodes.FlavorSweet16) - ra := redbook.NewRedbookA(opcodes.FlavorSweet16) - rb := redbook.NewRedbookB(opcodes.FlavorSweet16) - // aa := as65.New(opcodes.FlavorSweet16) - mm := merlin.New(opcodes.FlavorSweet16) + ss := scma.New(opcodes.SetSweet16) + ra := redbook.NewRedbookA(opcodes.SetSweet16) + rb := redbook.NewRedbookB(opcodes.SetSweet16) + aa := as65.New(opcodes.SetSweet16) + mm := merlin.New(opcodes.SetSweet16) tests := []struct { f flavors.F // assembler flavor @@ -28,27 +28,27 @@ func TestSimpleCommonFunctions(t *testing.T) { p string // printed instruction, expected b string // bytes, expected }{ - // {aa, " beq $2343", "{BEQ/rel $2343}", "f0fc"}, - // {aa, " beq $2345", "{BEQ/rel $2345}", "f0fe"}, - // {aa, " beq $2347", "{BEQ/rel $2347}", "f000"}, + {aa, " beq $2343", "{beq $2343}", "f0fc"}, + {aa, " beq $2345", "{beq $2345}", "f0fe"}, + {aa, " beq $2347", "{beq $2347}", "f000"}, // {aa, " dw $1234", "{data/wle $1234}", "3412"}, - // {aa, " jmp $1234", "{JMP/abs $1234}", "4c3412"}, - // {aa, " jmp ($1234)", "{JMP/ind $1234}", "6c3412"}, - // {aa, " lda #$12", "{LDA/imm (lsb $0012)}", "a912"}, - // {aa, " lda $12", "{LDA/zp $0012}", "a512"}, - // {aa, " lda $12,x", "{LDA/zpX $0012}", "b512"}, - // {aa, " lda $1234", "{LDA/abs $1234}", "ad3412"}, - // {aa, " lda $1234,x", "{LDA/absX $1234}", "bd3412"}, - // {aa, " lda ($12),y", "{LDA/indY $0012}", "b112"}, - // {aa, " lda ($12,x)", "{LDA/indX $0012}", "a112"}, - // {aa, " ldx $12,y", "{LDX/zpY $0012}", "b612"}, + {aa, " jmp $1234", "{jmp/abs $1234}", "4c3412"}, + {aa, " jmp ($1234)", "{jmp/ind $1234}", "6c3412"}, + {aa, " lda #$12", "{lda/imm (lsb $0012)}", "a912"}, + {aa, " lda $12", "{lda/zp $0012}", "a512"}, + {aa, " lda $12,x", "{lda/zpx $0012}", "b512"}, + {aa, " lda $1234", "{lda/abs $1234}", "ad3412"}, + {aa, " lda $1234,x", "{lda/absx $1234}", "bd3412"}, + {aa, " lda ($12),y", "{lda/indy $0012}", "b112"}, + {aa, " lda ($12,x)", "{lda/indx $0012}", "a112"}, + {aa, " ldx $12,y", "{ldx/zpy $0012}", "b612"}, // {aa, " org $D000", "{org $d000}", ""}, - // {aa, " rol $12", "{ROL/zp $0012}", "2612"}, - // {aa, " rol $1234", "{ROL/abs $1234}", "2e3412"}, - // {aa, " rol a", "{ROL/a}", "2a"}, - // {aa, " sta $1234,y", "{STA/absY $1234}", "993412"}, - // {aa, "; Comment", "{-}", ""}, - // {aa, "Label", "{- 'Label'}", ""}, + {aa, " rol $12", "{rol/zp $0012}", "2612"}, + {aa, " rol $1234", "{rol/abs $1234}", "2e3412"}, + {aa, " rol a", "{rol}", "2a"}, + {aa, " sta $1234,y", "{sta/absy $1234}", "993412"}, + {aa, "; Comment", "{-}", ""}, + {aa, "Label", "{- 'Label'}", ""}, // {aa, ` include "FILE.NAME"`, "{inc 'FILE.NAME'}", ""}, // {aa, ` title "Title here"`, "{-}", ""}, // {ss, " .TA *-1234", "{target (- * $04d2)}", ""}, @@ -70,34 +70,32 @@ func TestSimpleCommonFunctions(t *testing.T) { {mm, " HEX 00,01,FF,AB", "{data/b}", "0001ffab"}, {mm, " HEX 0001FFAB", "{data/b}", "0001ffab"}, {mm, " INCW $42;$43", `{call INCW {"$42", "$43"}}`, ""}, - {mm, " JMP $1234", "{JMP $1234}", "4c3412"}, - {mm, " JMP ($1234)", "{JMP $1234}", "6c3412"}, - {mm, " LDA #$12", "{LDA (lsb $0012)}", "a912"}, - {mm, " LDA #$1234", "{LDA (lsb $1234)}", "a934"}, - {mm, " LDA #/$1234", "{LDA (msb $1234)}", "a912"}, - {mm, " LDA #<$1234", "{LDA (lsb $1234)}", "a934"}, - {mm, " LDA #>$1234", "{LDA (msb $1234)}", "a912"}, - {mm, " LDA $12", "{LDA $0012}", "a512"}, - {mm, " LDA $12", "{LDA $0012}", "a512"}, - {mm, " LDA $12,X", "{LDA $0012}", "b512"}, - {mm, " LDA $1234", "{LDA $1234}", "ad3412"}, - {mm, " LDA $1234", "{LDA $1234}", "ad3412"}, - {mm, " LDA $1234,X", "{LDA $1234}", "bd3412"}, - {mm, " LDA ($12),Y", "{LDA $0012}", "b112"}, - {mm, " LDA ($12,X)", "{LDA $0012}", "a112"}, - {mm, " LDA: $12", "{LDA $0012}", "ad1200"}, - {mm, " LDA@ $12", "{LDA $0012}", "ad1200"}, - {mm, " LDAX $12", "{LDA $0012}", "ad1200"}, - {mm, " LDX $12,Y", "{LDX $0012}", "b612"}, + {mm, " JMP $1234", "{JMP/abs $1234}", "4c3412"}, + {mm, " JMP ($1234)", "{JMP/ind $1234}", "6c3412"}, + {mm, " LDA #$12", "{LDA/imm (lsb $0012)}", "a912"}, + {mm, " LDA #$1234", "{LDA/imm (lsb $1234)}", "a934"}, + {mm, " LDA #/$1234", "{LDA/imm (msb $1234)}", "a912"}, + {mm, " LDA #<$1234", "{LDA/imm (lsb $1234)}", "a934"}, + {mm, " LDA #>$1234", "{LDA/imm (msb $1234)}", "a912"}, + {mm, " LDA $12", "{LDA/zp $0012}", "a512"}, + {mm, " LDA $12,X", "{LDA/zpx $0012}", "b512"}, + {mm, " LDA $1234", "{LDA/abs $1234}", "ad3412"}, + {mm, " LDA $1234,X", "{LDA/absx $1234}", "bd3412"}, + {mm, " LDA ($12),Y", "{LDA/indy $0012}", "b112"}, + {mm, " LDA ($12,X)", "{LDA/indx $0012}", "a112"}, + {mm, " LDA: $12", "{LDA/abs $0012}", "ad1200"}, + {mm, " LDA@ $12", "{LDA/abs $0012}", "ad1200"}, + {mm, " LDAX $12", "{LDA/abs $0012}", "ad1200"}, + {mm, " LDX $12,Y", "{LDX/zpy $0012}", "b612"}, {mm, " ORG $D000", "{org $d000}", ""}, {mm, " PMC M1($42", `{call M1 {"$42"}}`, ""}, {mm, " PMC M1-$42", `{call M1 {"$42"}}`, ""}, {mm, " PUT !FILE.NAME", "{inc 'FILE.NAME'}", ""}, - {mm, " ROL $12", "{ROL $0012}", "2612"}, - {mm, " ROL $1234", "{ROL $1234}", "2e3412"}, + {mm, " ROL $12", "{ROL/zp $0012}", "2612"}, + {mm, " ROL $1234", "{ROL/abs $1234}", "2e3412"}, {mm, " ROL", "{ROL}", "2a"}, {mm, " SAV OUTFILE", "{-}", ""}, - {mm, " STA $1234,Y", "{STA $1234}", "993412"}, + {mm, " STA $1234,Y", "{STA/absy $1234}", "993412"}, {mm, "* Comment", "{-}", ""}, {mm, "ABC = $800", "{= 'ABC' $0800}", ""}, {mm, "L1 = 'A.2", "{= 'L1' (| $0041 $0002)}", ""}, @@ -183,24 +181,24 @@ func TestSimpleCommonFunctions(t *testing.T) { {ss, " BEQ $2343", "{BEQ $2343}", "f0fc"}, {ss, " BEQ $2345", "{BEQ $2345}", "f0fe"}, {ss, " BEQ $2347", "{BEQ $2347}", "f000"}, - {ss, " CMP #';'+1", "{CMP (lsb (+ $003b $0001))}", "c93c"}, - {ss, " JMP $1234", "{JMP $1234}", "4c3412"}, - {ss, " JMP ($1234)", "{JMP $1234}", "6c3412"}, - {ss, " LDA #$12", "{LDA (lsb $0012)}", "a912"}, - {ss, " LDA $12", "{LDA $0012}", "a512"}, - {ss, " LDA $12,X", "{LDA $0012}", "b512"}, - {ss, " LDA $1234", "{LDA $1234}", "ad3412"}, - {ss, " LDA $1234,X", "{LDA $1234}", "bd3412"}, - {ss, " LDA ($12),Y", "{LDA $0012}", "b112"}, - {ss, " LDA ($12,X)", "{LDA $0012}", "a112"}, - {ss, " LDX #']+$80", "{LDX (lsb (+ $005d $0080))}", "a2dd"}, - {ss, " LDX $12,Y", "{LDX $0012}", "b612"}, + {ss, " CMP #';'+1", "{CMP/imm (lsb (+ $003b $0001))}", "c93c"}, + {ss, " JMP $1234", "{JMP/abs $1234}", "4c3412"}, + {ss, " JMP ($1234)", "{JMP/ind $1234}", "6c3412"}, + {ss, " LDA #$12", "{LDA/imm (lsb $0012)}", "a912"}, + {ss, " LDA $12", "{LDA/zp $0012}", "a512"}, + {ss, " LDA $12,X", "{LDA/zpx $0012}", "b512"}, + {ss, " LDA $1234", "{LDA/abs $1234}", "ad3412"}, + {ss, " LDA $1234,X", "{LDA/absx $1234}", "bd3412"}, + {ss, " LDA ($12),Y", "{LDA/indy $0012}", "b112"}, + {ss, " LDA ($12,X)", "{LDA/indx $0012}", "a112"}, + {ss, " LDX #']+$80", "{LDX/imm (lsb (+ $005d $0080))}", "a2dd"}, + {ss, " LDX $12,Y", "{LDX/zpy $0012}", "b612"}, {ss, " ROL Comment after two spaces", "{ROL}", "2a"}, {ss, " ROL X", "{ROL}", "2a"}, // two spaces = comment - {ss, " ROL $12", "{ROL $0012}", "2612"}, - {ss, " ROL $1234", "{ROL $1234}", "2e3412"}, + {ss, " ROL $12", "{ROL/zp $0012}", "2612"}, + {ss, " ROL $1234", "{ROL/abs $1234}", "2e3412"}, {ss, " ROL", "{ROL}", "2a"}, - {ss, " STA $1234,Y", "{STA $1234}", "993412"}, + {ss, " STA $1234,Y", "{STA/absy $1234}", "993412"}, {ss, "* Comment", "{-}", ""}, {ss, "A.B .EQ *-C.D", "{= 'A.B' (- * C.D)}", ""}, {ss, "Label", "{- 'Label'}", ""}, @@ -241,6 +239,10 @@ func TestSimpleCommonFunctions(t *testing.T) { t.Errorf(`%d. %s.ParseInstr("%s") => error: %s`, i, tt.f, tt.i, err) continue } + if in.Line == nil { + t.Errorf("%d. %s: Got nil in.Line on input %q", i, tt.f, tt.i) + continue + } if in.Line.Parse == nil { t.Errorf("Got empty in.Line.Parse on input '%s'", tt.i) } @@ -279,9 +281,9 @@ func TestSimpleCommonFunctions(t *testing.T) { } func TestSimpleErrors(t *testing.T) { - ss := scma.New(opcodes.FlavorSweet16) - aa := as65.New(opcodes.FlavorSweet16) - mm := merlin.New(opcodes.FlavorSweet16) + ss := scma.New(opcodes.SetSweet16) + aa := as65.New(opcodes.SetSweet16) + mm := merlin.New(opcodes.SetSweet16) tests := []struct { f flavors.F // assembler flavor diff --git a/asm/inst/instruction.go b/asm/inst/instruction.go index 10e3555..258f722 100644 --- a/asm/inst/instruction.go +++ b/asm/inst/instruction.go @@ -73,6 +73,8 @@ type I struct { Line *lines.Line // Line object for this line Addr uint16 // Current memory address Var Variant // Variant of instruction type + + ModeStr string // Mode description, for debug printing } func (i I) TypeString() string { @@ -125,6 +127,9 @@ func (i I) TypeString() string { case TypeSetting: return "set" case TypeOp: + if i.ModeStr != "" { + return i.Command + "/" + i.ModeStr + } return i.Command } return "?" diff --git a/opcodes/opcodes.go b/opcodes/opcodes.go index 3f0a211..a163660 100644 --- a/opcodes/opcodes.go +++ b/opcodes/opcodes.go @@ -273,14 +273,14 @@ type OpSummary struct { Ops []OpInfo } -type Flavor uint16 +type Set uint16 const ( - FlavorUnknown Flavor = iota - FlavorSweet16 + SetUnknown Set = iota + SetSweet16 ) -func ByName(flavors Flavor) map[string]OpSummary { +func ByName(sets Set) map[string]OpSummary { m := make(map[string]OpSummary) for b, oc := range Opcodes { info := OpInfo{oc.Mode, ModeLengths[oc.Mode], b}