2018-11-21 13:02:18 -06:00
|
|
|
package gen
|
|
|
|
|
|
|
|
|
|
import (
|
2018-11-21 23:06:29 -06:00
|
|
|
"fmt"
|
|
|
|
|
"math"
|
2018-11-23 15:26:19 -06:00
|
|
|
"strconv"
|
2018-11-21 13:02:18 -06:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"github.com/mmcloughlin/avo/internal/inst"
|
|
|
|
|
)
|
|
|
|
|
|
2018-11-24 13:00:27 -08:00
|
|
|
type asmtest struct {
|
2018-11-24 13:47:30 -08:00
|
|
|
cfg Config
|
2018-11-22 16:21:05 -06:00
|
|
|
sym string // reference to the test function symbol
|
|
|
|
|
rel8 string // label to be used for near jumps
|
|
|
|
|
rel32 string // label for far jumps
|
2018-12-02 17:57:12 -08:00
|
|
|
generator
|
2018-11-22 16:21:05 -06:00
|
|
|
}
|
2018-11-21 13:02:18 -06:00
|
|
|
|
2018-11-24 13:47:30 -08:00
|
|
|
func NewAsmTest(cfg Config) Interface {
|
|
|
|
|
return &asmtest{cfg: cfg}
|
2018-11-24 13:00:27 -08:00
|
|
|
}
|
|
|
|
|
|
2018-11-24 14:20:04 -08:00
|
|
|
func (a *asmtest) Generate(is []inst.Instruction) ([]byte, error) {
|
2018-12-02 17:57:12 -08:00
|
|
|
a.Printf("// %s\n\n", a.cfg.GeneratedWarning())
|
2018-11-24 13:47:30 -08:00
|
|
|
|
2018-11-24 13:00:27 -08:00
|
|
|
a.sym = "\u00b7loadertest(SB)"
|
2018-12-02 17:57:12 -08:00
|
|
|
a.Printf("TEXT %s, 0, $0\n", a.sym)
|
2018-11-22 16:21:05 -06:00
|
|
|
|
|
|
|
|
// Define a label for far jumps.
|
2018-12-02 17:57:12 -08:00
|
|
|
a.Printf("rel32:\n")
|
2018-11-24 13:00:27 -08:00
|
|
|
a.rel32 = "rel32"
|
2018-11-21 13:02:18 -06:00
|
|
|
|
2018-11-22 14:12:20 -06:00
|
|
|
counts := map[string]int{}
|
|
|
|
|
|
2018-11-21 13:02:18 -06:00
|
|
|
for _, i := range is {
|
2018-12-02 17:57:12 -08:00
|
|
|
a.Printf("\t// %s %s\n", i.Opcode, i.Summary)
|
2018-11-24 13:00:27 -08:00
|
|
|
if skip, msg := a.skip(i.Opcode); skip {
|
2018-12-02 17:57:12 -08:00
|
|
|
a.Printf("\t// SKIP: %s\n", msg)
|
2018-11-22 14:12:20 -06:00
|
|
|
counts["skip"]++
|
2018-11-21 22:28:55 -06:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-22 16:21:05 -06:00
|
|
|
if i.Opcode[0] == 'J' {
|
|
|
|
|
label := fmt.Sprintf("rel8_%s", strings.ToLower(i.Opcode))
|
2018-12-02 17:57:12 -08:00
|
|
|
a.Printf("%s:\n", label)
|
2018-11-24 13:00:27 -08:00
|
|
|
a.rel8 = label
|
2018-11-22 16:21:05 -06:00
|
|
|
}
|
|
|
|
|
|
2018-11-21 13:02:18 -06:00
|
|
|
for _, f := range i.Forms {
|
2018-11-24 13:00:27 -08:00
|
|
|
as := a.args(i.Opcode, f.Operands)
|
2018-11-21 13:02:18 -06:00
|
|
|
if as == nil {
|
2018-12-02 17:57:12 -08:00
|
|
|
a.Printf("\t// TODO: %s %#v\n", i.Opcode, f.Operands)
|
2018-11-22 14:12:20 -06:00
|
|
|
counts["todo"]++
|
2018-11-21 13:02:18 -06:00
|
|
|
continue
|
|
|
|
|
}
|
2018-12-02 17:57:12 -08:00
|
|
|
a.Printf("\t%s\t%s\n", i.Opcode, strings.Join(as, ", "))
|
2018-11-22 14:12:20 -06:00
|
|
|
counts["total"]++
|
2018-11-21 13:02:18 -06:00
|
|
|
}
|
2018-12-02 17:57:12 -08:00
|
|
|
a.Printf("\n")
|
2018-11-21 13:02:18 -06:00
|
|
|
}
|
|
|
|
|
|
2018-12-02 17:57:12 -08:00
|
|
|
a.Printf("\tRET\n")
|
2018-11-21 13:02:18 -06:00
|
|
|
|
2018-11-22 14:12:20 -06:00
|
|
|
for m, c := range counts {
|
2018-12-02 17:57:12 -08:00
|
|
|
a.Printf("// %s: %d\n", m, c)
|
2018-11-22 14:12:20 -06:00
|
|
|
}
|
|
|
|
|
|
2018-12-02 17:57:12 -08:00
|
|
|
return a.Result()
|
2018-11-21 13:02:18 -06:00
|
|
|
}
|
|
|
|
|
|
2018-11-24 13:00:27 -08:00
|
|
|
func (a asmtest) skip(opcode string) (bool, string) {
|
2018-11-21 23:06:29 -06:00
|
|
|
prefixes := map[string]string{
|
|
|
|
|
"PUSH": "PUSH can produce 'unbalanced PUSH/POP' assembler error",
|
|
|
|
|
"POP": "POP can produce 'unbalanced PUSH/POP' assembler error",
|
|
|
|
|
}
|
|
|
|
|
for p, m := range prefixes {
|
|
|
|
|
if strings.HasPrefix(opcode, p) {
|
|
|
|
|
return true, m
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false, ""
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-24 13:00:27 -08:00
|
|
|
func (a asmtest) args(opcode string, ops []inst.Operand) []string {
|
2018-11-22 16:21:05 -06:00
|
|
|
// Special case for CALL, since it needs a different type of rel32 argument than others.
|
|
|
|
|
if opcode == "CALL" {
|
2018-11-24 13:00:27 -08:00
|
|
|
return []string{a.sym}
|
2018-11-22 16:21:05 -06:00
|
|
|
}
|
|
|
|
|
|
2018-11-21 13:02:18 -06:00
|
|
|
as := make([]string, len(ops))
|
|
|
|
|
for i, op := range ops {
|
2018-11-24 13:00:27 -08:00
|
|
|
a := a.arg(op.Type, i)
|
2018-11-21 13:02:18 -06:00
|
|
|
if a == "" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
as[i] = a
|
|
|
|
|
}
|
|
|
|
|
return as
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// arg generates an argument for an operand of the given type.
|
2018-11-24 13:00:27 -08:00
|
|
|
func (a asmtest) arg(t string, i int) string {
|
2018-11-21 13:02:18 -06:00
|
|
|
m := map[string]string{
|
2018-11-22 14:12:20 -06:00
|
|
|
"1": "$1", // <xs:enumeration value="1" />
|
|
|
|
|
"3": "$3", // <xs:enumeration value="3" />
|
2018-11-22 11:17:46 -06:00
|
|
|
"imm2u": "$3",
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="imm4" />
|
2018-11-22 11:17:46 -06:00
|
|
|
"imm8": fmt.Sprintf("$%d", math.MaxInt8), // <xs:enumeration value="imm8" />
|
|
|
|
|
"imm16": fmt.Sprintf("$%d", math.MaxInt16), // <xs:enumeration value="imm16" />
|
2018-11-21 23:06:29 -06:00
|
|
|
"imm32": fmt.Sprintf("$%d", math.MaxInt32), // <xs:enumeration value="imm32" />
|
|
|
|
|
"imm64": fmt.Sprintf("$%d", math.MaxInt64), // <xs:enumeration value="imm64" />
|
2018-11-22 14:58:31 -06:00
|
|
|
|
2018-11-23 15:26:19 -06:00
|
|
|
"al": "AL", // <xs:enumeration value="al" />
|
|
|
|
|
"cl": "CL", // <xs:enumeration value="cl" />
|
|
|
|
|
"r8": "CH", // <xs:enumeration value="r8" />
|
|
|
|
|
"ax": "AX", // <xs:enumeration value="ax" />
|
|
|
|
|
"r16": "SI", // <xs:enumeration value="r16" />
|
|
|
|
|
"eax": "AX", // <xs:enumeration value="eax" />
|
|
|
|
|
"r32": "DX", // <xs:enumeration value="r32" />
|
|
|
|
|
"rax": "AX", // <xs:enumeration value="rax" />
|
|
|
|
|
"r64": "R15", // <xs:enumeration value="r64" />
|
|
|
|
|
"mm": "M5", // <xs:enumeration value="mm" />
|
|
|
|
|
"xmm0": "X0", // <xs:enumeration value="xmm0" />
|
|
|
|
|
"xmm": "X" + strconv.Itoa(7+i), // <xs:enumeration value="xmm" />
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="xmm{k}" />
|
|
|
|
|
// <xs:enumeration value="xmm{k}{z}" />
|
2018-11-23 15:26:19 -06:00
|
|
|
"ymm": "Y" + strconv.Itoa(3+i), // <xs:enumeration value="ymm" />
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="ymm{k}" />
|
|
|
|
|
// <xs:enumeration value="ymm{k}{z}" />
|
|
|
|
|
// <xs:enumeration value="zmm" />
|
|
|
|
|
// <xs:enumeration value="zmm{k}" />
|
|
|
|
|
// <xs:enumeration value="zmm{k}{z}" />
|
|
|
|
|
// <xs:enumeration value="k" />
|
|
|
|
|
// <xs:enumeration value="k{k}" />
|
|
|
|
|
// <xs:enumeration value="moffs32" />
|
|
|
|
|
// <xs:enumeration value="moffs64" />
|
2018-11-23 15:26:19 -06:00
|
|
|
"m": "0(AX)(CX*2)", // <xs:enumeration value="m" />
|
2018-11-22 14:12:20 -06:00
|
|
|
"m8": "8(AX)(CX*2)", // <xs:enumeration value="m8" />
|
|
|
|
|
"m16": "16(AX)(CX*2)", // <xs:enumeration value="m16" />
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="m16{k}{z}" />
|
2018-11-22 14:12:20 -06:00
|
|
|
"m32": "32(AX)(CX*2)", // <xs:enumeration value="m32" />
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="m32{k}" />
|
|
|
|
|
// <xs:enumeration value="m32{k}{z}" />
|
2018-11-22 14:12:20 -06:00
|
|
|
"m64": "64(AX)(CX*2)", // <xs:enumeration value="m64" />
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="m64{k}" />
|
|
|
|
|
// <xs:enumeration value="m64{k}{z}" />
|
2018-11-22 14:12:20 -06:00
|
|
|
"m128": "128(AX)(CX*2)", // <xs:enumeration value="m128" />
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="m128{k}{z}" />
|
2018-11-22 15:24:28 -06:00
|
|
|
"m256": "256(AX)(CX*2)", // <xs:enumeration value="m256" />
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="m256{k}{z}" />
|
|
|
|
|
// <xs:enumeration value="m512" />
|
|
|
|
|
// <xs:enumeration value="m512{k}{z}" />
|
|
|
|
|
// <xs:enumeration value="m64/m32bcst" />
|
|
|
|
|
// <xs:enumeration value="m128/m32bcst" />
|
|
|
|
|
// <xs:enumeration value="m256/m32bcst" />
|
|
|
|
|
// <xs:enumeration value="m512/m32bcst" />
|
|
|
|
|
// <xs:enumeration value="m128/m64bcst" />
|
|
|
|
|
// <xs:enumeration value="m256/m64bcst" />
|
|
|
|
|
// <xs:enumeration value="m512/m64bcst" />
|
2018-11-23 15:26:19 -06:00
|
|
|
"vm32x": "32(X14*8)", // <xs:enumeration value="vm32x" />
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="vm32x{k}" />
|
2018-11-23 15:31:12 -06:00
|
|
|
"vm64x": "64(X14*8)", // <xs:enumeration value="vm64x" />
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="vm64x{k}" />
|
2018-11-23 15:31:12 -06:00
|
|
|
"vm32y": "32(Y13*8)", // <xs:enumeration value="vm32y" />
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="vm32y{k}" />
|
2018-11-23 15:31:12 -06:00
|
|
|
"vm64y": "64(Y13*8)", // <xs:enumeration value="vm64y" />
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="vm64y{k}" />
|
|
|
|
|
// <xs:enumeration value="vm32z" />
|
|
|
|
|
// <xs:enumeration value="vm32z{k}" />
|
|
|
|
|
// <xs:enumeration value="vm64z" />
|
|
|
|
|
// <xs:enumeration value="vm64z{k}" />
|
2018-11-24 13:00:27 -08:00
|
|
|
"rel8": a.rel8, // <xs:enumeration value="rel8" />
|
|
|
|
|
"rel32": a.rel32, // <xs:enumeration value="rel32" />
|
2018-11-21 13:02:18 -06:00
|
|
|
// <xs:enumeration value="{er}" />
|
|
|
|
|
// <xs:enumeration value="{sae}" />
|
2018-11-22 14:58:31 -06:00
|
|
|
|
|
|
|
|
// Appear unused:
|
|
|
|
|
"r8l": "????", // <xs:enumeration value="r8l" />
|
|
|
|
|
"r16l": "????", // <xs:enumeration value="r16l" />
|
|
|
|
|
"r32l": "????", // <xs:enumeration value="r32l" />
|
2018-11-21 13:02:18 -06:00
|
|
|
}
|
|
|
|
|
return m[t]
|
|
|
|
|
}
|