mirror of
https://github.com/zellyn/go6502.git
synced 2025-02-05 18:34:27 +00:00
Got intbasic.asm compiling
This commit is contained in:
parent
8f04a118ab
commit
a9f4d9b8ff
@ -1,7 +0,0 @@
|
||||
go run a2as.go --in ../../../goapple2/source/redbook/monitor.asm --out monitor.rom --flavor redbooka --listing monitor.lst --prefix=-1
|
||||
go run a2as.go --in ../../../goapple2/source/redbook/miniasm.asm --out miniasm.rom --flavor redbooka --listing miniasm.lst --prefix=-1
|
||||
go run a2as.go --in ../../../goapple2/source/redbook/sweet16.asm --out sweet16.rom --flavor redbooka --listing sweet16.lst --prefix=-1
|
||||
go run a2as.go --in ../../../goapple2/source/redbook/fp.asm --out fp.rom --flavor redbookb --listing fp.lst --prefix=-1
|
||||
go run a2as.go --in ../../../goapple2/source/redbook/misc-f699.asm --out misc-f699.rom --flavor redbooka --listing misc-f699.lst --prefix=0
|
||||
# go run a2as.go --in ../../../goapple2/source/redbook/intbasic.asm --out intbasic.rom --flavor redbook --listing intbasic.lst --prefix=-1
|
||||
|
11
asm/asm.go
11
asm/asm.go
@ -44,6 +44,9 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if line.Parse != nil {
|
||||
// fmt.Fprintf("PLUGH: %s\n", line.Text())
|
||||
// }
|
||||
if done {
|
||||
lineSources = lineSources[1:]
|
||||
continue
|
||||
@ -53,6 +56,11 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
// we're in an inactive ifdef branch
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := in.FixLabels(a.Flavor); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -79,7 +87,7 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
if !ok {
|
||||
return in.Errorf(`unknown macro: "%s"`, in.Command)
|
||||
}
|
||||
subLs, err := m.LineSource(a.Flavor, in, macroCall)
|
||||
subLs, err := m.LineSource(a.Flavor, in, macroCall, prefix)
|
||||
if err != nil {
|
||||
return in.Errorf(`error calling macro "%s": %v`, m.Name, err)
|
||||
}
|
||||
@ -170,6 +178,7 @@ func (a *Assembler) readMacro(in inst.I, ls lines.LineSource) error {
|
||||
m.Locals[in2.Label] = true
|
||||
}
|
||||
if err == nil && in2.Type == inst.TypeMacroEnd {
|
||||
m.Lines = append(m.Lines, line.Parse.Text())
|
||||
a.Macros[m.Name] = m
|
||||
a.Flavor.AddMacroName(m.Name)
|
||||
return nil
|
||||
|
@ -81,7 +81,6 @@ func main() {
|
||||
fmt.Fprintf(os.Stderr, "Error trying to determine prefix length for file '%s'", *infile, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Prefix guessed to be %d\n", p)
|
||||
}
|
||||
|
||||
if err := a.AssembleWithPrefix(*infile, p); err != nil {
|
7
asm/cmd/a2as/runtest.sh
Executable file
7
asm/cmd/a2as/runtest.sh
Executable file
@ -0,0 +1,7 @@
|
||||
go run a2as.go --in ../../../../goapple2/source/redbook/monitor.asm --out monitor.rom --flavor redbooka --listing monitor.lst --prefix=-1
|
||||
go run a2as.go --in ../../../../goapple2/source/redbook/miniasm.asm --out miniasm.rom --flavor redbooka --listing miniasm.lst --prefix=-1
|
||||
go run a2as.go --in ../../../../goapple2/source/redbook/sweet16.asm --out sweet16.rom --flavor redbooka --listing sweet16.lst --prefix=-1
|
||||
go run a2as.go --in ../../../../goapple2/source/redbook/fp.asm --out fp.rom --flavor redbookb --listing fp.lst --prefix=-1
|
||||
go run a2as.go --in ../../../../goapple2/source/redbook/misc-f699.asm --out misc-f699.rom --flavor redbooka --listing misc-f699.lst --prefix=0
|
||||
go run a2as.go --in ../../../../goapple2/source/redbook/intbasic.asm --out intbasic.rom --flavor merlin --listing intbasic.lst --prefix=-1
|
||||
|
180
asm/cmd/starbang/starbang.go
Normal file
180
asm/cmd/starbang/starbang.go
Normal file
@ -0,0 +1,180 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var re = regexp.MustCompile(`^([ ]*)([0-9]+)([ ]+)\*![ ]*(ENDIF|IF|LOOP|UNTIL|WHILE)(?: <(..)>)?$`)
|
||||
|
||||
type stackEntry struct {
|
||||
command string
|
||||
label string
|
||||
lineNum int
|
||||
endLabel string
|
||||
}
|
||||
|
||||
var labelNum int
|
||||
|
||||
func makeLabel() string {
|
||||
labelNum++
|
||||
return fmt.Sprintf("LABEL%d", labelNum)
|
||||
}
|
||||
|
||||
func printLine(space1, line, space2, label, text string) (int, error) {
|
||||
return printLineN("5", space1, line, space2, label, text)
|
||||
}
|
||||
|
||||
func printLine2(space1, line, space2, label, text string) (int, error) {
|
||||
return printLineN("7", space1, line, space2, label, text)
|
||||
}
|
||||
|
||||
func printLineN(units, space1, line, space2, label, text string) (int, error) {
|
||||
out := fmt.Sprintf("%s%s%s%s", space1, line[:len(line)-1], units, space2)
|
||||
if label != "" {
|
||||
out = out + label
|
||||
}
|
||||
if text != "" {
|
||||
out = out + " " + text
|
||||
}
|
||||
return fmt.Printf("%s\n", out)
|
||||
}
|
||||
|
||||
func branch(test string) string {
|
||||
switch test {
|
||||
case "CC":
|
||||
return "BCC"
|
||||
case "CS":
|
||||
return "BCS"
|
||||
case "EQ":
|
||||
return "BEQ"
|
||||
case "HS":
|
||||
return "BCS"
|
||||
case "LO":
|
||||
return "BCC"
|
||||
case "MI":
|
||||
return "BMI"
|
||||
case "NE":
|
||||
return "BNE"
|
||||
case "PL":
|
||||
return "BPL"
|
||||
}
|
||||
return "B??"
|
||||
}
|
||||
|
||||
func branchOpposite(test string) string {
|
||||
switch test {
|
||||
case "CC":
|
||||
return "BCS"
|
||||
case "CS":
|
||||
return "BCC"
|
||||
case "EQ":
|
||||
return "BNE"
|
||||
case "HS":
|
||||
return "BCC"
|
||||
case "LO":
|
||||
return "BCS"
|
||||
case "MI":
|
||||
return "BPL"
|
||||
case "NE":
|
||||
return "BEQ"
|
||||
case "PL":
|
||||
return "BMI"
|
||||
}
|
||||
return "B??"
|
||||
}
|
||||
|
||||
func process(filename string) error {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scanner := bufio.NewScanner(file)
|
||||
var stack []stackEntry
|
||||
lineNum := 0
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
lineNum++
|
||||
fmt.Println(line)
|
||||
groups := re.FindStringSubmatch(line)
|
||||
lastLabel := ""
|
||||
if groups == nil {
|
||||
lastLabel = ""
|
||||
continue
|
||||
}
|
||||
space1, line, space2, command, test := groups[1], groups[2], groups[3], groups[4], groups[5]
|
||||
_ = test
|
||||
last := &stackEntry{command: "(none)"}
|
||||
if len(stack) > 0 {
|
||||
last = &stack[len(stack)-1]
|
||||
}
|
||||
switch command {
|
||||
case "LOOP":
|
||||
if lastLabel == "" {
|
||||
lastLabel = makeLabel()
|
||||
}
|
||||
printLine(space1, line, space2, lastLabel, "")
|
||||
stack = append(stack, stackEntry{command: command, label: lastLabel, lineNum: lineNum})
|
||||
case "UNTIL":
|
||||
if last.command != "LOOP" {
|
||||
return fmt.Errorf("%d: %s found with no corresponding LOOP. Last command: %s/%d", lineNum, command, last.command, last.lineNum)
|
||||
}
|
||||
br := branchOpposite(test)
|
||||
cmd := fmt.Sprintf("%s %s", br, last.label)
|
||||
printLine(space1, line, space2, "", cmd)
|
||||
|
||||
// If we had a WHILE, we need an endlabel printed
|
||||
if last.endLabel != "" {
|
||||
printLine2(space1, line, space2, last.endLabel, "")
|
||||
lastLabel = last.endLabel
|
||||
}
|
||||
stack = stack[:len(stack)-1]
|
||||
case "WHILE":
|
||||
if last.command != "LOOP" {
|
||||
return fmt.Errorf("%d: %s found with no corresponding LOOP. Last command: %s/%d", lineNum, command, last.command, last.lineNum)
|
||||
}
|
||||
if last.endLabel == "" {
|
||||
last.endLabel = makeLabel()
|
||||
}
|
||||
br := branchOpposite(test)
|
||||
cmd := fmt.Sprintf("%s %s", br, last.endLabel)
|
||||
printLine(space1, line, space2, "", cmd)
|
||||
case "IF":
|
||||
lastLabel = ""
|
||||
label := makeLabel()
|
||||
stack = append(stack, stackEntry{command: command, label: label, lineNum: lineNum})
|
||||
cmd := fmt.Sprintf("%s %s", branchOpposite(test), label)
|
||||
printLine(space1, line, space2, "", cmd)
|
||||
|
||||
case "ENDIF":
|
||||
if last.command != "IF" {
|
||||
return fmt.Errorf("%d: %s found with no corresponding IF. Last command: %s/%d", lineNum, command, last.command, last.lineNum)
|
||||
}
|
||||
printLine(space1, line, space2, last.label, "")
|
||||
lastLabel = last.label
|
||||
stack = stack[:len(stack)-1]
|
||||
default:
|
||||
return fmt.Errorf("%d: unknown command: %s", lineNum, command)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if err = scanner.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "Usage: starbang <input file>\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := process(os.Args[1]); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@ func New() *Merlin {
|
||||
"=": {inst.TypeEqu, m.ParseEquate, inst.EquNormal},
|
||||
"HEX": {inst.TypeData, m.ParseHexString, inst.DataBytes},
|
||||
"DFB": {inst.TypeData, m.ParseData, inst.DataBytes},
|
||||
"DB": {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},
|
||||
|
@ -249,6 +249,43 @@ func TestMultiline(t *testing.T) {
|
||||
" PMC M1($43;$44",
|
||||
" M1 $44",
|
||||
}, nil, "eae642d000eae643d000eae644d000ea", nil, true},
|
||||
|
||||
// Merlin: macros in other files
|
||||
{mm, "macro in include", []string{
|
||||
" ORG $E000",
|
||||
" USE MACROS",
|
||||
"PROMPT = $0033",
|
||||
" INCW PROMPT",
|
||||
" NOP",
|
||||
}, map[string][]string{
|
||||
"T.MACROS": {
|
||||
"* Increment word",
|
||||
"INCW MAC",
|
||||
" INC ]1",
|
||||
" BNE INCW_END",
|
||||
" INC ]1+1",
|
||||
"INCW_END EOM",
|
||||
},
|
||||
}, "e633d002e634ea", nil, true},
|
||||
|
||||
// Merlin: macros override the 3+1 zero-page rule
|
||||
{mm, "macro vs zero page override", []string{
|
||||
" USE MACROS",
|
||||
"A1 = $0033",
|
||||
"A2 = $0035",
|
||||
" CMPW A1;A2",
|
||||
" NOP",
|
||||
}, map[string][]string{
|
||||
"T.MACROS": {
|
||||
"* Compare word",
|
||||
"CMPW MAC",
|
||||
" LDA ]1",
|
||||
" CMP ]2",
|
||||
" LDA ]1+1",
|
||||
" SBC ]2+1",
|
||||
" EOM",
|
||||
},
|
||||
}, "a533c535a534e536ea", nil, true},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
|
@ -373,7 +373,10 @@ func (i *I) computeMustKnow(c context.Context, setWidth bool, final bool) (bool,
|
||||
func (i *I) computeOp(c context.Context, setWidth bool, final bool) (bool, error) {
|
||||
// If the width is not known, we better have a ZeroPage alternative.
|
||||
if !i.WidthKnown && (i.ZeroOp == 0 || i.ZeroMode == 0) {
|
||||
panic(fmt.Sprintf("Reached computeOp for '%s' with no ZeroPage alternative, i.Command"))
|
||||
if i.Line.Context != nil && i.Line.Context.Parent != nil {
|
||||
fmt.Println(i.Line.Context.Parent.Sprintf("foo"))
|
||||
}
|
||||
panic(i.Sprintf("Reached computeOp for '%s' with no ZeroPage alternative: %#v [%s]", i.Command, i, i.Line.Text()))
|
||||
}
|
||||
// An op with no args would be final already, so we must have an Expression.
|
||||
if len(i.Exprs) == 0 {
|
||||
|
@ -13,7 +13,7 @@ type M struct {
|
||||
Locals map[string]bool // labels that should be scoped to macro invocation
|
||||
}
|
||||
|
||||
func (m M) LineSource(flavor flavors.F, in inst.I, macroCall int) (lines.LineSource, error) {
|
||||
func (m M) LineSource(flavor flavors.F, in inst.I, macroCall int, prefix int) (lines.LineSource, error) {
|
||||
var ls []string
|
||||
context := lines.Context{Filename: "macro:" + m.Name, Parent: in.Line, MacroCall: macroCall, MacroLocals: m.Locals}
|
||||
for _, line := range m.Lines {
|
||||
@ -24,5 +24,5 @@ func (m M) LineSource(flavor flavors.F, in inst.I, macroCall int) (lines.LineSou
|
||||
}
|
||||
ls = append(ls, subbed)
|
||||
}
|
||||
return lines.NewSimpleLineSource(context, ls, 0), nil
|
||||
return lines.NewSimpleLineSource(context, ls, prefix), nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user