1
0
mirror of https://github.com/zellyn/go6502.git synced 2024-06-06 05:29:30 +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:
Zellyn Hunter 2016-04-22 06:40:00 -04:00
parent 218c3b9a91
commit 07a8d64377
13 changed files with 95 additions and 127 deletions

View File

@ -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 {

View File

@ -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)

View File

@ -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)

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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)
}
}

View File

@ -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 {

View File

@ -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)
}