mirror of
https://github.com/zellyn/go6502.git
synced 2025-02-07 02:30:38 +00:00
Tidying, getting ready to add Sweet16 opcodes
- Getting tests to pass - Adding flavors of opcodes and passing them around - Rearranging a2as flags a little
This commit is contained in:
parent
218c3b9a91
commit
07a8d64377
@ -13,6 +13,8 @@ import (
|
||||
"github.com/zellyn/go6502/asm/membuf"
|
||||
)
|
||||
|
||||
// Assembler is the basic assembler struct. It keeps track of its
|
||||
// options, the stream of instructions, and defined macros.
|
||||
type Assembler struct {
|
||||
Flavor flavors.F
|
||||
Opener lines.Opener
|
||||
@ -21,15 +23,18 @@ type Assembler struct {
|
||||
Ctx *context.SimpleContext
|
||||
}
|
||||
|
||||
// NewAssembler creates a new assembler with the given flavor and
|
||||
// file-opener.
|
||||
func NewAssembler(flavor flavors.F, opener lines.Opener) *Assembler {
|
||||
ctx := &context.SimpleContext{}
|
||||
flavor.InitContext(ctx)
|
||||
return &Assembler{
|
||||
a := &Assembler{
|
||||
Flavor: flavor,
|
||||
Opener: opener,
|
||||
Macros: make(map[string]macros.M),
|
||||
Ctx: ctx,
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
type ifdef struct {
|
||||
|
@ -13,25 +13,14 @@ import (
|
||||
"github.com/zellyn/go6502/asm/flavors/scma"
|
||||
"github.com/zellyn/go6502/asm/ihex"
|
||||
"github.com/zellyn/go6502/asm/lines"
|
||||
"github.com/zellyn/go6502/opcodes"
|
||||
)
|
||||
|
||||
var flavorsByName map[string]flavors.F
|
||||
var flavor string
|
||||
|
||||
func init() {
|
||||
flavorsByName = map[string]flavors.F{
|
||||
"merlin": merlin.New(),
|
||||
"scma": scma.New(),
|
||||
"redbooka": redbook.NewRedbookA(),
|
||||
"redbookb": redbook.NewRedbookB(),
|
||||
}
|
||||
var names []string
|
||||
for name := range flavorsByName {
|
||||
names = append(names, name)
|
||||
}
|
||||
usage := fmt.Sprintf("assembler flavor: %s", strings.Join(names, ","))
|
||||
flag.StringVar(&flavor, "flavor", "", usage)
|
||||
|
||||
var flavorNames = []string{
|
||||
"merlin",
|
||||
"scma",
|
||||
"redbooka",
|
||||
"redbookb",
|
||||
}
|
||||
|
||||
var infile = flag.String("in", "", "input file")
|
||||
@ -40,6 +29,8 @@ var listfile = flag.String("listing", "", "listing file")
|
||||
var format = flag.String("format", "binary", "output format: binary/ihex")
|
||||
var fill = flag.Uint("fillbyte", 0x00, "byte value to use when filling gaps between assmebler output regions")
|
||||
var prefix = flag.Int("prefix", -1, "length of prefix to skip past addresses and bytes, -1 to guess")
|
||||
var sweet16 = flag.Bool("sw16", false, "assemble sweet16 opcodes")
|
||||
var flavorName = flag.String("flavor", "", fmt.Sprintf("assemble flavor: %s", strings.Join(flavorNames, ",")))
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
@ -51,16 +42,6 @@ func main() {
|
||||
fmt.Fprintln(os.Stderr, "no output file specified")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if flavor == "" {
|
||||
fmt.Fprintln(os.Stderr, "no flavor specified")
|
||||
os.Exit(1)
|
||||
}
|
||||
f, ok := flavorsByName[flavor]
|
||||
if !ok {
|
||||
fmt.Fprintf(os.Stderr, "invalid flavor: '%s'\n", flavor)
|
||||
os.Exit(1)
|
||||
}
|
||||
if *format != "binary" && *format != "ihex" {
|
||||
fmt.Fprintf(os.Stderr, "format must be binary or ihex; got '%s'\n", *format)
|
||||
os.Exit(1)
|
||||
@ -70,6 +51,30 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if *flavorName == "" {
|
||||
fmt.Fprintln(os.Stderr, "no flavor specified")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var f flavors.F
|
||||
var flavor opcodes.Flavor
|
||||
if *sweet16 {
|
||||
flavor |= opcodes.FlavorSweet16
|
||||
}
|
||||
switch *flavorName {
|
||||
case "merlin":
|
||||
f = merlin.New(flavor)
|
||||
case "scma":
|
||||
f = scma.New(flavor)
|
||||
case "redbooka":
|
||||
f = redbook.NewRedbookA(flavor)
|
||||
case "redbookb":
|
||||
f = redbook.NewRedbookB(flavor)
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "invalid flavor: '%s'\n", flavor)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var o lines.OsOpener
|
||||
a := asm.NewAssembler(f, o)
|
||||
|
||||
|
@ -6,6 +6,12 @@ MD5_MONITOR=$(md5 -q monitor.rom)
|
||||
[[ $MD5_MONITOR == 'bc0163ca04c463e06f99fb029ad21b1f' ]] || (echo 'Wrong checksum for monitor.rom'; false) || exit 1
|
||||
rm -f monitor.rom monitor.lst
|
||||
|
||||
echo autostart.rom
|
||||
./a2as --in ../../../../goapple2/source/redbook/autostart.asm --out autostart.rom --flavor redbooka --listing autostart.lst --prefix=-1
|
||||
MD5_AUTOSTART=$(md5 -q autostart.rom)
|
||||
[[ $MD5_AUTOSTART == '8925b695ae0177dd3919dbea2f2f202b' ]] || (echo 'Wrong checksum for autostart.rom'; false) || exit 1
|
||||
rm -f autostart.rom autostart.lst
|
||||
|
||||
echo miniasm.rom
|
||||
./a2as --in ../../../../goapple2/source/redbook/miniasm.asm --out miniasm.rom --flavor redbooka --listing miniasm.lst --prefix=-1
|
||||
MD5_MINIASM=$(md5 -q miniasm.rom)
|
||||
|
@ -7,15 +7,20 @@ import (
|
||||
"github.com/zellyn/go6502/asm/flavors"
|
||||
"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{}
|
||||
type AS65 struct {
|
||||
OpcodesByName map[string]opcodes.OpSummary
|
||||
}
|
||||
|
||||
func New() *AS65 {
|
||||
return &AS65{}
|
||||
func New(flavors opcodes.Flavor) *AS65 {
|
||||
return &AS65{
|
||||
OpcodesByName: opcodes.ByName(flavors),
|
||||
}
|
||||
}
|
||||
|
||||
// Parse an entire instruction, or return an appropriate error.
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/zellyn/go6502/asm/flavors/oldschool"
|
||||
"github.com/zellyn/go6502/asm/inst"
|
||||
"github.com/zellyn/go6502/asm/lines"
|
||||
"github.com/zellyn/go6502/opcodes"
|
||||
)
|
||||
|
||||
// Merlin implements the Merlin-compatible assembler flavor.
|
||||
@ -21,9 +22,10 @@ type Merlin struct {
|
||||
const whitespace = " \t"
|
||||
const macroNameChars = oldschool.Letters + oldschool.Digits + "_"
|
||||
|
||||
func New() *Merlin {
|
||||
func New(flavors opcodes.Flavor) *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
|
||||
|
@ -44,6 +44,7 @@ const (
|
||||
type Base struct {
|
||||
Name string
|
||||
Directives map[string]DirectiveInfo
|
||||
OpcodesByName map[string]opcodes.OpSummary
|
||||
Operators map[string]expr.Operator
|
||||
EquateDirectives map[string]bool
|
||||
LabelChars string
|
||||
@ -239,15 +240,15 @@ func (a *Base) parseCmd(ctx context.Context, in inst.I, lp *lines.Parse, mode fl
|
||||
return a.parseSetting(ctx, in, lp)
|
||||
}
|
||||
|
||||
if summary, ok := opcodes.ByName[in.Command]; ok {
|
||||
if summary, ok := a.OpcodesByName[in.Command]; ok {
|
||||
in.Type = inst.TypeOp
|
||||
return a.parseOpArgs(ctx, in, lp, summary, false)
|
||||
}
|
||||
|
||||
// Merlin lets you say "LDA:" or "LDA@" or "LDAZ" to force non-zero-page.
|
||||
if a.SuffixForWide {
|
||||
if a.SuffixForWide && len(in.Command) == 4 {
|
||||
prefix := in.Command[:len(in.Command)-1]
|
||||
if summary, ok := opcodes.ByName[prefix]; ok {
|
||||
if summary, ok := a.OpcodesByName[prefix]; ok {
|
||||
in.Command = prefix
|
||||
in.Type = inst.TypeOp
|
||||
return a.parseOpArgs(ctx, in, lp, summary, true)
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/zellyn/go6502/asm/flavors/oldschool"
|
||||
"github.com/zellyn/go6502/asm/inst"
|
||||
"github.com/zellyn/go6502/asm/lines"
|
||||
"github.com/zellyn/go6502/opcodes"
|
||||
)
|
||||
|
||||
// RedBook implements a Redbook-listing-compatible-ish assembler flavor.
|
||||
@ -15,21 +16,22 @@ type RedBook struct {
|
||||
oldschool.Base
|
||||
}
|
||||
|
||||
func NewRedbookA() *RedBook {
|
||||
r := newRedbook("redbook-a")
|
||||
func NewRedbookA(flavors opcodes.Flavor) *RedBook {
|
||||
r := newRedbook("redbook-a", flavors)
|
||||
return r
|
||||
}
|
||||
|
||||
func NewRedbookB() *RedBook {
|
||||
r := newRedbook("redbook-b")
|
||||
func NewRedbookB(flavors opcodes.Flavor) *RedBook {
|
||||
r := newRedbook("redbook-b", flavors)
|
||||
r.ExplicitARegister = oldschool.ReqRequired
|
||||
r.SpacesForComment = 3
|
||||
return r
|
||||
}
|
||||
|
||||
func newRedbook(name string) *RedBook {
|
||||
func newRedbook(name string, flavors opcodes.Flavor) *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
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/zellyn/go6502/asm/flavors/oldschool"
|
||||
"github.com/zellyn/go6502/asm/inst"
|
||||
"github.com/zellyn/go6502/asm/lines"
|
||||
"github.com/zellyn/go6502/opcodes"
|
||||
)
|
||||
|
||||
// 40 spaces = comment column
|
||||
@ -19,9 +20,10 @@ type SCMA struct {
|
||||
oldschool.Base
|
||||
}
|
||||
|
||||
func New() *SCMA {
|
||||
func New(flavors opcodes.Flavor) *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
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/zellyn/go6502/asm/flavors/scma"
|
||||
"github.com/zellyn/go6502/asm/lines"
|
||||
"github.com/zellyn/go6502/asm/membuf"
|
||||
"github.com/zellyn/go6502/opcodes"
|
||||
)
|
||||
|
||||
// h converts from hex or panics.
|
||||
@ -29,13 +30,13 @@ func TestMultiline(t *testing.T) {
|
||||
o := lines.NewTestOpener()
|
||||
|
||||
ss := asmFactory(func() *asm.Assembler {
|
||||
return asm.NewAssembler(scma.New(), o)
|
||||
return asm.NewAssembler(scma.New(opcodes.FlavorSweet16), o)
|
||||
})
|
||||
ra := asmFactory(func() *asm.Assembler {
|
||||
return asm.NewAssembler(redbook.NewRedbookA(), o)
|
||||
return asm.NewAssembler(redbook.NewRedbookA(opcodes.FlavorSweet16), o)
|
||||
})
|
||||
mm := asmFactory(func() *asm.Assembler {
|
||||
return asm.NewAssembler(merlin.New(), o)
|
||||
return asm.NewAssembler(merlin.New(opcodes.FlavorSweet16), o)
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
|
@ -12,14 +12,15 @@ import (
|
||||
"github.com/zellyn/go6502/asm/flavors/scma"
|
||||
"github.com/zellyn/go6502/asm/inst"
|
||||
"github.com/zellyn/go6502/asm/lines"
|
||||
"github.com/zellyn/go6502/opcodes"
|
||||
)
|
||||
|
||||
func TestSimpleCommonFunctions(t *testing.T) {
|
||||
ss := scma.New()
|
||||
ra := redbook.NewRedbookA()
|
||||
rb := redbook.NewRedbookB()
|
||||
// aa := as65.New()
|
||||
mm := merlin.New()
|
||||
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)
|
||||
|
||||
tests := []struct {
|
||||
f flavors.F // assembler flavor
|
||||
@ -278,9 +279,9 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSimpleErrors(t *testing.T) {
|
||||
ss := scma.New()
|
||||
aa := as65.New()
|
||||
mm := merlin.New()
|
||||
ss := scma.New(opcodes.FlavorSweet16)
|
||||
aa := as65.New(opcodes.FlavorSweet16)
|
||||
mm := merlin.New(opcodes.FlavorSweet16)
|
||||
|
||||
tests := []struct {
|
||||
f flavors.F // assembler flavor
|
||||
|
@ -1,69 +0,0 @@
|
||||
package inst
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/zellyn/go6502/asm/context"
|
||||
"github.com/zellyn/go6502/asm/expr"
|
||||
"github.com/zellyn/go6502/asm/lines"
|
||||
)
|
||||
|
||||
func TestComputeLabel(t *testing.T) {
|
||||
i := I{
|
||||
Label: "L1",
|
||||
}
|
||||
c := &context.SimpleContext{}
|
||||
i.computeLabel(c, false)
|
||||
}
|
||||
|
||||
func TestWidthDoesNotChange(t *testing.T) {
|
||||
i := I{
|
||||
Type: TypeOp,
|
||||
Command: "LDA",
|
||||
Exprs: []*expr.E{
|
||||
&expr.E{
|
||||
Op: expr.OpMinus,
|
||||
Left: &expr.E{Op: expr.OpLeaf, Text: "L1"},
|
||||
Right: &expr.E{Op: expr.OpLeaf, Text: "L2"},
|
||||
},
|
||||
},
|
||||
Width: 0x2,
|
||||
Final: false,
|
||||
Op: 0xad,
|
||||
Mode: 0x2,
|
||||
ZeroMode: 0x80,
|
||||
ZeroOp: 0xa5,
|
||||
Line: &lines.Line{},
|
||||
}
|
||||
c := &context.SimpleContext{}
|
||||
c.Set("L1", 0x102)
|
||||
final, err := i.Compute(c, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if final {
|
||||
t.Fatal("Second pass shouldn't be able to finalize expression with unknown variable.")
|
||||
}
|
||||
if !i.WidthKnown {
|
||||
t.Fatal("Second pass should have set width.")
|
||||
}
|
||||
if i.Width != 3 {
|
||||
t.Fatalf("i.Width should be 3; got %d", i.Width)
|
||||
}
|
||||
|
||||
c.Set("L2", 0x101)
|
||||
|
||||
final, err = i.Compute(c, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !final {
|
||||
t.Fatal("Third pass should be able to finalize expression.")
|
||||
}
|
||||
if !i.WidthKnown {
|
||||
t.Fatal("Third pass should left width unchanged.")
|
||||
}
|
||||
if i.Width != 3 {
|
||||
t.Fatalf("i.Width should still be 3; got %d", i.Width)
|
||||
}
|
||||
}
|
@ -273,17 +273,24 @@ type OpSummary struct {
|
||||
Ops []OpInfo
|
||||
}
|
||||
|
||||
var ByName map[string]OpSummary
|
||||
type Flavor uint16
|
||||
|
||||
func init() {
|
||||
ByName = make(map[string]OpSummary)
|
||||
const (
|
||||
FlavorUnknown Flavor = iota
|
||||
FlavorSweet16
|
||||
)
|
||||
|
||||
func ByName(flavors Flavor) map[string]OpSummary {
|
||||
m := make(map[string]OpSummary)
|
||||
for b, oc := range Opcodes {
|
||||
info := OpInfo{oc.Mode, ModeLengths[oc.Mode], b}
|
||||
summary := ByName[oc.Name]
|
||||
summary := m[oc.Name]
|
||||
summary.Modes |= oc.Mode
|
||||
summary.Ops = append(summary.Ops, info)
|
||||
ByName[oc.Name] = summary
|
||||
m[oc.Name] = summary
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (s OpSummary) AnyModes(modes AddressingMode) bool {
|
||||
|
@ -39,7 +39,7 @@ func randomize(k *K64) {
|
||||
|
||||
// status prints out the current CPU instruction and register status.
|
||||
func status(c cpu.Cpu, m *[65536]byte, cc uint64) string {
|
||||
bytes, text, _ := asm.Disasm(c.PC(), m[c.PC()], m[c.PC()+1], m[c.PC()+2])
|
||||
bytes, text, _ := asm.Disasm(c.PC(), m[c.PC()], m[c.PC()+1], m[c.PC()+2], nil, 0)
|
||||
return fmt.Sprintf("$%04X: %s %s A=$%02X X=$%02X Y=$%02X SP=$%02X P=$%08b - %d\n",
|
||||
c.PC(), bytes, text, c.A(), c.X(), c.Y(), c.SP(), c.P(), cc)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user