mirror of
https://github.com/zellyn/go6502.git
synced 2025-04-14 02:36:58 +00:00
merlin: simple tests passing, only macros remain
This commit is contained in:
parent
a31ee8b1d1
commit
65c391cc46
@ -10,7 +10,7 @@ import (
|
||||
|
||||
// DecodeOp contains the common code that decodes an Opcode, once we
|
||||
// have fully parsed it.
|
||||
func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect bool, xy rune) (inst.I, error) {
|
||||
func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect bool, xy rune, forceWide bool) (inst.I, error) {
|
||||
i := inst.I{}
|
||||
ex := in.Exprs[0]
|
||||
|
||||
@ -20,7 +20,10 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
case 'x':
|
||||
op, ok := summary.OpForMode(opcodes.MODE_INDIRECT_X)
|
||||
if !ok {
|
||||
return i, fmt.Errorf("%s doesn't support indexed indirect (addr,X) mode", in.Command)
|
||||
return i, in.Errorf("%s doesn't support indexed indirect (addr,X) mode", in.Command)
|
||||
}
|
||||
if forceWide {
|
||||
return i, in.Errorf("%s (addr,X) doesn't have a wide variant", in.Command)
|
||||
}
|
||||
in.Op = op.Byte
|
||||
in.WidthKnown = true
|
||||
@ -31,7 +34,10 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
case 'y':
|
||||
op, ok := summary.OpForMode(opcodes.MODE_INDIRECT_Y)
|
||||
if !ok {
|
||||
return i, fmt.Errorf("%s doesn't support indirect indexed (addr),Y mode", in.Command)
|
||||
return i, in.Errorf("%s doesn't support indirect indexed (addr),Y mode", in.Command)
|
||||
}
|
||||
if forceWide {
|
||||
return i, fmt.Errorf("%s (addr),Y doesn't have a wide variant", in.Command)
|
||||
}
|
||||
in.WidthKnown = true
|
||||
in.MinWidth = 2
|
||||
@ -42,7 +48,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
default:
|
||||
op, ok := summary.OpForMode(opcodes.MODE_INDIRECT)
|
||||
if !ok {
|
||||
return i, fmt.Errorf("%s doesn't support indirect (addr) mode", in.Command)
|
||||
return i, in.Errorf("%s doesn't support indirect (addr) mode", in.Command)
|
||||
}
|
||||
in.Op = op.Byte
|
||||
in.WidthKnown = true
|
||||
@ -59,6 +65,10 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("opcode error: %s has no MODE_RELATIVE opcode", in.Command))
|
||||
}
|
||||
if forceWide {
|
||||
return i, fmt.Errorf("%s doesn't have a wide variant", in.Command)
|
||||
}
|
||||
|
||||
in.Op = op.Byte
|
||||
in.WidthKnown = true
|
||||
in.MinWidth = 2
|
||||
@ -68,7 +78,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
}
|
||||
|
||||
// No ,X or ,Y, and width is forced to 1-byte: immediate mode.
|
||||
if xy == '-' && ex.Width() == 1 && summary.AnyModes(opcodes.MODE_IMMEDIATE) {
|
||||
if xy == '-' && ex.Width() == 1 && summary.AnyModes(opcodes.MODE_IMMEDIATE) && !forceWide {
|
||||
op, ok := summary.OpForMode(opcodes.MODE_IMMEDIATE)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("opcode error: %s has no MODE_IMMEDIATE opcode", in.Command))
|
||||
@ -99,7 +109,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
opZp, zpOk := summary.OpForMode(zp)
|
||||
|
||||
if !summary.AnyModes(zp | wide) {
|
||||
return i, fmt.Errorf("%s opcode doesn't support %s or %s modes.", zpS, wideS)
|
||||
return i, in.Errorf("%s opcode doesn't support %s or %s modes.", zpS, wideS)
|
||||
}
|
||||
|
||||
if !summary.AnyModes(zp) {
|
||||
@ -117,6 +127,9 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
if !zpOk {
|
||||
panic(fmt.Sprintf("opcode error: %s has no %s opcode", in.Command, zpS))
|
||||
}
|
||||
if forceWide {
|
||||
return i, fmt.Errorf("%s doesn't have a wide variant", in.Command)
|
||||
}
|
||||
in.Op = opZp.Byte
|
||||
in.WidthKnown = true
|
||||
in.MinWidth = 2
|
||||
@ -125,6 +138,15 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
return in, nil
|
||||
}
|
||||
|
||||
if forceWide {
|
||||
in.Op = opWide.Byte
|
||||
in.WidthKnown = true
|
||||
in.MinWidth = 3
|
||||
in.MaxWidth = 3
|
||||
in.Mode = wide
|
||||
return in, nil
|
||||
}
|
||||
|
||||
// Okay, we don't know whether it's wide or narrow: store enough info for either.
|
||||
if !zpOk {
|
||||
panic(fmt.Sprintf("opcode error: %s has no %s opcode", in.Command, zpS))
|
||||
|
@ -36,6 +36,7 @@ func New() *Merlin {
|
||||
m.CharChars = "'"
|
||||
m.InvCharChars = `"`
|
||||
m.MacroArgSep = ";"
|
||||
m.SuffixForWide = true
|
||||
|
||||
m.Directives = map[string]oldschool.DirectiveInfo{
|
||||
"ORG": {inst.TypeOrg, m.ParseAddress, 0},
|
||||
|
@ -20,7 +20,7 @@ const Digits = "0123456789"
|
||||
const binarydigits = "01"
|
||||
const hexdigits = Digits + "abcdefABCDEF"
|
||||
const Whitespace = " \t"
|
||||
const cmdChars = Letters + Digits + ".>_"
|
||||
const cmdChars = Letters + Digits + ".<>_:@"
|
||||
const fileChars = Letters + Digits + "."
|
||||
|
||||
type DirectiveInfo struct {
|
||||
@ -50,6 +50,7 @@ type Base struct {
|
||||
HexCommas Requiredness
|
||||
SpacesForComment int // this many spaces after command means it's the comment field
|
||||
StringEndOptional bool // can omit closing delimeter from string args?
|
||||
SuffixForWide bool // is eg. "LDA:" a force-wide on "LDA"? (Merlin)
|
||||
CommentChar rune
|
||||
BinaryChar rune
|
||||
MsbChars string
|
||||
@ -166,7 +167,17 @@ func (a *Base) ParseCmd(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
|
||||
if summary, ok := opcodes.ByName[in.Command]; ok {
|
||||
in.Type = inst.TypeOp
|
||||
return a.ParseOpArgs(in, lp, summary)
|
||||
return a.ParseOpArgs(in, lp, summary, false)
|
||||
}
|
||||
|
||||
// Merlin lets you say "LDA:" or "LDA@" or "LDAZ" to force non-zero-page.
|
||||
if a.SuffixForWide {
|
||||
prefix := in.Command[:len(in.Command)-1]
|
||||
if summary, ok := opcodes.ByName[prefix]; ok {
|
||||
in.Command = prefix
|
||||
in.Type = inst.TypeOp
|
||||
return a.ParseOpArgs(in, lp, summary, true)
|
||||
}
|
||||
}
|
||||
|
||||
return inst.I{}, in.Errorf(`unknown command/instruction: "%s"`, in.Command)
|
||||
@ -229,9 +240,9 @@ func (a *Base) ParseQuoted(in inst.I, lp *lines.Parse) (string, error) {
|
||||
return strings.Replace(s, `""`, `"`, -1), nil
|
||||
}
|
||||
|
||||
// ParseOpArgs parses the arguments to an assembly op. We expect to be looking at the first
|
||||
// non-op character (probably whitespace)
|
||||
func (a *Base) ParseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary) (inst.I, error) {
|
||||
// ParseOpArgs parses the arguments to an assembly op. We expect to be
|
||||
// looking at the first non-op character (probably whitespace)
|
||||
func (a *Base) ParseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary, forceWide bool) (inst.I, error) {
|
||||
i := inst.I{}
|
||||
|
||||
// MODE_IMPLIED: we don't really care what comes next: it's a comment.
|
||||
@ -338,7 +349,7 @@ func (a *Base) ParseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary
|
||||
}
|
||||
}
|
||||
|
||||
return common.DecodeOp(a, in, summary, indirect, xy)
|
||||
return common.DecodeOp(a, in, summary, indirect, xy, forceWide)
|
||||
}
|
||||
|
||||
func (a *Base) ParseAddress(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
|
@ -49,6 +49,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
// {aa, ` include "FILE.NAME"`, "{inc 'FILE.NAME'}", ""},
|
||||
// {aa, ` title "Title here"`, "{-}", ""},
|
||||
// {ss, " .TA *-1234", "{target (- * $04d2)}", ""},
|
||||
{mm, " <<<", `{endm}`, ""},
|
||||
{mm, " >>> M1,$42 ;$43", `{call M1 {"$42"}}`, ""},
|
||||
{mm, " >>> M1.$42", `{call M1 {"$42"}}`, ""},
|
||||
{mm, " >>> M1/$42;$43", `{call M1 {"$42", "$43"}}`, ""},
|
||||
@ -61,6 +62,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
{mm, " DFB $12,$34,$1234", "{data/b $0012,$0034,$1234}", "123434"},
|
||||
{mm, " DFB $34,100,$81A2-$77C4,%1011,>$81A2-$77C4", "{data/b $0034,$0064,(- $81a2 $77c4),$000b,(msb (- $81a2 $77c4))}", "3464de0b09"},
|
||||
{mm, " DSK OUTFILE", "{-}", ""},
|
||||
{mm, " EOM", `{endm}`, ""},
|
||||
{mm, " HEX 00,01,FF,AB", "{data/b}", "0001ffab"},
|
||||
{mm, " HEX 0001FFAB", "{data/b}", "0001ffab"},
|
||||
{mm, " INCW $42;$43", `{call INCW {"$42", "$43"}}`, ""},
|
||||
@ -79,9 +81,9 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
{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/zp $0012}", "ad1200"},
|
||||
{mm, " LDA@ $12", "{LDA/zp $0012}", "ad1200"},
|
||||
{mm, " LDAX $12", "{LDA/zp $0012}", "ad1200"},
|
||||
{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"}}`, ""},
|
||||
@ -107,6 +109,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
{mm, "Label", "{- 'Label'}", ""},
|
||||
{mm, "Label;Comment", "{- 'Label'}", ""},
|
||||
{mm, "MacroName MAC", `{macro "MacroName"}`, ""},
|
||||
{mm, "MacroName MAC", `{macro "MacroName"}`, ""},
|
||||
{mm, ` ASC !ABC!`, "{data/b}", "c1c2c3"},
|
||||
{mm, ` ASC "ABC"`, "{data/b}", "c1c2c3"},
|
||||
{mm, ` ASC #ABC#`, "{data/b}", "c1c2c3"},
|
||||
|
Loading…
x
Reference in New Issue
Block a user