mirror of
https://github.com/zellyn/go6502.git
synced 2025-02-12 04:30:30 +00:00
wip: merlin assembler
This commit is contained in:
parent
2a9c4df2af
commit
1754dcf7a3
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/zellyn/go6502/asm"
|
"github.com/zellyn/go6502/asm"
|
||||||
"github.com/zellyn/go6502/asm/flavors"
|
"github.com/zellyn/go6502/asm/flavors"
|
||||||
|
"github.com/zellyn/go6502/asm/flavors/merlin"
|
||||||
"github.com/zellyn/go6502/asm/flavors/redbook"
|
"github.com/zellyn/go6502/asm/flavors/redbook"
|
||||||
"github.com/zellyn/go6502/asm/flavors/scma"
|
"github.com/zellyn/go6502/asm/flavors/scma"
|
||||||
"github.com/zellyn/go6502/asm/ihex"
|
"github.com/zellyn/go6502/asm/ihex"
|
||||||
@ -19,6 +20,7 @@ var flavor string
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flavorsByName = map[string]flavors.F{
|
flavorsByName = map[string]flavors.F{
|
||||||
|
"merlin": merlin.New(),
|
||||||
"scma": scma.New(),
|
"scma": scma.New(),
|
||||||
"redbooka": redbook.NewRedbookA(),
|
"redbooka": redbook.NewRedbookA(),
|
||||||
"redbookb": redbook.NewRedbookB(),
|
"redbookb": redbook.NewRedbookB(),
|
||||||
@ -79,6 +81,7 @@ func main() {
|
|||||||
fmt.Fprintf(os.Stderr, "Error trying to determine prefix length for file '%s'", *infile, err)
|
fmt.Fprintf(os.Stderr, "Error trying to determine prefix length for file '%s'", *infile, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "Prefix guessed to be %d\n", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.AssembleWithPrefix(*infile, p); err != nil {
|
if err := a.AssembleWithPrefix(*infile, p); err != nil {
|
||||||
|
@ -2,8 +2,11 @@ package merlin
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/zellyn/go6502/asm/context"
|
"github.com/zellyn/go6502/asm/expr"
|
||||||
|
"github.com/zellyn/go6502/asm/flavors/oldschool"
|
||||||
"github.com/zellyn/go6502/asm/inst"
|
"github.com/zellyn/go6502/asm/inst"
|
||||||
"github.com/zellyn/go6502/asm/lines"
|
"github.com/zellyn/go6502/asm/lines"
|
||||||
)
|
)
|
||||||
@ -11,41 +14,140 @@ import (
|
|||||||
// Merlin implements the Merlin-compatible assembler flavor.
|
// Merlin implements the Merlin-compatible assembler flavor.
|
||||||
// See http://en.wikipedia.org/wiki/Merlin_(assembler) and
|
// See http://en.wikipedia.org/wiki/Merlin_(assembler) and
|
||||||
// http://www.apple-iigs.info/doc/fichiers/merlin816.pdf
|
// http://www.apple-iigs.info/doc/fichiers/merlin816.pdf
|
||||||
|
|
||||||
type Merlin struct {
|
type Merlin struct {
|
||||||
context.SimpleContext
|
oldschool.Base
|
||||||
context.LabelerBase
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const whitespace = " \t"
|
||||||
|
|
||||||
func New() *Merlin {
|
func New() *Merlin {
|
||||||
return &Merlin{}
|
m := &Merlin{}
|
||||||
|
m.LabelChars = oldschool.Letters + oldschool.Digits + ":"
|
||||||
|
m.LabelColons = oldschool.ReqDisallowed
|
||||||
|
m.ExplicitARegister = oldschool.ReqOptional
|
||||||
|
m.StringEndOptional = false
|
||||||
|
m.CommentChar = ';'
|
||||||
|
m.BinaryChar = '%'
|
||||||
|
m.LsbChars = "<"
|
||||||
|
m.MsbChars = ">/"
|
||||||
|
m.ImmediateChars = "#"
|
||||||
|
m.HexCommas = oldschool.ReqOptional
|
||||||
|
|
||||||
|
m.Directives = map[string]oldschool.DirectiveInfo{
|
||||||
|
"ORG": {inst.TypeOrg, m.ParseAddress, 0},
|
||||||
|
"OBJ": {inst.TypeNone, nil, 0},
|
||||||
|
"ENDASM": {inst.TypeEnd, m.ParseNoArgDir, 0},
|
||||||
|
"=": {inst.TypeEqu, m.ParseEquate, inst.EquNormal},
|
||||||
|
"HEX": {inst.TypeData, m.ParseHexString, inst.DataBytes},
|
||||||
|
"DFB": {inst.TypeData, m.ParseData, inst.DataBytes},
|
||||||
|
"DA": {inst.TypeData, m.ParseData, inst.DataWordsLe},
|
||||||
|
"DDB": {inst.TypeData, m.ParseData, inst.DataWordsBe},
|
||||||
|
"ASC": {inst.TypeData, m.ParseAscii, inst.DataAscii},
|
||||||
|
"DCI": {inst.TypeData, m.ParseAscii, inst.DataAsciiFlip},
|
||||||
|
".DO": {inst.TypeIfdef, m.ParseDo, 0},
|
||||||
|
".ELSE": {inst.TypeIfdefElse, m.ParseNoArgDir, 0},
|
||||||
|
".FIN": {inst.TypeIfdefEnd, m.ParseNoArgDir, 0},
|
||||||
|
".MA": {inst.TypeMacroStart, m.ParseMacroStart, 0},
|
||||||
|
".EM": {inst.TypeMacroEnd, m.ParseNoArgDir, 0},
|
||||||
|
".US": {inst.TypeNone, m.ParseNotImplemented, 0},
|
||||||
|
"PAGE": {inst.TypeNone, nil, 0}, // New page
|
||||||
|
"TTL": {inst.TypeNone, nil, 0}, // Title
|
||||||
|
"SAV": {inst.TypeNone, nil, 0}, // Save
|
||||||
|
"DSK": {inst.TypeNone, nil, 0}, // Assemble to disk
|
||||||
|
"PUT": {inst.TypeInclude, m.ParseInclude, 0},
|
||||||
|
"USE": {inst.TypeInclude, m.ParseInclude, 0},
|
||||||
|
}
|
||||||
|
m.Operators = map[string]expr.Operator{
|
||||||
|
"*": expr.OpMul,
|
||||||
|
"/": expr.OpDiv,
|
||||||
|
"+": expr.OpPlus,
|
||||||
|
"-": expr.OpMinus,
|
||||||
|
"<": expr.OpLt,
|
||||||
|
">": expr.OpGt,
|
||||||
|
"=": expr.OpEq,
|
||||||
|
}
|
||||||
|
|
||||||
|
m.OnOff = map[string]bool{
|
||||||
|
"LST": true, // Display listing: not used
|
||||||
|
"XC": false, // Extended commands: not implemented yet
|
||||||
|
"EXP": false, // How to print macro calls
|
||||||
|
"LSTDO": false, // List conditional code?
|
||||||
|
"TR": false, // truncate listing to 3 bytes?
|
||||||
|
"CYC": false, // print cycle times?
|
||||||
|
}
|
||||||
|
|
||||||
|
m.SetAsciiVariation = func(in *inst.I, lp *lines.Parse) {
|
||||||
|
if in.Command != "ASC" && in.Command != "DCI" {
|
||||||
|
panic(fmt.Sprintf("Unimplemented/unknown ascii directive: '%s'", in.Command))
|
||||||
|
}
|
||||||
|
invert := lp.Peek() < '\''
|
||||||
|
invertLast := in.Command == "DCI"
|
||||||
|
switch {
|
||||||
|
case !invert && !invertLast:
|
||||||
|
in.Var = inst.DataAscii
|
||||||
|
case !invert && invertLast:
|
||||||
|
in.Var = inst.DataAsciiFlip
|
||||||
|
case invert && !invertLast:
|
||||||
|
in.Var = inst.DataAsciiHi
|
||||||
|
case invert && invertLast:
|
||||||
|
in.Var = inst.DataAsciiHiFlip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse an entire instruction, or return an appropriate error.
|
func (m *Merlin) Zero() (uint16, error) {
|
||||||
func (a *Merlin) ParseInstr(line lines.Line) (inst.I, error) {
|
|
||||||
return inst.I{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Merlin) Zero() (uint16, error) {
|
|
||||||
return 0, errors.New("Division by zero.")
|
return 0, errors.New("Division by zero.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Merlin) DefaultOrigin() (uint16, error) {
|
func (m *Merlin) DefaultOrigin() (uint16, error) {
|
||||||
return 0x8000, nil
|
return 0x8000, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Merlin) SetWidthsOnFirstPass() bool {
|
func (m *Merlin) SetWidthsOnFirstPass() bool {
|
||||||
panic("don't know yet")
|
// TODO(zellyn): figure this out
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Merlin) ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error) {
|
func (m *Merlin) ParseInclude(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||||
|
lp.IgnoreRun(whitespace)
|
||||||
|
lp.AcceptUntil(";")
|
||||||
|
filename := strings.TrimSpace(lp.Emit())
|
||||||
|
prefix := "T."
|
||||||
|
if len(filename) > 0 && filename[0] < '@' {
|
||||||
|
prefix = ""
|
||||||
|
filename = strings.TrimSpace(filename[1:])
|
||||||
|
}
|
||||||
|
if filename == "" {
|
||||||
|
return inst.I{}, in.Errorf("%s expects filename", in.Command)
|
||||||
|
}
|
||||||
|
in.TextArg = prefix + filename
|
||||||
|
in.WidthKnown = true
|
||||||
|
in.MinWidth = 0
|
||||||
|
in.MaxWidth = 0
|
||||||
|
in.Final = true
|
||||||
|
return in, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Merlin) ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error) {
|
||||||
panic("Merlin.ReplaceMacroArgs not implemented yet.")
|
panic("Merlin.ReplaceMacroArgs not implemented yet.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Merlin) IsNewParentLabel(label string) bool {
|
func (m *Merlin) IsNewParentLabel(label string) bool {
|
||||||
return label != "" && label[0] != '.'
|
return label != "" && label[0] != ':'
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Merlin) FixLabel(label string, macroCount int) (string, error) {
|
func (m *Merlin) FixLabel(label string, macroCount int) (string, error) {
|
||||||
panic("Merlin.FixLabel not implemented yet.")
|
switch {
|
||||||
|
case label == "":
|
||||||
|
return label, nil
|
||||||
|
case label[0] == ':':
|
||||||
|
if last := m.LastLabel(); last == "" {
|
||||||
|
return "", fmt.Errorf("sublabel '%s' without previous label", label)
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("%s/%s", last, label), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return label, nil
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,9 @@ import (
|
|||||||
"github.com/zellyn/go6502/opcodes"
|
"github.com/zellyn/go6502/opcodes"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
const Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"
|
||||||
const Digits = "0123456789"
|
const Digits = "0123456789"
|
||||||
|
const binarydigits = "01"
|
||||||
const hexdigits = Digits + "abcdefABCDEF"
|
const hexdigits = Digits + "abcdefABCDEF"
|
||||||
const whitespace = " \t"
|
const whitespace = " \t"
|
||||||
const cmdChars = Letters + "."
|
const cmdChars = Letters + "."
|
||||||
@ -33,9 +34,9 @@ type DirectiveInfo struct {
|
|||||||
type Requiredness int
|
type Requiredness int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ReqOptional Requiredness = iota
|
ReqDisallowed Requiredness = iota
|
||||||
|
ReqOptional
|
||||||
ReqRequired
|
ReqRequired
|
||||||
ReqDisallowed
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Base implements the S-C Macro Assembler-compatible assembler flavor.
|
// Base implements the S-C Macro Assembler-compatible assembler flavor.
|
||||||
@ -48,11 +49,16 @@ type Base struct {
|
|||||||
LabelChars string
|
LabelChars string
|
||||||
LabelColons Requiredness
|
LabelColons Requiredness
|
||||||
ExplicitARegister Requiredness
|
ExplicitARegister Requiredness
|
||||||
|
HexCommas Requiredness
|
||||||
ExtraCommenty func(string) bool
|
ExtraCommenty func(string) bool
|
||||||
SpacesForComment int // this many spaces after command means it's the comment field
|
SpacesForComment int // this many spaces after command means it's the comment field
|
||||||
StringEndOptional bool // can omit closing delimeter from string args?
|
StringEndOptional bool // can omit closing delimeter from string args?
|
||||||
SetAsciiVariation func(*inst.I, *lines.Parse)
|
SetAsciiVariation func(*inst.I, *lines.Parse)
|
||||||
CommentChar rune
|
CommentChar rune
|
||||||
|
BinaryChar rune
|
||||||
|
MsbChars string
|
||||||
|
LsbChars string
|
||||||
|
ImmediateChars string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse an entire instruction, or return an appropriate error.
|
// Parse an entire instruction, or return an appropriate error.
|
||||||
@ -107,7 +113,7 @@ func (a *Base) ParseInstr(line lines.Line) (inst.I, error) {
|
|||||||
// Ignore whitespace at the start or after the label.
|
// Ignore whitespace at the start or after the label.
|
||||||
lp.IgnoreRun(whitespace)
|
lp.IgnoreRun(whitespace)
|
||||||
|
|
||||||
if lp.Peek() == lines.Eol {
|
if lp.Peek() == lines.Eol || lp.Peek() == a.CommentChar {
|
||||||
in.Type = inst.TypeNone
|
in.Type = inst.TypeNone
|
||||||
return in, nil
|
return in, nil
|
||||||
}
|
}
|
||||||
@ -128,7 +134,7 @@ func (a *Base) ParseCmd(in inst.I, lp *lines.Parse) (inst.I, error) {
|
|||||||
if lp.Consume(">") {
|
if lp.Consume(">") {
|
||||||
return a.ParseMacroCall(in, lp)
|
return a.ParseMacroCall(in, lp)
|
||||||
}
|
}
|
||||||
if !lp.AcceptRun(cmdChars) {
|
if !lp.AcceptRun(cmdChars) && !(a.Directives["="].Func != nil && lp.Accept("=")) {
|
||||||
c := lp.Next()
|
c := lp.Next()
|
||||||
return inst.I{}, in.Errorf("expecting instruction, found '%c' (%d)", c, c)
|
return inst.I{}, in.Errorf("expecting instruction, found '%c' (%d)", c, c)
|
||||||
}
|
}
|
||||||
@ -453,17 +459,26 @@ func (a *Base) ParseEquate(in inst.I, lp *lines.Parse) (inst.I, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *Base) ParseHexString(in inst.I, lp *lines.Parse) (inst.I, error) {
|
func (a *Base) ParseHexString(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||||
lp.IgnoreRun(whitespace)
|
lp.AcceptRun(whitespace)
|
||||||
if !lp.AcceptRun(hexdigits) {
|
for {
|
||||||
return inst.I{}, in.Errorf("%s expects hex digits; got '%s'", in.Command, lp.Next())
|
lp.Ignore()
|
||||||
}
|
if !lp.AcceptRun(hexdigits) {
|
||||||
hs := lp.Emit()
|
return inst.I{}, in.Errorf("%s expects hex digits; got '%s'", in.Command, lp.Next())
|
||||||
if len(hs)%2 != 0 {
|
}
|
||||||
return inst.I{}, in.Errorf("%s expects pairs of hex digits; got %d", in.Command, len(hs))
|
hs := lp.Emit()
|
||||||
}
|
if len(hs)%2 != 0 {
|
||||||
var err error
|
return inst.I{}, in.Errorf("%s expects pairs of hex digits; got %d", in.Command, len(hs))
|
||||||
if in.Data, err = hex.DecodeString(hs); err != nil {
|
}
|
||||||
return inst.I{}, in.Errorf("%s: error decoding hex string: %s", in.Command, err)
|
data, err := hex.DecodeString(hs)
|
||||||
|
if err != nil {
|
||||||
|
return inst.I{}, in.Errorf("%s: error decoding hex string: %s", in.Command, err)
|
||||||
|
}
|
||||||
|
in.Data = append(in.Data, data...)
|
||||||
|
|
||||||
|
// Keep going if we allow commas and have one
|
||||||
|
if a.HexCommas == ReqDisallowed || !lp.Accept(",") {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return in, nil
|
return in, nil
|
||||||
}
|
}
|
||||||
@ -508,12 +523,30 @@ func (a *Base) ParseNotImplemented(in inst.I, lp *lines.Parse) (inst.I, error) {
|
|||||||
|
|
||||||
func (a *Base) ParseExpression(in inst.I, lp *lines.Parse) (*expr.E, error) {
|
func (a *Base) ParseExpression(in inst.I, lp *lines.Parse) (*expr.E, error) {
|
||||||
var outer *expr.E
|
var outer *expr.E
|
||||||
if lp.Accept("#/") {
|
if lp.AcceptRun(a.MsbChars + a.LsbChars + a.ImmediateChars) {
|
||||||
switch lp.Emit() {
|
pc := lp.Emit()
|
||||||
case "#":
|
switch len(pc) {
|
||||||
outer = &expr.E{Op: expr.OpLsb}
|
case 1:
|
||||||
case "/":
|
switch {
|
||||||
outer = &expr.E{Op: expr.OpMsb}
|
case strings.Contains(a.MsbChars, pc[:1]):
|
||||||
|
outer = &expr.E{Op: expr.OpMsb}
|
||||||
|
case strings.Contains(a.LsbChars+a.ImmediateChars, pc[:1]):
|
||||||
|
outer = &expr.E{Op: expr.OpLsb}
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
err := in.Errorf("Got strange number prefix: '%s'", pc)
|
||||||
|
switch {
|
||||||
|
case !strings.Contains(a.ImmediateChars, pc[:1]):
|
||||||
|
return &expr.E{}, err
|
||||||
|
case strings.Contains(a.MsbChars, pc[1:]):
|
||||||
|
outer = &expr.E{Op: expr.OpMsb}
|
||||||
|
case strings.Contains(a.LsbChars, pc[1:]):
|
||||||
|
outer = &expr.E{Op: expr.OpLsb}
|
||||||
|
default:
|
||||||
|
return &expr.E{}, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return &expr.E{}, in.Errorf("Expected one or two number prefixes, got '%s'", pc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,6 +603,22 @@ func (a *Base) ParseTerm(in inst.I, lp *lines.Parse) (*expr.E, error) {
|
|||||||
return top, nil
|
return top, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hex
|
||||||
|
if lp.Consume(string(a.BinaryChar)) {
|
||||||
|
if !lp.AcceptRun(binarydigits) {
|
||||||
|
c := lp.Next()
|
||||||
|
return &expr.E{}, in.Errorf("expecting binary number, found '%c' (%d)", c, c)
|
||||||
|
}
|
||||||
|
s := lp.Emit()
|
||||||
|
i, err := strconv.ParseUint(s, 2, 16)
|
||||||
|
if err != nil {
|
||||||
|
return &expr.E{}, in.Errorf("invalid binary number: %s: %s", s, err)
|
||||||
|
}
|
||||||
|
ex.Op = expr.OpLeaf
|
||||||
|
ex.Val = uint16(i)
|
||||||
|
return top, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Decimal
|
// Decimal
|
||||||
if lp.AcceptRun(Digits) {
|
if lp.AcceptRun(Digits) {
|
||||||
s := lp.Emit()
|
s := lp.Emit()
|
||||||
|
@ -34,6 +34,8 @@ func newRedbook() *RedBook {
|
|||||||
r.ExplicitARegister = oldschool.ReqRequired
|
r.ExplicitARegister = oldschool.ReqRequired
|
||||||
r.StringEndOptional = true
|
r.StringEndOptional = true
|
||||||
r.CommentChar = ';'
|
r.CommentChar = ';'
|
||||||
|
r.MsbChars = "/"
|
||||||
|
r.ImmediateChars = "#"
|
||||||
|
|
||||||
r.Directives = map[string]oldschool.DirectiveInfo{
|
r.Directives = map[string]oldschool.DirectiveInfo{
|
||||||
"ORG": {inst.TypeOrg, r.ParseAddress, 0},
|
"ORG": {inst.TypeOrg, r.ParseAddress, 0},
|
||||||
|
@ -24,6 +24,8 @@ func New() *SCMA {
|
|||||||
a.LabelColons = oldschool.ReqDisallowed
|
a.LabelColons = oldschool.ReqDisallowed
|
||||||
a.ExplicitARegister = oldschool.ReqDisallowed
|
a.ExplicitARegister = oldschool.ReqDisallowed
|
||||||
a.SpacesForComment = 2
|
a.SpacesForComment = 2
|
||||||
|
a.MsbChars = "/"
|
||||||
|
a.ImmediateChars = "#"
|
||||||
|
|
||||||
a.Directives = map[string]oldschool.DirectiveInfo{
|
a.Directives = map[string]oldschool.DirectiveInfo{
|
||||||
".IN": {inst.TypeInclude, a.ParseInclude, 0},
|
".IN": {inst.TypeInclude, a.ParseInclude, 0},
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/zellyn/go6502/asm"
|
"github.com/zellyn/go6502/asm"
|
||||||
|
"github.com/zellyn/go6502/asm/flavors/merlin"
|
||||||
"github.com/zellyn/go6502/asm/flavors/redbook"
|
"github.com/zellyn/go6502/asm/flavors/redbook"
|
||||||
"github.com/zellyn/go6502/asm/flavors/scma"
|
"github.com/zellyn/go6502/asm/flavors/scma"
|
||||||
"github.com/zellyn/go6502/asm/lines"
|
"github.com/zellyn/go6502/asm/lines"
|
||||||
@ -27,9 +28,7 @@ func TestMultiline(t *testing.T) {
|
|||||||
|
|
||||||
ss := asm.NewAssembler(scma.New(), o)
|
ss := asm.NewAssembler(scma.New(), o)
|
||||||
ra := asm.NewAssembler(redbook.NewRedbookA(), o)
|
ra := asm.NewAssembler(redbook.NewRedbookA(), o)
|
||||||
// rb := asm.NewAssembler(redbook.NewRedbookB(), o)
|
mm := asm.NewAssembler(merlin.New(), o)
|
||||||
// aa := asm.NewAssembler(as65.New(), o)
|
|
||||||
// mm := asm.NewAssembler(merlin.New(), o)
|
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
a *asm.Assembler // assembler
|
a *asm.Assembler // assembler
|
||||||
@ -54,7 +53,7 @@ func TestMultiline(t *testing.T) {
|
|||||||
}, nil, "adff00ea", nil, true},
|
}, nil, "adff00ea", nil, true},
|
||||||
|
|
||||||
// Sub-labels
|
// Sub-labels
|
||||||
{ss, "Sublabels", []string{
|
{ss, "ss:Sublabels", []string{
|
||||||
"L1 BEQ .1",
|
"L1 BEQ .1",
|
||||||
".1 NOP",
|
".1 NOP",
|
||||||
"L2 BEQ .2",
|
"L2 BEQ .2",
|
||||||
@ -62,6 +61,15 @@ func TestMultiline(t *testing.T) {
|
|||||||
".2 NOP",
|
".2 NOP",
|
||||||
}, nil, "f000eaf001eaea", nil, true},
|
}, nil, "f000eaf001eaea", nil, true},
|
||||||
|
|
||||||
|
// Sub-labels
|
||||||
|
{mm, "mm:Sublabels", []string{
|
||||||
|
"L1 BEQ :ONE",
|
||||||
|
":ONE NOP",
|
||||||
|
"L2 BEQ :TWO",
|
||||||
|
":ONE NOP",
|
||||||
|
":TWO NOP",
|
||||||
|
}, nil, "f000eaf001eaea", nil, true},
|
||||||
|
|
||||||
// Includes: one level deep
|
// Includes: one level deep
|
||||||
{ss, "Include A", []string{
|
{ss, "Include A", []string{
|
||||||
" BEQ OVER",
|
" BEQ OVER",
|
||||||
@ -228,6 +236,19 @@ func TestMultiline(t *testing.T) {
|
|||||||
" MSB ON",
|
" MSB ON",
|
||||||
" ASC 'AB'",
|
" ASC 'AB'",
|
||||||
}, nil, "c1c24142c1c2", nil, true},
|
}, nil, "c1c24142c1c2", nil, true},
|
||||||
|
|
||||||
|
// Merlin: macros, local labels
|
||||||
|
{mm, "Macros: local labels", []string{
|
||||||
|
"L1 NOP",
|
||||||
|
"M1 MAC",
|
||||||
|
" INC ]1",
|
||||||
|
" BNE L1",
|
||||||
|
"L1 NOP",
|
||||||
|
" <<<",
|
||||||
|
" >>> M1.$42",
|
||||||
|
" PMC M1($43;$44",
|
||||||
|
" M1 $44",
|
||||||
|
}, nil, "eae642d000eae643d000eae644d000ea", nil, true},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
|
@ -17,7 +17,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
|||||||
ra := redbook.NewRedbookA()
|
ra := redbook.NewRedbookA()
|
||||||
rb := redbook.NewRedbookB()
|
rb := redbook.NewRedbookB()
|
||||||
// aa := as65.New()
|
// aa := as65.New()
|
||||||
// mm := merlin.New()
|
mm := merlin.New()
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
a flavors.F // assembler flavor
|
a flavors.F // assembler flavor
|
||||||
@ -25,131 +25,187 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
|||||||
p string // printed instruction, expected
|
p string // printed instruction, expected
|
||||||
b string // bytes, expected
|
b string // bytes, expected
|
||||||
}{
|
}{
|
||||||
{ss, "* Comment", "{-}", ""},
|
// {aa, " beq $2343", "{BEQ/rel $2343}", "f0fc"},
|
||||||
{ra, "* Comment", "{-}", ""},
|
// {aa, " beq $2345", "{BEQ/rel $2345}", "f0fe"},
|
||||||
{ra, " ; Comment", "{-}", ""},
|
// {aa, " beq $2347", "{BEQ/rel $2347}", "f000"},
|
||||||
// {aa, "; Comment", "{-}", ""},
|
|
||||||
// {mm, "* Comment", "{-}", ""},
|
|
||||||
{ss, " far-out-comment", "{-}", ""},
|
|
||||||
{ss, "Label", "{- 'Label'}", ""},
|
|
||||||
{ra, "Label", "{- 'Label'}", ""},
|
|
||||||
{ra, "Label:", "{- 'Label'}", ""},
|
|
||||||
// {aa, "Label", "{- 'Label'}", ""},
|
|
||||||
// {mm, "Label", "{- 'Label'}", ""},
|
|
||||||
{ss, " .IN FILE.NAME", "{inc 'FILE.NAME'}", ""},
|
|
||||||
{ss, " .IN S.DEFS", "{inc 'S.DEFS'}", ""},
|
|
||||||
// {aa, ` include "FILE.NAME"`, "{inc 'FILE.NAME'}", ""},
|
|
||||||
// {mm, " PUT !FILE.NAME", "{inc 'FILE.NAME'}", ""},
|
|
||||||
{ss, " .TI 76,Title here", "{-}", ""},
|
|
||||||
{ra, ` SBTL Title here`, "{-}", ""},
|
|
||||||
{ra, ` TITLE Title here`, "{-}", ""},
|
|
||||||
// {aa, ` title "Title here"`, "{-}", ""},
|
|
||||||
// {mm, ` TTL "Title here"`, "{-}", ""},
|
|
||||||
{ss, " .TF OUT.BIN", "{-}", ""},
|
|
||||||
// {mm, " DSK OUTFILE", "{-}", ""},
|
|
||||||
// {mm, " SAV OUTFILE", "{-}", ""},
|
|
||||||
{ss, " .OR $D000", "{org $d000}", ""},
|
|
||||||
{ra, " ORG $D000", "{org $d000}", ""},
|
|
||||||
// {aa, " org $D000", "{org $d000}", ""},
|
|
||||||
// {mm, " ORG $D000", "{org $d000}", ""},
|
|
||||||
// {ss, " .TA *-1234", "{target (- * $04d2)}", ""},
|
|
||||||
{ss, " .DA $1234", "{data $1234}", "3412"},
|
|
||||||
// {aa, " dw $1234", "{data/wle $1234}", "3412"},
|
// {aa, " dw $1234", "{data/wle $1234}", "3412"},
|
||||||
// {mm, " DW $1234", "{data/wle $1234}", "3412"},
|
// {aa, " jmp $1234", "{JMP/abs $1234}", "4c3412"},
|
||||||
{ss, " .DA/$1234,#$1234,$1234", "{data (msb $1234),(lsb $1234),$1234}", "12343412"},
|
// {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, ` include "FILE.NAME"`, "{inc 'FILE.NAME'}", ""},
|
||||||
|
// {aa, ` title "Title here"`, "{-}", ""},
|
||||||
|
// {ss, " .TA *-1234", "{target (- * $04d2)}", ""},
|
||||||
|
{mm, " >>> M1,$42 ;$43", `{call M1 {"$42"}}`, ""},
|
||||||
|
{mm, " >>> M1.$42", `{call M1 {"$42"}}`, ""},
|
||||||
|
{mm, " >>> M1/$42;$43", `{call M1 {"$42", "$43"}}`, ""},
|
||||||
|
{mm, " BEQ $2343", "{BEQ/rel $2343}", "f0fc"},
|
||||||
|
{mm, " BEQ $2345", "{BEQ/rel $2345}", "f0fe"},
|
||||||
|
{mm, " BEQ $2347", "{BEQ/rel $2347}", "f000"},
|
||||||
|
{mm, " DA $12,$34,$1234", "{data/wle $0012,$0034,$1234}", "120034003412"},
|
||||||
|
{mm, " DDB $12,$34,$1234", "{data/wbe $0012,$0034,$1234}", "001200341234"},
|
||||||
|
{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, " DA $1234", "{data/wle $1234}", "3412"},
|
||||||
|
{mm, " HEX 00,01,FF,AB", "{data/b}", "0001ffab"},
|
||||||
|
{mm, " HEX 0001FFAB", "{data/b}", "0001ffab"},
|
||||||
|
{mm, " JMP $1234", "{JMP/abs $1234}", "4c3412"},
|
||||||
|
{mm, " JMP ($1234)", "{JMP/ind $1234}", "6c3412"},
|
||||||
|
{mm, " LDA #$12", "{LDA/imm (lsb $0012)}", "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, " 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/zp $0012}", "2612"},
|
||||||
|
{mm, " ROL $1234", "{ROL/abs $1234}", "2e3412"},
|
||||||
|
{mm, " ROL", "{ROL/a}", "2a"},
|
||||||
|
{mm, " SAV OUTFILE", "{-}", ""},
|
||||||
|
{mm, " STA $1234,Y", "{STA/absY $1234}", "993412"},
|
||||||
|
{mm, "* Comment", "{-}", ""},
|
||||||
|
{mm, "ABC = $800", "{= 'ABC' $0800}", ""},
|
||||||
|
{mm, "Label ;Comment", "{- 'Label'}", ""},
|
||||||
|
{mm, "Label", "{- 'Label'}", ""},
|
||||||
|
{mm, "Label", "{- 'Label'}", ""},
|
||||||
|
{mm, "Label;Comment", "{- 'Label'}", ""},
|
||||||
|
{mm, ` ASC !ABC!`, "{data/b}", "c1c2c3"},
|
||||||
|
{mm, ` ASC "ABC"`, "{data/b}", "c1c2c3"},
|
||||||
|
{mm, ` ASC #ABC#`, "{data/b}", "c1c2c3"},
|
||||||
|
{mm, ` ASC $ABC$`, "{data/b}", "c1c2c3"},
|
||||||
|
{mm, ` ASC %ABC%`, "{data/b}", "c1c2c3"},
|
||||||
|
{mm, ` ASC &ABC&`, "{data/b}", "c1c2c3"},
|
||||||
|
{mm, ` ASC 'ABC'`, "{data/b}", "414243"},
|
||||||
|
{mm, ` ASC (ABC(`, "{data/b}", "414243"},
|
||||||
|
{mm, ` ASC )ABC)`, "{data/b}", "414243"},
|
||||||
|
{mm, ` ASC +ABC+`, "{data/b}", "414243"},
|
||||||
|
{mm, ` ASC ?ABC?`, "{data/b}", "414243"},
|
||||||
|
{mm, ` DCI !ABC!`, "{data/b}", "c1c243"},
|
||||||
|
{mm, ` DCI "ABC"`, "{data/b}", "c1c243"},
|
||||||
|
{mm, ` DCI #ABC#`, "{data/b}", "c1c243"},
|
||||||
|
{mm, ` DCI $ABC$`, "{data/b}", "c1c243"},
|
||||||
|
{mm, ` DCI %ABC%`, "{data/b}", "c1c243"},
|
||||||
|
{mm, ` DCI &ABC&`, "{data/b}", "c1c243"},
|
||||||
|
{mm, ` DCI 'ABC'`, "{data/b}", "4142c3"},
|
||||||
|
{mm, ` DCI (ABC(`, "{data/b}", "4142c3"},
|
||||||
|
{mm, ` DCI )ABC)`, "{data/b}", "4142c3"},
|
||||||
|
{mm, ` DCI +ABC+`, "{data/b}", "4142c3"},
|
||||||
|
{mm, ` DCI ?ABC?`, "{data/b}", "4142c3"},
|
||||||
|
{mm, ` TTL "Title here"`, "{-}", ""},
|
||||||
|
{mm, " LDA #$1234", "{LDA/imm (lsb $1234)}", "a934"},
|
||||||
|
{mm, " LDA #<$1234", "{LDA/imm (lsb $1234)}", "a934"},
|
||||||
|
{mm, " LDA #>$1234", "{LDA/imm (msb $1234)}", "a912"},
|
||||||
|
{mm, " LDA #/$1234", "{LDA/imm (msb $1234)}", "a912"},
|
||||||
|
{mm, " LDA $12", "{LDA/zp $0012}", "a512"},
|
||||||
|
{mm, " LDA: $12", "{LDA/zp $0012}", "ad1200"},
|
||||||
|
{mm, " LDA@ $12", "{LDA/zp $0012}", "ad1200"},
|
||||||
|
{mm, " LDAX $12", "{LDA/zp $0012}", "ad1200"},
|
||||||
|
{mm, " LDA $1234", "{LDA/abs $1234}", "ad3412"},
|
||||||
|
|
||||||
|
{mm, "L1 = L2-L3", "{= 'L1' (- L2 L3)}", ""},
|
||||||
|
{mm, "L1 = 2*L2+$231", "{= 'L1' (+ (* $0002 L2) $0231)}", ""},
|
||||||
|
{mm, "L1 = 1234+%10111", "{= 'L1' (+ $04d2 $0017)}", ""},
|
||||||
|
{mm, "L1 = L2&$7F", "{= 'L1' (& L2 $007f)}", ""},
|
||||||
|
{mm, "L1 = *-2", "{= 'L1' (- * $0002)}", ""},
|
||||||
|
{mm, "L1 = L2.%10000000", "{= 'L1' (| L2 $0080)}", ""},
|
||||||
|
{mm, `L1 = L2!"A"`, "{= 'L1' (^ L2 $00c1)}", ""},
|
||||||
|
{mm, "L1 = L2!'A'", "{= 'L1' (^ L2 $0041)}", ""},
|
||||||
|
{mm, `L1 = "A+3`, "{= 'L1' (+ $00c1 $0003)}", ""},
|
||||||
|
{mm, "L1 = 'A.2", "{= 'L1' (| $0041 $0002)}", ""},
|
||||||
|
|
||||||
|
{ra, " ; Comment", "{-}", ""},
|
||||||
|
{ra, " DDB $12,$34,$1234", "{data/wbe $0012,$0034,$1234}", "001200341234"},
|
||||||
{ra, " DFB $12", "{data/b $0012}", "12"},
|
{ra, " DFB $12", "{data/b $0012}", "12"},
|
||||||
{ra, " DFB $12,$34,$1234", "{data/b $0012,$0034,$1234}", "123434"},
|
{ra, " DFB $12,$34,$1234", "{data/b $0012,$0034,$1234}", "123434"},
|
||||||
{ra, " DW $12,$34,$1234", "{data/wle $0012,$0034,$1234}", "120034003412"},
|
{ra, " DW $12,$34,$1234", "{data/wle $0012,$0034,$1234}", "120034003412"},
|
||||||
{ra, " DDB $12,$34,$1234", "{data/wbe $0012,$0034,$1234}", "001200341234"},
|
{ra, " LST OFF", "{set LST OFF}", ""},
|
||||||
{ss, " ROL", "{ROL/a}", "2a"},
|
{ra, " LST ON", "{set LST ON}", ""},
|
||||||
// {aa, " rol a", "{ROL/a}", "2a"},
|
{ra, " MSB OFF", "{set MSB OFF}", ""},
|
||||||
{ra, " ROL A", "{ROL/a}", "2a"},
|
{ra, " MSB ON", "{set MSB ON}", ""},
|
||||||
|
{ra, " ORG $D000", "{org $d000}", ""},
|
||||||
{ra, " ROL A", "{ROL/a}", "2a"}, // two spaces is no big deal
|
{ra, " ROL A", "{ROL/a}", "2a"}, // two spaces is no big deal
|
||||||
// {mm, " ROL", "{ROL/a}", "2a"},
|
{ra, " ROL A", "{ROL/a}", "2a"},
|
||||||
{ss, " ROL Comment after two spaces", "{ROL/a}", "2a"},
|
{ra, "* Comment", "{-}", ""},
|
||||||
{ss, " ROL X", "{ROL/a}", "2a"}, // two spaces = comment
|
{ra, "Label", "{- 'Label'}", ""},
|
||||||
{rb, " ROL", "{ROL/a}", "2a"},
|
{ra, "Label:", "{- 'Label'}", ""},
|
||||||
{rb, " ROL Comment after three spaces", "{ROL/a}", "2a"},
|
|
||||||
{rb, " ROL X", "{ROL/a}", "2a"}, // two spaces = comment
|
|
||||||
{ss, " ROL $1234", "{ROL/abs $1234}", "2e3412"},
|
|
||||||
// {aa, " rol $1234", "{ROL/abs $1234}", "2e3412"},
|
|
||||||
// {mm, " ROL $1234", "{ROL/abs $1234}", "2e3412"},
|
|
||||||
{ss, " ROL $12", "{ROL/zp $0012}", "2612"},
|
|
||||||
// {aa, " rol $12", "{ROL/zp $0012}", "2612"},
|
|
||||||
// {mm, " ROL $12", "{ROL/zp $0012}", "2612"},
|
|
||||||
{ss, " LDA #$12", "{LDA/imm (lsb $0012)}", "a912"},
|
|
||||||
// {aa, " lda #$12", "{LDA/imm (lsb $0012)}", "a912"},
|
|
||||||
// {mm, " LDA #$12", "{LDA/imm (lsb $0012)}", "a912"},
|
|
||||||
{ss, " JMP $1234", "{JMP/abs $1234}", "4c3412"},
|
|
||||||
// {aa, " jmp $1234", "{JMP/abs $1234}", "4c3412"},
|
|
||||||
// {mm, " JMP $1234", "{JMP/abs $1234}", "4c3412"},
|
|
||||||
{ss, " JMP ($1234)", "{JMP/ind $1234}", "6c3412"},
|
|
||||||
// {aa, " jmp ($1234)", "{JMP/ind $1234}", "6c3412"},
|
|
||||||
// {mm, " JMP ($1234)", "{JMP/ind $1234}", "6c3412"},
|
|
||||||
{ss, " BEQ $2345", "{BEQ/rel $2345}", "f0fe"},
|
|
||||||
// {aa, " beq $2345", "{BEQ/rel $2345}", "f0fe"},
|
|
||||||
// {mm, " BEQ $2345", "{BEQ/rel $2345}", "f0fe"},
|
|
||||||
{ss, " BEQ $2347", "{BEQ/rel $2347}", "f000"},
|
|
||||||
// {aa, " beq $2347", "{BEQ/rel $2347}", "f000"},
|
|
||||||
// {mm, " BEQ $2347", "{BEQ/rel $2347}", "f000"},
|
|
||||||
{ss, " BEQ $2343", "{BEQ/rel $2343}", "f0fc"},
|
|
||||||
// {aa, " beq $2343", "{BEQ/rel $2343}", "f0fc"},
|
|
||||||
// {mm, " BEQ $2343", "{BEQ/rel $2343}", "f0fc"},
|
|
||||||
{ss, " LDA $1234", "{LDA/abs $1234}", "ad3412"},
|
|
||||||
// {aa, " lda $1234", "{LDA/abs $1234}", "ad3412"},
|
|
||||||
// {mm, " LDA $1234", "{LDA/abs $1234}", "ad3412"},
|
|
||||||
{ss, " LDA $1234,X", "{LDA/absX $1234}", "bd3412"},
|
|
||||||
// {aa, " lda $1234,x", "{LDA/absX $1234}", "bd3412"},
|
|
||||||
// {mm, " LDA $1234,X", "{LDA/absX $1234}", "bd3412"},
|
|
||||||
{ss, " STA $1234,Y", "{STA/absY $1234}", "993412"},
|
|
||||||
// {aa, " sta $1234,y", "{STA/absY $1234}", "993412"},
|
|
||||||
// {mm, " STA $1234,Y", "{STA/absY $1234}", "993412"},
|
|
||||||
{ss, " LDA $12", "{LDA/zp $0012}", "a512"},
|
|
||||||
// {aa, " lda $12", "{LDA/zp $0012}", "a512"},
|
|
||||||
// {mm, " LDA $12", "{LDA/zp $0012}", "a512"},
|
|
||||||
{ss, " LDA $12,X", "{LDA/zpX $0012}", "b512"},
|
|
||||||
// {aa, " lda $12,x", "{LDA/zpX $0012}", "b512"},
|
|
||||||
// {mm, " LDA $12,X", "{LDA/zpX $0012}", "b512"},
|
|
||||||
{ss, " LDX $12,Y", "{LDX/zpY $0012}", "b612"},
|
|
||||||
// {aa, " ldx $12,y", "{LDX/zpY $0012}", "b612"},
|
|
||||||
// {mm, " LDX $12,Y", "{LDX/zpY $0012}", "b612"},
|
|
||||||
{ss, " LDA ($12),Y", "{LDA/indY $0012}", "b112"},
|
|
||||||
// {aa, " lda ($12),y", "{LDA/indY $0012}", "b112"},
|
|
||||||
// {mm, " LDA ($12),Y", "{LDA/indY $0012}", "b112"},
|
|
||||||
{ss, " LDA ($12,X)", "{LDA/indX $0012}", "a112"},
|
|
||||||
// {aa, " lda ($12,x)", "{LDA/indX $0012}", "a112"},
|
|
||||||
// {mm, " LDA ($12,X)", "{LDA/indX $0012}", "a112"},
|
|
||||||
{ss, ` .AS "ABC"`, "{data/b}", "414243"},
|
|
||||||
{ss, ` .AT "ABC"`, "{data/b}", "4142c3"},
|
|
||||||
{ss, ` .AS /ABC/`, "{data/b}", "414243"},
|
|
||||||
{ss, ` .AT /ABC/`, "{data/b}", "4142c3"},
|
|
||||||
{ss, ` .AS -"ABC"`, "{data/b}", "c1c2c3"},
|
|
||||||
{ss, ` .AT -"ABC"`, "{data/b}", "c1c243"},
|
|
||||||
{ss, ` .AS -dABCd`, "{data/b}", "c1c2c3"},
|
|
||||||
{ss, ` .AT -dABCd`, "{data/b}", "c1c243"},
|
|
||||||
{ra, ` ASC "ABC"`, "{data/b}", "c1c2c3"},
|
{ra, ` ASC "ABC"`, "{data/b}", "c1c2c3"},
|
||||||
{ra, ` ASC $ABC$ ;comment`, "{data/b}", "c1c2c3"},
|
{ra, ` ASC $ABC$ ;comment`, "{data/b}", "c1c2c3"},
|
||||||
{ra, ` ASC $ABC`, "{data/b}", "c1c2c3"},
|
{ra, ` ASC $ABC`, "{data/b}", "c1c2c3"},
|
||||||
{ra, ` DCI "ABC"`, "{data/b}", "4142c3"},
|
|
||||||
{ra, ` ASC -ABC-`, "{data/b}", "c1c2c3"},
|
{ra, ` ASC -ABC-`, "{data/b}", "c1c2c3"},
|
||||||
{ss, " .HS 0001ffAb", "{data/b}", "0001ffab"},
|
{ra, ` DCI "ABC"`, "{data/b}", "4142c3"},
|
||||||
{ss, "A.B .EQ *-C.D", "{= 'A.B' (- * C.D)}", ""},
|
{ra, ` SBTL Title here`, "{-}", ""},
|
||||||
|
{ra, ` TITLE Title here`, "{-}", ""},
|
||||||
|
{rb, " ROL Comment after three spaces", "{ROL/a}", "2a"},
|
||||||
|
{rb, " ROL X", "{ROL/a}", "2a"}, // two spaces = comment
|
||||||
|
{rb, " ROL", "{ROL/a}", "2a"},
|
||||||
|
{ss, " far-out-comment", "{-}", ""},
|
||||||
{ss, " .BS $8", "{block $0008}", "xxxxxxxxxxxxxxxx"},
|
{ss, " .BS $8", "{block $0008}", "xxxxxxxxxxxxxxxx"},
|
||||||
|
{ss, " .DA $1234", "{data $1234}", "3412"},
|
||||||
|
{ss, " .DA/$1234,#$1234,$1234", "{data (msb $1234),(lsb $1234),$1234}", "12343412"},
|
||||||
{ss, " .DO A<$3", "{if (< A $0003)}", ""},
|
{ss, " .DO A<$3", "{if (< A $0003)}", ""},
|
||||||
{ss, " .ELSE", "{else}", ""},
|
{ss, " .ELSE", "{else}", ""},
|
||||||
{ss, " .FIN", "{endif}", ""},
|
|
||||||
{ss, " .MA MacroName", "{macro 'MacroName'}", ""},
|
|
||||||
{ss, " .EM", "{endm}", ""},
|
{ss, " .EM", "{endm}", ""},
|
||||||
{ss, " .EN", "{end}", ""},
|
{ss, " .EN", "{end}", ""},
|
||||||
{ss, `>SAM AB,$12,"A B","A, B, "" C"`,
|
{ss, " .FIN", "{endif}", ""},
|
||||||
`{call SAM {"AB", "$12", "A B", "A, B, \" C"}}`, ""},
|
{ss, " .HS 0001FFAB", "{data/b}", "0001ffab"},
|
||||||
{ss, " LDX #']+$80", "{LDX/imm (lsb (+ $005d $0080))}", "a2dd"},
|
{ss, " .IN FILE.NAME", "{inc 'FILE.NAME'}", ""},
|
||||||
|
{ss, " .IN S.DEFS", "{inc 'S.DEFS'}", ""},
|
||||||
|
{ss, " .MA MacroName", "{macro 'MacroName'}", ""},
|
||||||
|
{ss, " .OR $D000", "{org $d000}", ""},
|
||||||
|
{ss, " .TF OUT.BIN", "{-}", ""},
|
||||||
|
{ss, " .TI 76,Title here", "{-}", ""},
|
||||||
|
{ss, " BEQ $2343", "{BEQ/rel $2343}", "f0fc"},
|
||||||
|
{ss, " BEQ $2345", "{BEQ/rel $2345}", "f0fe"},
|
||||||
|
{ss, " BEQ $2347", "{BEQ/rel $2347}", "f000"},
|
||||||
{ss, " CMP #';'+1", "{CMP/imm (lsb (+ $003b $0001))}", "c93c"},
|
{ss, " CMP #';'+1", "{CMP/imm (lsb (+ $003b $0001))}", "c93c"},
|
||||||
{ra, " LST ON", "{set LST ON}", ""},
|
{ss, " JMP $1234", "{JMP/abs $1234}", "4c3412"},
|
||||||
{ra, " LST OFF", "{set LST OFF}", ""},
|
{ss, " JMP ($1234)", "{JMP/ind $1234}", "6c3412"},
|
||||||
{ra, " MSB ON", "{set MSB ON}", ""},
|
{ss, " LDA #$12", "{LDA/imm (lsb $0012)}", "a912"},
|
||||||
{ra, " MSB OFF", "{set MSB OFF}", ""},
|
{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/a}", "2a"},
|
||||||
|
{ss, " ROL X", "{ROL/a}", "2a"}, // two spaces = comment
|
||||||
|
{ss, " ROL $12", "{ROL/zp $0012}", "2612"},
|
||||||
|
{ss, " ROL $1234", "{ROL/abs $1234}", "2e3412"},
|
||||||
|
{ss, " ROL", "{ROL/a}", "2a"},
|
||||||
|
{ss, " STA $1234,Y", "{STA/absY $1234}", "993412"},
|
||||||
|
{ss, "* Comment", "{-}", ""},
|
||||||
|
{ss, "A.B .EQ *-C.D", "{= 'A.B' (- * C.D)}", ""},
|
||||||
|
{ss, "Label", "{- 'Label'}", ""},
|
||||||
|
{ss, ` .AS "ABC"`, "{data/b}", "414243"},
|
||||||
|
{ss, ` .AS -"ABC"`, "{data/b}", "c1c2c3"},
|
||||||
|
{ss, ` .AS -DABCD`, "{data/b}", "c1c2c3"},
|
||||||
|
{ss, ` .AS /ABC/`, "{data/b}", "414243"},
|
||||||
|
{ss, ` .AT "ABC"`, "{data/b}", "4142c3"},
|
||||||
|
{ss, ` .AT -"ABC"`, "{data/b}", "c1c243"},
|
||||||
|
{ss, ` .AT -DABCD`, "{data/b}", "c1c243"},
|
||||||
|
{ss, ` .AT /ABC/`, "{data/b}", "4142c3"},
|
||||||
|
{ss, `>SAM AB,$12,"A B","A, B, "" C"`, `{call SAM {"AB", "$12", "A B", "A, B, \" C"}}`, ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(zellyn): Add tests for finalization of four SCMA directives:
|
// TODO(zellyn): Add tests for finalization of four SCMA directives:
|
||||||
@ -165,6 +221,8 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
|||||||
tt.a.SetAddr(0x2345)
|
tt.a.SetAddr(0x2345)
|
||||||
tt.a.Set("A.B", 0x6789)
|
tt.a.Set("A.B", 0x6789)
|
||||||
tt.a.Set("C.D", 0x789a)
|
tt.a.Set("C.D", 0x789a)
|
||||||
|
tt.a.Set("L2", 0x6789)
|
||||||
|
tt.a.Set("L3", 0x789a)
|
||||||
|
|
||||||
inst, err := tt.a.ParseInstr(lines.NewSimple(tt.i))
|
inst, err := tt.a.ParseInstr(lines.NewSimple(tt.i))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -176,7 +234,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
_, err = inst.Compute(tt.a, true, true)
|
_, err = inst.Compute(tt.a, true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf(`%d. %s.Compute(tt.a, true, true) => error: %s`, i, inst, err)
|
t.Errorf(`%d. %T.ParseInstr("%s"): %s.Compute(tt.a, true, true) => error: %s`, i, tt.a, tt.i, inst, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if inst.String() != tt.p {
|
if inst.String() != tt.p {
|
||||||
|
@ -43,8 +43,8 @@ const (
|
|||||||
DataWordsLe // Data: expressions, but forced to one word per, little-endian
|
DataWordsLe // Data: expressions, but forced to one word per, little-endian
|
||||||
DataWordsBe // Data: expressions, but forced to one word per, big-endian
|
DataWordsBe // Data: expressions, but forced to one word per, big-endian
|
||||||
DataAscii // Data: from ASCII strings, high bit clear
|
DataAscii // Data: from ASCII strings, high bit clear
|
||||||
DataAsciiHi // Data: from ASCII strings, high bit set
|
|
||||||
DataAsciiFlip // Data: from ASCII strings, high bit clear, except last char
|
DataAsciiFlip // Data: from ASCII strings, high bit clear, except last char
|
||||||
|
DataAsciiHi // Data: from ASCII strings, high bit set
|
||||||
DataAsciiHiFlip // Data: from ASCII strings, high bit set, except last char
|
DataAsciiHiFlip // Data: from ASCII strings, high bit set, except last char
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ func (lp *Parse) AcceptRun(valid string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (lp *Parse) AcceptUntil(until string) bool {
|
func (lp *Parse) AcceptUntil(until string) bool {
|
||||||
until += "\n"
|
until += string(Eol)
|
||||||
some := false
|
some := false
|
||||||
for strings.IndexRune(until, lp.Next()) < 0 {
|
for strings.IndexRune(until, lp.Next()) < 0 {
|
||||||
some = true
|
some = true
|
||||||
|
Loading…
x
Reference in New Issue
Block a user