From 072a4521def3c364947aee0b453138c27649707e Mon Sep 17 00:00:00 2001 From: Zellyn Hunter Date: Mon, 8 Sep 2014 20:59:14 -0700 Subject: [PATCH] Removed WidthKnown: ParseInstr sets width --- asm/asm.go | 10 ++-- asm/asm.org | 11 ++++ asm/cmd/a2as/runtest.sh | 14 ++++++ asm/flavors/common/common.go | 70 +++++++++++++++++--------- asm/flavors/merlin/merlin.go | 1 - asm/flavors/oldschool/oldschool.go | 24 +-------- asm/flavors/tests/assemble_test.go | 11 ++++ asm/flavors/tests/simple_parse_test.go | 16 +++--- asm/inst/instruction.go | 46 ----------------- 9 files changed, 96 insertions(+), 107 deletions(-) diff --git a/asm/asm.go b/asm/asm.go index 35ada0f..5c31b32 100644 --- a/asm/asm.go +++ b/asm/asm.go @@ -71,10 +71,6 @@ func (a *Assembler) Load(filename string, prefix int) error { return parseErr } - if mode == flavors.ParseModeNormal && !in.WidthKnown { - return in.Errorf("Width unknown") - } - if _, err := a.passInst(&in, false); err != nil { return err } @@ -253,7 +249,11 @@ func (a *Assembler) RawBytes() ([]byte, error) { if !in.Final { return []byte{}, in.Errorf("cannot finalize value: %s", in) } - result = append(result, in.Data...) + data := in.Data + for len(data) < int(in.Width) { + data = append(data, 0x00) + } + result = append(result, data...) } return result, nil } diff --git a/asm/asm.org b/asm/asm.org index 2eb9490..d19d11b 100644 --- a/asm/asm.org +++ b/asm/asm.org @@ -139,3 +139,14 @@ It's a bit tricky: 4. Evaluate instructions. + +** How it works now +asm.Load + for each line: + Flavor.ParseInstr(...) + passInst + Set address if ORG + in.Compute + Update addr +asm.Pass2 + passInst diff --git a/asm/cmd/a2as/runtest.sh b/asm/cmd/a2as/runtest.sh index a53ac9b..7e6029b 100755 --- a/asm/cmd/a2as/runtest.sh +++ b/asm/cmd/a2as/runtest.sh @@ -20,3 +20,17 @@ MD5_MONITOR=$(md5 -q monitor.rom) [[ $MD5_MONITOR == 'bc0163ca04c463e06f99fb029ad21b1f' ]] || echo 'Wrong checksum for monitor.rom' MD5_SWEET16=$(md5 -q sweet16.rom) [[ $MD5_SWEET16 == '93e148f5e30cdd574fd1bb3c26798787' ]] || echo 'Wrong checksum for sweet16.rom' + +go run a2as.go --in ../../../../goapple2/source/progaid/hires.asm --out hires.rom --flavor redbooka +go run a2as.go --in ../../../../goapple2/source/progaid/verify.asm --out verify.rom --flavor redbooka +go run a2as.go --in ../../../../goapple2/source/progaid/ramtest.asm --out ramtest.rom --flavor redbooka +go run a2as.go --in ../../../../goapple2/source/progaid/music.asm --out music.rom --flavor redbooka + +MD5_HIRES=$(md5 -q hires.rom) +[[ $MD5_HIRES == 'efe22f1a8c94458068fb12ae702b58c4' ]] || echo 'Wrong checksum for hires.rom' +MD5_MUSIC=$(md5 -q music.rom) +[[ $MD5_MUSIC == '0ffe796a73410e822fcae5e510374924' ]] || echo 'Wrong checksum for music.rom' +MD5_RAMTEST=$(md5 -q ramtest.rom) +[[ $MD5_RAMTEST == '0420635256a3b016323989e3a9fe4ce7' ]] || echo 'Wrong checksum for ramtest.rom' +MD5_VERIFY=$(md5 -q verify.rom) +[[ $MD5_VERIFY == '527f420462426e4851b942af46cc7f48' ]] || echo 'Wrong checksum for verify.rom' diff --git a/asm/flavors/common/common.go b/asm/flavors/common/common.go index 3871777..18dc4b5 100644 --- a/asm/flavors/common/common.go +++ b/asm/flavors/common/common.go @@ -29,7 +29,6 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect return in, in.Errorf("%s (addr,X) doesn't have a wide variant", in.Command) } in.Op = op.Byte - in.WidthKnown = true in.Width = 2 in.Mode = opcodes.MODE_INDIRECT_X in.Var = inst.VarOpByte @@ -46,7 +45,6 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect if forceWide { return in, fmt.Errorf("%s (addr),Y doesn't have a wide variant", in.Command) } - in.WidthKnown = true in.Width = 2 in.Mode = opcodes.MODE_INDIRECT_Y in.Op = op.Byte @@ -62,7 +60,6 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect return in, in.Errorf("%s doesn't support indirect (addr) mode", in.Command) } in.Op = op.Byte - in.WidthKnown = true in.Width = 3 in.Mode = opcodes.MODE_INDIRECT in.Var = inst.VarOpWord @@ -85,7 +82,6 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect } in.Op = op.Byte - in.WidthKnown = true in.Width = 2 in.Mode = opcodes.MODE_RELATIVE in.Var = inst.VarOpBranch @@ -107,7 +103,6 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect panic(fmt.Sprintf("opcode error: %s has no MODE_IMMEDIATE opcode", in.Command)) } in.Op = op.Byte - in.WidthKnown = true in.Width = 2 in.Mode = opcodes.MODE_IMMEDIATE in.Var = inst.VarOpByte @@ -139,50 +134,77 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect return in, in.Errorf("%s opcode doesn't support %s or %s modes.", zpS, wideS) } - if !summary.AnyModes(zp) { - if !wideOk { - panic(fmt.Sprintf("opcode error: %s has no %s opcode", in.Command, wideS)) - } + if !zpOk { in.Op = opWide.Byte - in.WidthKnown = true in.Width = 3 in.Mode = wide + in.Var = inst.VarOpWord + in.Mode = wide + if valKnown { + in.Data = []byte{in.Op, byte(val), byte(val >> 8)} + in.Final = true + } return in, nil } - if !summary.AnyModes(wide) { - if !zpOk { - panic(fmt.Sprintf("opcode error: %s has no %s opcode", in.Command, zpS)) - } + if !wideOk { if forceWide { return in, fmt.Errorf("%s doesn't have a wide variant", in.Command) } in.Op = opZp.Byte - in.WidthKnown = true in.Width = 2 in.Mode = zp + in.Var = inst.VarOpByte + in.Mode = zp + if valKnown { + in.Data = []byte{in.Op, byte(val)} + in.Final = true + } return in, nil } if forceWide { in.Op = opWide.Byte - in.WidthKnown = true in.Width = 3 in.Mode = wide + in.Var = inst.VarOpWord + if valKnown { + in.Data = []byte{in.Op, byte(val), byte(val >> 8)} + in.Final = true + } 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)) + if valKnown { + if val < 0x100 { + in.Op = opZp.Byte + in.Data = []byte{in.Op, byte(val)} + in.Width = 2 + in.Var = inst.VarOpByte + in.Mode = zp + in.Final = true + return in, nil + } + in.Op = opWide.Byte + in.Data = []byte{in.Op, byte(val), byte(val >> 8)} + in.Width = 3 + in.Var = inst.VarOpWord + in.Mode = wide + in.Final = true + return in, nil } - if !wideOk { - panic(fmt.Sprintf("opcode error: %s has no %s opcode", in.Command, wideS)) + + if in.Exprs[0].Width() == 1 { + in.Op = opZp.Byte + in.Mode = zp + in.Width = 2 + in.Var = inst.VarOpByte + return in, nil } + in.Op = opWide.Byte - in.ZeroOp = opZp.Byte in.Mode = wide - in.ZeroMode = zp - in.Width = 2 + in.Width = 3 + in.Var = inst.VarOpWord return in, nil } diff --git a/asm/flavors/merlin/merlin.go b/asm/flavors/merlin/merlin.go index 5dc0c12..400fd8c 100644 --- a/asm/flavors/merlin/merlin.go +++ b/asm/flavors/merlin/merlin.go @@ -200,7 +200,6 @@ func (m *Merlin) ParseInclude(ctx context.Context, in inst.I, lp *lines.Parse) ( return in, in.Errorf("%s expects filename", in.Command) } in.TextArg = prefix + filename - in.WidthKnown = true in.Width = 0 in.Final = true return in, nil diff --git a/asm/flavors/oldschool/oldschool.go b/asm/flavors/oldschool/oldschool.go index ce46a30..384c46f 100644 --- a/asm/flavors/oldschool/oldschool.go +++ b/asm/flavors/oldschool/oldschool.go @@ -102,7 +102,6 @@ func (a *Base) ParseInstr(ctx context.Context, line lines.Line, mode flavors.Par if a.ExtraCommenty != nil && a.ExtraCommenty(lp.Rest()) { in.Type = inst.TypeNone in.Final = true - in.WidthKnown = true in.Width = 0 return in, nil } @@ -112,7 +111,6 @@ func (a *Base) ParseInstr(ctx context.Context, line lines.Line, mode flavors.Par if trimmed == "" || trimmed[0] == '*' || rune(trimmed[0]) == a.CommentChar { in.Type = inst.TypeNone in.Final = true - in.WidthKnown = true in.Width = 0 return in, nil } @@ -143,7 +141,6 @@ func (a *Base) ParseInstr(ctx context.Context, line lines.Line, mode flavors.Par } } in.Final = true - in.WidthKnown = true in.Width = 0 return in, nil } @@ -221,7 +218,6 @@ func (a *Base) parseCmd(ctx context.Context, in inst.I, lp *lines.Parse, mode fl return in, err } if isMacro { - i.WidthKnown = true i.Width = 0 i.Final = true return i, nil @@ -232,7 +228,6 @@ func (a *Base) parseCmd(ctx context.Context, in inst.I, lp *lines.Parse, mode fl in.Type = dir.Type in.Var = dir.Var if dir.Func == nil { - in.WidthKnown = true in.Width = 0 in.Final = true return in, nil @@ -278,7 +273,6 @@ func (a *Base) parseSetting(ctx context.Context, in inst.I, lp *lines.Parse) (in default: return in, in.Errorf("expecting ON/OFF, found '%s'", in.TextArg) } - in.WidthKnown = true in.Width = 0 in.Final = true return in, nil @@ -330,7 +324,6 @@ func (a *Base) parseOpArgs(ctx context.Context, in inst.I, lp *lines.Parse, summ if summary.Modes == opcodes.MODE_IMPLIED { op := summary.Ops[0] in.Data = []byte{op.Byte} - in.WidthKnown = true in.Width = 1 in.Final = true in.Mode = opcodes.MODE_IMPLIED @@ -358,7 +351,6 @@ func (a *Base) parseOpArgs(ctx context.Context, in inst.I, lp *lines.Parse, summ panic(fmt.Sprintf("%s doesn't support accumulator mode", in.Command)) } in.Data = []byte{op.Byte} - in.WidthKnown = true in.Width = 1 in.Final = true in.Mode = opcodes.MODE_A @@ -387,7 +379,6 @@ func (a *Base) parseOpArgs(ctx context.Context, in inst.I, lp *lines.Parse, summ panic(fmt.Sprintf("%s doesn't support accumulator mode", in.Command)) } in.Data = []byte{op.Byte} - in.WidthKnown = true in.Width = 1 in.Final = true in.Mode = opcodes.MODE_A @@ -441,7 +432,6 @@ func (a *Base) ParseOrg(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I if err != nil { return in, err } - in.WidthKnown = true in.Width = 0 in.Final = true in.Addr = val @@ -483,7 +473,6 @@ func (a *Base) ParseAscii(ctx context.Context, in inst.I, lp *lines.Parse) (inst } } in.Width = uint16(len(in.Data)) - in.WidthKnown = true in.Final = true return in, nil } @@ -500,7 +489,6 @@ func (a *Base) ParseBlockStorage(ctx context.Context, in inst.I, lp *lines.Parse return in, in.Errorf("Cannot evaluate size of block storage on first pass") } - in.WidthKnown = true in.Final = true in.Width = val return in, nil @@ -520,7 +508,6 @@ func (a *Base) ParseData(ctx context.Context, in inst.I, lp *lines.Parse) (inst. } switch in.Var { case inst.VarBytes: - in.WidthKnown = true in.Width = uint16(len(in.Exprs)) in.Final = true for _, expr := range in.Exprs { @@ -528,11 +515,11 @@ func (a *Base) ParseData(ctx context.Context, in inst.I, lp *lines.Parse) (inst. if err != nil { in.Final = false in.Data = nil + break } in.Data = append(in.Data, byte(val)) } case inst.VarWordsLe, inst.VarWordsBe: - in.WidthKnown = true in.Width = 2 * uint16(len(in.Exprs)) in.Final = true for _, expr := range in.Exprs { @@ -540,6 +527,7 @@ func (a *Base) ParseData(ctx context.Context, in inst.I, lp *lines.Parse) (inst. if err != nil { in.Final = false in.Data = nil + break } if in.Var == inst.VarWordsLe { in.Data = append(in.Data, byte(val), byte(val>>8)) @@ -548,7 +536,6 @@ func (a *Base) ParseData(ctx context.Context, in inst.I, lp *lines.Parse) (inst. } } case inst.VarMixed: - in.WidthKnown = true in.Final = true for _, expr := range in.Exprs { in.Width += expr.Width() @@ -582,7 +569,6 @@ func (a *Base) ParseDo(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, return in, err } in.Exprs = append(in.Exprs, expr) - in.WidthKnown = true in.Width = 0 in.Final = true return in, nil @@ -601,7 +587,6 @@ func (a *Base) ParseEquate(ctx context.Context, in inst.I, lp *lines.Parse) (ins } _ = xyzzy in.Exprs = append(in.Exprs, expr) - in.WidthKnown = true in.Width = 0 in.Final = true return in, nil @@ -629,7 +614,6 @@ func (a *Base) ParseHexString(ctx context.Context, in inst.I, lp *lines.Parse) ( break } } - in.WidthKnown = true in.Width = uint16(len(in.Data)) in.Final = true return in, nil @@ -641,7 +625,6 @@ func (a *Base) ParseInclude(ctx context.Context, in inst.I, lp *lines.Parse) (in return in, in.Errorf("Expecting filename, found '%c'", lp.Next()) } in.TextArg = lp.Emit() - in.WidthKnown = true in.Width = 0 in.Final = true return in, nil @@ -654,7 +637,6 @@ func (a *Base) ParseMacroStart(ctx context.Context, in inst.I, lp *lines.Parse) return in, in.Errorf("Expecting valid macro name, found '%c'", lp.Next()) } in.TextArg = lp.Emit() - in.WidthKnown = true in.Width = 0 in.Final = true return in, nil @@ -663,14 +645,12 @@ func (a *Base) ParseMacroStart(ctx context.Context, in inst.I, lp *lines.Parse) // For assemblers where the macro name is the label, followed by the directive. func (a *Base) MarkMacroStart(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) { in.TextArg, in.Label = in.Label, "" - in.WidthKnown = true in.Width = 0 in.Final = true return in, nil } func (a *Base) ParseNoArgDir(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) { - in.WidthKnown = true in.Width = 0 in.Final = true return in, nil diff --git a/asm/flavors/tests/assemble_test.go b/asm/flavors/tests/assemble_test.go index ddb5040..6f669dd 100644 --- a/asm/flavors/tests/assemble_test.go +++ b/asm/flavors/tests/assemble_test.go @@ -294,6 +294,17 @@ func TestMultiline(t *testing.T) { " EOM", }, }, "a533c535a534e536ea", nil, true}, + + // Merlin: DB with unknown addresses + {mm, "DB with unknown addresses", []string{ + "ONE = $0123", + "TWO = $4567", + " DB $81A2-$77C4", "{data/b $0034,$0064,(- $81a2 $77c4),$000b,(msb (- $81a2 $77c4))}", "3464de0b09"}, @@ -239,13 +240,13 @@ func TestSimpleCommonFunctions(t *testing.T) { t.Errorf(`%d. %s.ParseInstr("%s") => error: %s`, i, tt.f, tt.i, err) continue } - if !in.WidthKnown { - t.Errorf(`%d. %s.ParseInstr("%s") => WidthKnown=false`, i, tt.f, tt.i) - continue - } if in.Line.Parse == nil { t.Errorf("Got empty in.Line.Parse on input '%s'", tt.i) } + + ctx.Set("L4", 0xbcde) + ctx.Set("L5", 0xcdef) + if in.Type != inst.TypeOrg { _, err = in.Compute(ctx, true) @@ -263,16 +264,13 @@ func TestSimpleCommonFunctions(t *testing.T) { hx := hex.EncodeToString(in.Data) // xxxxxx sets the width, but doesn't expect actual data if hx != tt.b && (len(tt.b) == 0 || tt.b[0] != 'x') { - t.Errorf(`%d. %s.ParseInstr("%s").Data = [%s]; want [%s]`, i, tt.f, tt.i, hx, tt.b) + t.Errorf(`%d. %s.ParseInstr("%s").Data = [%s]; want [%s] (%s)`, i, tt.f, tt.i, hx, tt.b, in) continue } // Check length w := uint16(len(tt.b) / 2) - if !in.WidthKnown { - t.Errorf(`%d. %s.WidthKnown is false`, i, in) - continue - } + if in.Width != w { t.Errorf(`%d. %s.Width=%d; want %d`, i, in, in.Width, w) continue diff --git a/asm/inst/instruction.go b/asm/inst/instruction.go index 28933f6..d4b4bd4 100644 --- a/asm/inst/instruction.go +++ b/asm/inst/instruction.go @@ -66,13 +66,10 @@ type I struct { TextArg string // Text of argument part Exprs []*expr.E // Expression(s) Data []byte // Actual bytes - WidthKnown bool // Do we know how many bytes this instruction takes yet? Width uint16 // width in bytes Final bool // Do we know the actual bytes yet? Op byte // Opcode Mode opcodes.AddressingMode // Opcode mode - ZeroMode opcodes.AddressingMode // Possible ZP-option mode - ZeroOp byte // Possible ZP-option Opcode Value uint16 // For Equates, the value DeclaredLine uint16 // Line number listed in file Line *lines.Line // Line object for this line @@ -216,7 +213,6 @@ func (i *I) Compute(c context.Context, final bool) (bool, error) { } // Everything else is zero-width - i.WidthKnown = true i.Width = 0 i.Final = true @@ -225,7 +221,6 @@ func (i *I) Compute(c context.Context, final bool) (bool, error) { func (i *I) computeData(c context.Context, final bool) (bool, error) { if len(i.Data) > 0 { - i.WidthKnown = true i.Width = uint16(len(i.Data)) i.Final = true return true, nil @@ -274,7 +269,6 @@ func (i *I) computeData(c context.Context, final bool) (bool, error) { } } i.Width = width - i.WidthKnown = true if allFinal { i.Data = data i.Final = true @@ -287,7 +281,6 @@ func (i *I) computeBlock(c context.Context, final bool) (bool, error) { val, err := i.Exprs[0].Eval(c, i.Line) if err == nil { i.Value = val - i.WidthKnown = true i.Final = true i.Width = val } else { @@ -299,7 +292,6 @@ func (i *I) computeBlock(c context.Context, final bool) (bool, error) { } func (i *I) computeMustKnow(c context.Context, final bool) (bool, error) { - i.WidthKnown = true i.Width = 0 i.Final = true val, err := i.Exprs[0].Eval(c, i.Line) @@ -322,12 +314,6 @@ func (i *I) computeMustKnow(c context.Context, final bool) (bool, error) { func (i *I) computeOp(c context.Context, 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) { - 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 { panic(fmt.Sprintf("Reached computeOp for '%s' with no expressions", i.Command)) @@ -344,40 +330,11 @@ func (i *I) computeOp(c context.Context, final bool) (bool, error) { return false, err } - // Already know enough. - if i.WidthKnown { - return false, nil - } - - // Do we know the width, even though the value is unknown? - if i.Exprs[0].Width() == 1 { - i.WidthKnown = true - i.Width = 2 - i.Op, i.Mode = i.ZeroOp, i.ZeroMode - i.ZeroOp, i.ZeroMode = 0, 0 - return false, nil - } - - // Okay, we have to set the width: since we don't know, go wide. - i.WidthKnown = true - i.Width = 3 - i.ZeroOp, i.ZeroMode = 0, 0 return false, nil } // If we got here, we got an actual value. - // We need to figure out the width - if !i.WidthKnown { - if val < 0x100 { - i.Width = 2 - i.Op = i.ZeroOp - i.Mode = i.ZeroMode - } else { - i.Width = 3 - } - } - // It's a branch if i.Mode == opcodes.MODE_RELATIVE { curr := c.GetAddr() @@ -391,10 +348,7 @@ func (i *I) computeOp(c context.Context, final bool) (bool, error) { val = uint16(offset) } - i.WidthKnown = true i.Final = true - i.ZeroOp = 0 - i.ZeroMode = 0 switch i.Width { case 2: