mirror of
https://github.com/zellyn/go6502.git
synced 2024-06-15 18:29:47 +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
|
return parseErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := a.passInst(&in, false); err != nil {
|
if in.Type == inst.TypeOrg {
|
||||||
return err
|
a.Ctx.SetAddr(in.Addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update address
|
||||||
|
addr := a.Ctx.GetAddr()
|
||||||
|
in.Addr = addr
|
||||||
|
a.Ctx.SetAddr(addr + in.Width)
|
||||||
|
|
||||||
switch in.Type {
|
switch in.Type {
|
||||||
case inst.TypeUnknown:
|
case inst.TypeUnknown:
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
|
@ -200,41 +205,26 @@ func (a *Assembler) initPass() {
|
||||||
a.Ctx.SetAddr(a.Flavor.DefaultOrigin())
|
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
|
// Pass2 performs the second assembly pass. It returns an error for
|
||||||
// any instruction that cannot be finalized.
|
// any instruction that cannot be finalized.
|
||||||
func (a *Assembler) Pass2() error {
|
func (a *Assembler) Pass2() error {
|
||||||
a.initPass()
|
a.initPass()
|
||||||
|
|
||||||
for _, in := range a.Insts {
|
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 {
|
if err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
|
|
|
@ -581,11 +581,11 @@ func (a *Base) ParseEquate(ctx context.Context, in inst.I, lp *lines.Parse) (ins
|
||||||
return in, err
|
return in, err
|
||||||
}
|
}
|
||||||
|
|
||||||
xyzzy, err := expr.Eval(ctx, in.Line)
|
val, err := expr.Eval(ctx, in.Line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return in, err
|
return in, err
|
||||||
}
|
}
|
||||||
_ = xyzzy
|
ctx.Set(in.Label, val)
|
||||||
in.Exprs = append(in.Exprs, expr)
|
in.Exprs = append(in.Exprs, expr)
|
||||||
in.Width = 0
|
in.Width = 0
|
||||||
in.Final = true
|
in.Final = true
|
||||||
|
|
|
@ -248,10 +248,8 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||||
ctx.Set("L5", 0xcdef)
|
ctx.Set("L5", 0xcdef)
|
||||||
|
|
||||||
if in.Type != inst.TypeOrg {
|
if in.Type != inst.TypeOrg {
|
||||||
_, err = in.Compute(ctx, true)
|
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)
|
||||||
if err != nil {
|
|
||||||
t.Errorf(`%d. %s.ParseInstr("%s"): %s.Compute(tt.f, true) => error: %s`, i, tt.f, tt.i, in, err)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,42 +191,36 @@ func (i I) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute attempts to finalize the instruction.
|
// Compute attempts to finalize the instruction.
|
||||||
func (i *I) Compute(c context.Context, final bool) (bool, error) {
|
func (i *I) Compute(c context.Context) error {
|
||||||
// xyzzy - remove
|
|
||||||
if i.Type == TypeOrg {
|
|
||||||
panic("Compute called with TypeOrg")
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
if i.Type == TypeEqu || i.Type == TypeTarget {
|
if i.Type == TypeEqu || i.Type == TypeTarget {
|
||||||
return i.computeMustKnow(c, final)
|
return i.computeMustKnow(c)
|
||||||
}
|
}
|
||||||
if i.Final {
|
if i.Final {
|
||||||
return true, nil
|
return nil
|
||||||
}
|
}
|
||||||
switch i.Type {
|
switch i.Type {
|
||||||
case TypeOp:
|
case TypeOp:
|
||||||
return i.computeOp(c, final)
|
return i.computeOp(c)
|
||||||
case TypeData:
|
case TypeData:
|
||||||
return i.computeData(c, final)
|
return i.computeData(c)
|
||||||
case TypeBlock:
|
case TypeBlock:
|
||||||
return i.computeBlock(c, final)
|
panic("Compute called with TypeBlock")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Everything else is zero-width
|
// Everything else is zero-width
|
||||||
i.Width = 0
|
i.Width = 0
|
||||||
i.Final = true
|
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 {
|
if len(i.Data) > 0 {
|
||||||
i.Width = uint16(len(i.Data))
|
i.Width = uint16(len(i.Data))
|
||||||
i.Final = true
|
i.Final = true
|
||||||
return true, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
allFinal := true
|
|
||||||
data := []byte{}
|
data := []byte{}
|
||||||
var width uint16
|
var width uint16
|
||||||
for _, e := range i.Exprs {
|
for _, e := range i.Exprs {
|
||||||
|
@ -240,15 +234,9 @@ func (i *I) computeData(c context.Context, final bool) (bool, error) {
|
||||||
w = 2
|
w = 2
|
||||||
}
|
}
|
||||||
width += w
|
width += w
|
||||||
val, labelMissing, err := e.CheckedEval(c, i.Line)
|
val, err := e.Eval(c, i.Line)
|
||||||
if err != nil && !labelMissing {
|
if err != nil {
|
||||||
return false, err
|
return err
|
||||||
}
|
|
||||||
if labelMissing {
|
|
||||||
allFinal = false
|
|
||||||
if final {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
switch i.Var {
|
switch i.Var {
|
||||||
case VarMixed:
|
case VarMixed:
|
||||||
|
@ -269,12 +257,9 @@ func (i *I) computeData(c context.Context, final bool) (bool, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i.Width = width
|
i.Width = width
|
||||||
if allFinal {
|
i.Data = data
|
||||||
i.Data = data
|
i.Final = true
|
||||||
i.Final = true
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
return i.Final, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *I) computeBlock(c context.Context, final bool) (bool, error) {
|
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
|
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.Width = 0
|
||||||
i.Final = true
|
i.Final = true
|
||||||
val, err := i.Exprs[0].Eval(c, i.Line)
|
val, err := i.Exprs[0].Eval(c, i.Line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
i.Value = val
|
i.Value = val
|
||||||
switch i.Type {
|
switch i.Type {
|
||||||
case TypeTarget:
|
case TypeTarget:
|
||||||
return false, errors.New("Target not implemented yet.")
|
return errors.New("Target not implemented yet.")
|
||||||
case TypeOrg:
|
case TypeOrg:
|
||||||
c.SetAddr(val)
|
c.SetAddr(val)
|
||||||
case TypeEqu:
|
case TypeEqu:
|
||||||
c.Set(i.Label, val)
|
c.Set(i.Label, val)
|
||||||
// Don't handle labels.
|
// 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) {
|
func (i *I) computeOp(c context.Context) error {
|
||||||
// If the width is not known, we better have a ZeroPage alternative.
|
|
||||||
// An op with no args would be final already, so we must have an Expression.
|
// An op with no args would be final already, so we must have an Expression.
|
||||||
if len(i.Exprs) == 0 {
|
if len(i.Exprs) == 0 {
|
||||||
panic(fmt.Sprintf("Reached computeOp for '%s' with no expressions", i.Command))
|
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
|
// A real error
|
||||||
if !labelMissing && err != nil {
|
if err != nil {
|
||||||
return false, err
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
if labelMissing {
|
|
||||||
// Don't know, do care.
|
|
||||||
if final {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we got here, we got an actual value.
|
// 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()
|
curr := c.GetAddr()
|
||||||
offset := int32(val) - (int32(curr) + 2)
|
offset := int32(val) - (int32(curr) + 2)
|
||||||
if offset > 127 {
|
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 {
|
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)
|
val = uint16(offset)
|
||||||
}
|
}
|
||||||
|
@ -359,7 +334,7 @@ func (i *I) computeOp(c context.Context, final bool) (bool, error) {
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("computeOp reached erroneously for '%s'", i.Command))
|
panic(fmt.Sprintf("computeOp reached erroneously for '%s'", i.Command))
|
||||||
}
|
}
|
||||||
return true, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i I) Errorf(format string, a ...interface{}) error {
|
func (i I) Errorf(format string, a ...interface{}) error {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user