From 9c0bcea95d97983275e8fa83bba72b9d8ccff848 Mon Sep 17 00:00:00 2001 From: Zellyn Hunter Date: Tue, 10 May 2016 05:57:17 -0400 Subject: [PATCH] Use int64 for intermediate results internally --- asm/context/context.go | 12 ++++---- asm/expr/expression.go | 8 +++--- asm/flavors/as65/as65.go | 29 ++++++++++++-------- asm/flavors/common/base.go | 38 ++++++++++++++++++-------- asm/flavors/common/decodeop.go | 2 +- asm/flavors/tests/simple_parse_test.go | 3 +- asm/inst/instruction.go | 11 +++++--- 7 files changed, 65 insertions(+), 38 deletions(-) diff --git a/asm/context/context.go b/asm/context/context.go index 57a1379..27c9fa3 100644 --- a/asm/context/context.go +++ b/asm/context/context.go @@ -3,8 +3,8 @@ package context import "fmt" type Context interface { - Set(name string, value uint16) - Get(name string) (uint16, bool) + Set(name string, value int64) + Get(name string) (int64, bool) SetAddr(uint16) GetAddr() uint16 DivZero() *uint16 @@ -44,7 +44,7 @@ type SimpleContext struct { } type symbolValue struct { - v uint16 + v int64 changed bool // Did the value ever change? } @@ -54,9 +54,9 @@ func (sc *SimpleContext) fix() { } } -func (sc *SimpleContext) Get(name string) (uint16, bool) { +func (sc *SimpleContext) Get(name string) (int64, bool) { if name == "*" { - return sc.GetAddr(), true + return int64(sc.GetAddr()), true } sc.fix() s, found := sc.symbols[name] @@ -71,7 +71,7 @@ func (sc *SimpleContext) GetAddr() uint16 { return sc.addr } -func (sc *SimpleContext) Set(name string, value uint16) { +func (sc *SimpleContext) Set(name string, value int64) { sc.fix() s, found := sc.symbols[name] if found && s.v != value { diff --git a/asm/expr/expression.go b/asm/expr/expression.go index 0063d0b..9c3882a 100644 --- a/asm/expr/expression.go +++ b/asm/expr/expression.go @@ -57,7 +57,7 @@ type E struct { Right *E Op Operator Text string - Val uint16 + Val int64 } func (e E) String() string { @@ -106,7 +106,7 @@ func (e *E) Width() uint16 { return 2 } -func (e *E) Eval(ctx context.Context, ln *lines.Line) (uint16, error) { +func (e *E) Eval(ctx context.Context, ln *lines.Line) (int64, error) { if e == nil { return 0, errors.New("cannot Eval() nil expression") } @@ -178,7 +178,7 @@ func (e *E) Eval(ctx context.Context, ln *lines.Line) (uint16, error) { if z == nil { return 0, ln.Errorf("divizion by zero") } - return *z, nil + return int64(*z), nil } return l / r, nil case OpAnd: @@ -194,7 +194,7 @@ func (e *E) Eval(ctx context.Context, ln *lines.Line) (uint16, error) { } // CheckedEval calls Eval, but also turns UnknownLabelErrors into labelMissing booleans. -func (e *E) CheckedEval(ctx context.Context, ln *lines.Line) (val uint16, labelMissing bool, err error) { +func (e *E) CheckedEval(ctx context.Context, ln *lines.Line) (val int64, labelMissing bool, err error) { val, err = e.Eval(ctx, ln) switch err.(type) { case nil: diff --git a/asm/flavors/as65/as65.go b/asm/flavors/as65/as65.go index a3bcb0b..bc72612 100644 --- a/asm/flavors/as65/as65.go +++ b/asm/flavors/as65/as65.go @@ -37,17 +37,24 @@ func New(sets opcodes.Set) *As65 { "EQU": {inst.TypeEqu, a.ParseEquate, inst.VarEquNormal}, "EPZ": {inst.TypeEqu, a.ParseEquate, inst.VarEquPageZero}, "DFB": {inst.TypeData, a.ParseData, inst.VarBytes}, - "DW": {inst.TypeData, a.ParseData, inst.VarWordsLe}, - "DDB": {inst.TypeData, a.ParseData, inst.VarWordsBe}, - "ASC": {inst.TypeData, a.ParseAscii, inst.VarAscii}, - "DCI": {inst.TypeData, a.ParseAscii, inst.VarAsciiFlip}, - "HEX": {inst.TypeData, a.ParseHexString, inst.VarBytes}, - "PAGE": {inst.TypeNone, nil, 0}, // New page - "TITLE": {inst.TypeNone, nil, 0}, // Title - "SBTL": {inst.TypeNone, nil, 0}, // Subtitle - "SKP": {inst.TypeNone, nil, 0}, // Skip lines - "REP": {inst.TypeNone, nil, 0}, // Repeat character - "CHR": {inst.TypeNone, nil, 0}, // Set repeated character + + "ds": {inst.TypeData, a.ParseData, inst.VarBytesZero}, + "rmb": {inst.TypeData, a.ParseData, inst.VarBytesZero}, + + "dw": {inst.TypeData, a.ParseData, inst.VarWordsLe}, + "fcw": {inst.TypeData, a.ParseData, inst.VarWordsLe}, + "fdb": {inst.TypeData, a.ParseData, inst.VarWordsLe}, + + "DDB": {inst.TypeData, a.ParseData, inst.VarWordsBe}, + "ASC": {inst.TypeData, a.ParseAscii, inst.VarAscii}, + "DCI": {inst.TypeData, a.ParseAscii, inst.VarAsciiFlip}, + "HEX": {inst.TypeData, a.ParseHexString, inst.VarBytes}, + "PAGE": {inst.TypeNone, nil, 0}, // New page + "TITLE": {inst.TypeNone, nil, 0}, // Title + "SBTL": {inst.TypeNone, nil, 0}, // Subtitle + "SKP": {inst.TypeNone, nil, 0}, // Skip lines + "REP": {inst.TypeNone, nil, 0}, // Repeat character + "CHR": {inst.TypeNone, nil, 0}, // Set repeated character } a.EquateDirectives = map[string]bool{ diff --git a/asm/flavors/common/base.go b/asm/flavors/common/base.go index 498eee9..77c75ab 100644 --- a/asm/flavors/common/base.go +++ b/asm/flavors/common/base.go @@ -166,10 +166,10 @@ func (a *Base) handleLabel(ctx context.Context, in inst.I) error { } lval, lok := ctx.Get(in.Label) - if lok && addr != lval { + if lok && int64(addr) != lval { return in.Errorf("Trying to set label '%s' to $%04x, but it already has value $%04x", in.Label, addr, lval) } - ctx.Set(in.Label, addr) + ctx.Set(in.Label, int64(addr)) return nil } @@ -432,7 +432,7 @@ func (a *Base) ParseOrg(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I } in.Width = 0 in.Final = true - in.Addr = val + in.Addr = uint16(val) return in, nil } @@ -488,7 +488,7 @@ func (a *Base) ParseBlockStorage(ctx context.Context, in inst.I, lp *lines.Parse } in.Final = true - in.Width = val + in.Width = uint16(val) return in, nil } @@ -554,6 +554,22 @@ func (a *Base) ParseData(ctx context.Context, in inst.I, lp *lines.Parse) (inst. } } } + case inst.VarBytesZero: + in.Final = true + if len(in.Exprs) != 1 { + return in, in.Errorf("%v expected one expression (length); got %d", in.Command, len(in.Exprs)) + } + val, err := in.Exprs[0].Eval(ctx, in.Line) + if err != nil { + in.Final = false + in.Data = nil + } else { + in.Final = true + in.Width = uint16(val) + for i := int(val); i > 0; i-- { + in.Data = append(in.Data, 0) + } + } default: return in, in.Errorf("Unknown Var(%d) with ParseData for %s", in.Var, in.Command) } @@ -738,12 +754,12 @@ func (a *Base) ParseTerm(ctx context.Context, in inst.I, lp *lines.Parse) (*expr return &expr.E{}, in.Errorf("expecting hex number, found '%c' (%d)", c, c) } s := lp.Emit() - i, err := strconv.ParseUint(s, 16, 16) + i, err := strconv.ParseInt(s, 16, 64) if err != nil { return &expr.E{}, in.Errorf("invalid hex number: %s: %s", s, err) } ex.Op = expr.OpLeaf - ex.Val = uint16(i) + ex.Val = i return top, nil } @@ -754,24 +770,24 @@ func (a *Base) ParseTerm(ctx context.Context, in inst.I, lp *lines.Parse) (*expr return &expr.E{}, in.Errorf("expecting binary number, found '%c' (%d)", c, c) } s := lp.Emit() - i, err := strconv.ParseUint(s, 2, 16) + i, err := strconv.ParseInt(s, 2, 64) if err != nil { return &expr.E{}, in.Errorf("invalid binary number: %s: %s", s, err) } ex.Op = expr.OpLeaf - ex.Val = uint16(i) + ex.Val = i return top, nil } // Decimal if lp.AcceptRun(Digits) { s := lp.Emit() - i, err := strconv.ParseUint(s, 10, 16) + i, err := strconv.ParseInt(s, 10, 64) if err != nil { return &expr.E{}, in.Errorf("invalid number: %s: %s", s, err) } ex.Op = expr.OpLeaf - ex.Val = uint16(i) + ex.Val = i return top, nil } @@ -784,7 +800,7 @@ func (a *Base) ParseTerm(ctx context.Context, in inst.I, lp *lines.Parse) (*expr return &expr.E{}, in.Errorf("end of line after quote") } ex.Op = expr.OpLeaf - ex.Val = uint16(c) + ex.Val = int64(c) if strings.Contains(a.InvCharChars, quote[:1]) { ex.Val |= 0x80 } diff --git a/asm/flavors/common/decodeop.go b/asm/flavors/common/decodeop.go index b0c86c8..ddfb648 100644 --- a/asm/flavors/common/decodeop.go +++ b/asm/flavors/common/decodeop.go @@ -83,7 +83,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect in.Width = 2 in.Var = inst.VarOpBranch if valKnown { - b, err := RelativeAddr(c, in, val) + b, err := RelativeAddr(c, in, uint16(val)) if err != nil { return in, err } diff --git a/asm/flavors/tests/simple_parse_test.go b/asm/flavors/tests/simple_parse_test.go index 442b395..d89db3f 100644 --- a/asm/flavors/tests/simple_parse_test.go +++ b/asm/flavors/tests/simple_parse_test.go @@ -31,7 +31,8 @@ func TestSimpleCommonFunctions(t *testing.T) { {aa, " beq $2343", "{beq $2343}", "f0fc"}, {aa, " beq $2345", "{beq $2345}", "f0fe"}, {aa, " beq $2347", "{beq $2347}", "f000"}, - // {aa, " dw $1234", "{data/wle $1234}", "3412"}, + {aa, " dw $1234", "{data/wle $1234}", "3412"}, + {aa, " ds 5", "{data/bz $0005}", "0000000000"}, {aa, " jmp $1234", "{jmp/abs $1234}", "4c3412"}, {aa, " jmp ($1234)", "{jmp/ind $1234}", "6c3412"}, {aa, " lda #$12", "{lda/imm (lsb $0012)}", "a912"}, diff --git a/asm/inst/instruction.go b/asm/inst/instruction.go index 258f722..86cf513 100644 --- a/asm/inst/instruction.go +++ b/asm/inst/instruction.go @@ -45,6 +45,7 @@ const ( VarMixed // Bytes or words (LE), depending on individual expression widths VarWordsLe // Data: expressions, but forced to one word per, little-endian VarWordsBe // Data: expressions, but forced to one word per, big-endian + VarBytesZero // Data: a run of zeros VarAscii // Data: from ASCII strings, high bit clear VarAsciiFlip // Data: from ASCII strings, high bit clear, except last char VarAsciiHi // Data: from ASCII strings, high bit set @@ -68,7 +69,7 @@ type I struct { Width uint16 // width in bytes Final bool // Do we know the actual bytes yet? Op byte // Opcode - Value uint16 // For Equates, the value + Value int64 // For Equates, the value DeclaredLine uint16 // Line number listed in file Line *lines.Line // Line object for this line Addr uint16 // Current memory address @@ -103,6 +104,8 @@ func (i I) TypeString() string { return "data" case VarBytes: return "data/b" + case VarBytesZero: + return "data/bz" case VarWordsLe: return "data/wle" case VarWordsBe: @@ -235,7 +238,7 @@ func (i *I) computeBlock(c context.Context, final bool) (bool, error) { if err == nil { i.Value = val i.Final = true - i.Width = val + i.Width = uint16(val) } else { if final { return false, i.Errorf("block storage with unknown size") @@ -254,7 +257,7 @@ func (i *I) computeMustKnow(c context.Context) error { case TypeTarget: return errors.New("Target not implemented yet.") case TypeOrg: - c.SetAddr(val) + c.SetAddr(uint16(val)) case TypeEqu: c.Set(i.Label, val) // Don't handle labels. @@ -286,7 +289,7 @@ func (i *I) computeOp(c context.Context) error { if offset < -128 { return i.Errorf("%s cannot jump back %d (max -128) from $%04x to $%04x", i.Command, offset, curr+2, val) } - val = uint16(offset) + val = int64(offset) } i.Final = true