mirror of
https://github.com/zellyn/go6502.git
synced 2025-02-12 04:30:30 +00:00
Only call compute on second pass.
This commit is contained in:
parent
072a4521de
commit
498b6c5a7d
46
asm/asm.go
46
asm/asm.go
@ -71,10 +71,15 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
return parseErr
|
||||
}
|
||||
|
||||
if _, err := a.passInst(&in, false); err != nil {
|
||||
return err
|
||||
if in.Type == inst.TypeOrg {
|
||||
a.Ctx.SetAddr(in.Addr)
|
||||
}
|
||||
|
||||
// Update address
|
||||
addr := a.Ctx.GetAddr()
|
||||
in.Addr = addr
|
||||
a.Ctx.SetAddr(addr + in.Width)
|
||||
|
||||
switch in.Type {
|
||||
case inst.TypeUnknown:
|
||||
if parseErr != nil {
|
||||
@ -200,41 +205,26 @@ func (a *Assembler) initPass() {
|
||||
a.Ctx.SetAddr(a.Flavor.DefaultOrigin())
|
||||
}
|
||||
|
||||
// passInst performs a pass on a single instruction. It forces the
|
||||
// instruction to decide its width, but may not know all the
|
||||
// arguments. If final is true, and the instruction cannot be
|
||||
// finalized, it returns an error.
|
||||
func (a *Assembler) passInst(in *inst.I, final bool) (isFinal bool, err error) {
|
||||
if in.Type == inst.TypeOrg {
|
||||
a.Ctx.SetAddr(in.Addr)
|
||||
return true, nil
|
||||
}
|
||||
isFinal, err = in.Compute(a.Ctx, final)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Update address
|
||||
addr := a.Ctx.GetAddr()
|
||||
in.Addr = addr
|
||||
a.Ctx.SetAddr(addr + in.Width)
|
||||
|
||||
return isFinal, nil
|
||||
}
|
||||
|
||||
// Pass2 performs the second assembly pass. It returns an error for
|
||||
// any instruction that cannot be finalized.
|
||||
func (a *Assembler) Pass2() error {
|
||||
a.initPass()
|
||||
|
||||
for _, in := range a.Insts {
|
||||
instFinal, err := a.passInst(in, true)
|
||||
if in.Type == inst.TypeOrg {
|
||||
a.Ctx.SetAddr(in.Addr)
|
||||
continue
|
||||
}
|
||||
|
||||
err := in.Compute(a.Ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !instFinal {
|
||||
return in.Errorf("cannot finalize instruction: %s", in)
|
||||
}
|
||||
|
||||
// Update address
|
||||
addr := a.Ctx.GetAddr()
|
||||
in.Addr = addr
|
||||
a.Ctx.SetAddr(addr + in.Width)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -581,11 +581,11 @@ func (a *Base) ParseEquate(ctx context.Context, in inst.I, lp *lines.Parse) (ins
|
||||
return in, err
|
||||
}
|
||||
|
||||
xyzzy, err := expr.Eval(ctx, in.Line)
|
||||
val, err := expr.Eval(ctx, in.Line)
|
||||
if err != nil {
|
||||
return in, err
|
||||
}
|
||||
_ = xyzzy
|
||||
ctx.Set(in.Label, val)
|
||||
in.Exprs = append(in.Exprs, expr)
|
||||
in.Width = 0
|
||||
in.Final = true
|
||||
|
@ -248,10 +248,8 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
ctx.Set("L5", 0xcdef)
|
||||
|
||||
if in.Type != inst.TypeOrg {
|
||||
_, err = in.Compute(ctx, true)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s"): %s.Compute(tt.f, true) => error: %s`, i, tt.f, tt.i, in, err)
|
||||
if err = in.Compute(ctx); err != nil {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s"): %s.Compute(tt.f) => error: %s`, i, tt.f, tt.i, in, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -191,42 +191,36 @@ func (i I) String() string {
|
||||
}
|
||||
|
||||
// Compute attempts to finalize the instruction.
|
||||
func (i *I) Compute(c context.Context, final bool) (bool, error) {
|
||||
// xyzzy - remove
|
||||
if i.Type == TypeOrg {
|
||||
panic("Compute called with TypeOrg")
|
||||
return true, nil
|
||||
}
|
||||
func (i *I) Compute(c context.Context) error {
|
||||
if i.Type == TypeEqu || i.Type == TypeTarget {
|
||||
return i.computeMustKnow(c, final)
|
||||
return i.computeMustKnow(c)
|
||||
}
|
||||
if i.Final {
|
||||
return true, nil
|
||||
return nil
|
||||
}
|
||||
switch i.Type {
|
||||
case TypeOp:
|
||||
return i.computeOp(c, final)
|
||||
return i.computeOp(c)
|
||||
case TypeData:
|
||||
return i.computeData(c, final)
|
||||
return i.computeData(c)
|
||||
case TypeBlock:
|
||||
return i.computeBlock(c, final)
|
||||
panic("Compute called with TypeBlock")
|
||||
}
|
||||
|
||||
// Everything else is zero-width
|
||||
i.Width = 0
|
||||
i.Final = true
|
||||
|
||||
return true, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *I) computeData(c context.Context, final bool) (bool, error) {
|
||||
func (i *I) computeData(c context.Context) error {
|
||||
if len(i.Data) > 0 {
|
||||
i.Width = uint16(len(i.Data))
|
||||
i.Final = true
|
||||
return true, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
allFinal := true
|
||||
data := []byte{}
|
||||
var width uint16
|
||||
for _, e := range i.Exprs {
|
||||
@ -240,15 +234,9 @@ func (i *I) computeData(c context.Context, final bool) (bool, error) {
|
||||
w = 2
|
||||
}
|
||||
width += w
|
||||
val, labelMissing, err := e.CheckedEval(c, i.Line)
|
||||
if err != nil && !labelMissing {
|
||||
return false, err
|
||||
}
|
||||
if labelMissing {
|
||||
allFinal = false
|
||||
if final {
|
||||
return false, err
|
||||
}
|
||||
val, err := e.Eval(c, i.Line)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch i.Var {
|
||||
case VarMixed:
|
||||
@ -269,12 +257,9 @@ func (i *I) computeData(c context.Context, final bool) (bool, error) {
|
||||
}
|
||||
}
|
||||
i.Width = width
|
||||
if allFinal {
|
||||
i.Data = data
|
||||
i.Final = true
|
||||
}
|
||||
|
||||
return i.Final, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *I) computeBlock(c context.Context, final bool) (bool, error) {
|
||||
@ -291,46 +276,36 @@ func (i *I) computeBlock(c context.Context, final bool) (bool, error) {
|
||||
return i.Final, nil
|
||||
}
|
||||
|
||||
func (i *I) computeMustKnow(c context.Context, final bool) (bool, error) {
|
||||
func (i *I) computeMustKnow(c context.Context) error {
|
||||
i.Width = 0
|
||||
i.Final = true
|
||||
val, err := i.Exprs[0].Eval(c, i.Line)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return err
|
||||
}
|
||||
i.Value = val
|
||||
switch i.Type {
|
||||
case TypeTarget:
|
||||
return false, errors.New("Target not implemented yet.")
|
||||
return errors.New("Target not implemented yet.")
|
||||
case TypeOrg:
|
||||
c.SetAddr(val)
|
||||
case TypeEqu:
|
||||
c.Set(i.Label, val)
|
||||
// Don't handle labels.
|
||||
return true, nil
|
||||
return nil
|
||||
}
|
||||
return true, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *I) computeOp(c context.Context, final bool) (bool, error) {
|
||||
// If the width is not known, we better have a ZeroPage alternative.
|
||||
func (i *I) computeOp(c context.Context) error {
|
||||
// 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))
|
||||
}
|
||||
val, labelMissing, err := i.Exprs[0].CheckedEval(c, i.Line)
|
||||
val, err := i.Exprs[0].Eval(c, i.Line)
|
||||
// A real error
|
||||
if !labelMissing && err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if labelMissing {
|
||||
// Don't know, do care.
|
||||
if final {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return false, nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we got here, we got an actual value.
|
||||
@ -340,10 +315,10 @@ func (i *I) computeOp(c context.Context, final bool) (bool, error) {
|
||||
curr := c.GetAddr()
|
||||
offset := int32(val) - (int32(curr) + 2)
|
||||
if offset > 127 {
|
||||
return false, i.Errorf("%s cannot jump forward %d (max 127) from $%04x to $%04x", i.Command, offset, curr+2, val)
|
||||
return i.Errorf("%s cannot jump forward %d (max 127) from $%04x to $%04x", i.Command, offset, curr+2, val)
|
||||
}
|
||||
if offset < -128 {
|
||||
return false, i.Errorf("%s cannot jump back %d (max -128) from $%04x to $%04x", i.Command, offset, curr+2, val)
|
||||
return i.Errorf("%s cannot jump back %d (max -128) from $%04x to $%04x", i.Command, offset, curr+2, val)
|
||||
}
|
||||
val = uint16(offset)
|
||||
}
|
||||
@ -359,7 +334,7 @@ func (i *I) computeOp(c context.Context, final bool) (bool, error) {
|
||||
default:
|
||||
panic(fmt.Sprintf("computeOp reached erroneously for '%s'", i.Command))
|
||||
}
|
||||
return true, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i I) Errorf(format string, a ...interface{}) error {
|
||||
|
Loading…
x
Reference in New Issue
Block a user