1
0
mirror of https://github.com/zellyn/go6502.git synced 2024-12-27 04:29:27 +00:00

Removed WidthKnown: ParseInstr sets width

This commit is contained in:
Zellyn Hunter 2014-09-08 20:59:14 -07:00
parent ddc6d85b46
commit 072a4521de
9 changed files with 96 additions and 107 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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'

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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 <ONE,<$FFFF,<$FFFF,<TWO",
" DB <THREE,<FOUR",
"THREE = $89ab",
"FOUR = $cdef",
" NOP",
}, nil, "23ffff67abefea", nil, true},
}
for i, tt := range tests {

View File

@ -60,6 +60,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
{mm, " BEQ $2347", "{BEQ/rel $2347}", "f000"},
{mm, " DA $12,$34,$1234", "{data/wle $0012,$0034,$1234}", "120034003412"},
{mm, " DA $1234", "{data/wle $1234}", "3412"},
{mm, " DB <L4,<L5", "{data/b (lsb L4),(lsb L5)}", "deef"},
{mm, " DDB $12,$34,$1234", "{data/wbe $0012,$0034,$1234}", "001200341234"},
{mm, " DFB $12,$34,$1234", "{data/b $0012,$0034,$1234}", "123434"},
{mm, " DFB $34,100,$81A2-$77C4,%1011,>$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

View File

@ -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: