mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-18 21:14:31 -04:00
feat(compiler): Add support for targeting WebAssembly.
The working principle is similar as before with x86, but instead of outputting .asm, it outputs .wat. This can be compiled into .wasm by using the wat2wasm assembler.
This commit is contained in:
@ -21,7 +21,15 @@ type Compiler struct {
|
||||
// New returns a new compiler using the default .asm templates
|
||||
func New(os string, arch string) (*Compiler, error) {
|
||||
_, myname, _, _ := runtime.Caller(0)
|
||||
templateDir := filepath.Join(path.Dir(myname), "..", "templates")
|
||||
var subdir string
|
||||
if arch == "386" || arch == "amd64" {
|
||||
subdir = "amd64-386"
|
||||
} else if arch == "wasm" {
|
||||
subdir = "wasm"
|
||||
} else {
|
||||
return nil, fmt.Errorf("compiler.New failed, because only amd64, 386 and wasm archs are supported (targeted architecture was %v)", arch)
|
||||
}
|
||||
templateDir := filepath.Join(path.Dir(myname), "..", "templates", subdir)
|
||||
compiler, err := NewFromTemplates(os, arch, templateDir)
|
||||
return compiler, err
|
||||
}
|
||||
@ -43,9 +51,16 @@ func (com *Compiler) Library() (map[string]string, error) {
|
||||
features := AllFeatures{}
|
||||
retmap := map[string]string{}
|
||||
for _, templateName := range templates {
|
||||
macros := NewMacros(*com, features)
|
||||
macros.Library = true
|
||||
populatedTemplate, extension, err := com.compile(templateName, macros)
|
||||
compilerMacros := *NewCompilerMacros(*com)
|
||||
compilerMacros.Library = true
|
||||
featureSetMacros := FeatureSetMacros{features}
|
||||
x86Macros := *NewX86Macros(com.OS, com.Arch == "amd64", features, false)
|
||||
data := struct {
|
||||
CompilerMacros
|
||||
FeatureSetMacros
|
||||
X86Macros
|
||||
}{compilerMacros, featureSetMacros, x86Macros}
|
||||
populatedTemplate, extension, err := com.compile(templateName, &data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`could not execute template "%v": %v`, templateName, err)
|
||||
}
|
||||
@ -55,10 +70,15 @@ func (com *Compiler) Library() (map[string]string, error) {
|
||||
}
|
||||
|
||||
func (com *Compiler) Song(song *sointu.Song) (map[string]string, error) {
|
||||
if com.Arch != "386" && com.Arch != "amd64" {
|
||||
return nil, fmt.Errorf(`compiling a song player is supported only on 386 and amd64 architectures (targeted architecture was %v)`, com.Arch)
|
||||
if com.Arch != "386" && com.Arch != "amd64" && com.Arch != "wasm" {
|
||||
return nil, fmt.Errorf(`compiling a song player is supported only on 386, amd64 and wasm architectures (targeted architecture was %v)`, com.Arch)
|
||||
}
|
||||
var templates []string
|
||||
if com.Arch == "386" || com.Arch == "amd64" {
|
||||
templates = []string{"player.asm", "player.h"}
|
||||
} else if com.Arch == "wasm" {
|
||||
templates = []string{"player.wat"}
|
||||
}
|
||||
templates := []string{"player.asm", "player.h"}
|
||||
features := NecessaryFeaturesFor(song.Patch)
|
||||
retmap := map[string]string{}
|
||||
encodedPatch, err := Encode(&song.Patch, features)
|
||||
@ -66,8 +86,32 @@ func (com *Compiler) Song(song *sointu.Song) (map[string]string, error) {
|
||||
return nil, fmt.Errorf(`could not encode patch: %v`, err)
|
||||
}
|
||||
for _, templateName := range templates {
|
||||
macros := NewPlayerMacros(*com, features, song, encodedPatch)
|
||||
populatedTemplate, extension, err := com.compile(templateName, macros)
|
||||
compilerMacros := *NewCompilerMacros(*com)
|
||||
featureSetMacros := FeatureSetMacros{features}
|
||||
songMacros := *NewSongMacros(song)
|
||||
var populatedTemplate, extension string
|
||||
var err error
|
||||
if com.Arch == "386" || com.Arch == "amd64" {
|
||||
x86Macros := *NewX86Macros(com.OS, com.Arch == "amd64", features, false)
|
||||
data := struct {
|
||||
CompilerMacros
|
||||
FeatureSetMacros
|
||||
X86Macros
|
||||
SongMacros
|
||||
*EncodedPatch
|
||||
}{compilerMacros, featureSetMacros, x86Macros, songMacros, encodedPatch}
|
||||
populatedTemplate, extension, err = com.compile(templateName, &data)
|
||||
} else if com.Arch == "wasm" {
|
||||
wasmMacros := *NewWasmMacros()
|
||||
data := struct {
|
||||
CompilerMacros
|
||||
FeatureSetMacros
|
||||
WasmMacros
|
||||
SongMacros
|
||||
*EncodedPatch
|
||||
}{compilerMacros, featureSetMacros, wasmMacros, songMacros, encodedPatch}
|
||||
populatedTemplate, extension, err = com.compile(templateName, &data)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`could not execute template "%v": %v`, templateName, err)
|
||||
}
|
||||
|
28
compiler/compiler_macros.go
Normal file
28
compiler/compiler_macros.go
Normal file
@ -0,0 +1,28 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"github.com/vsariola/sointu"
|
||||
)
|
||||
|
||||
type CompilerMacros struct {
|
||||
Clip bool
|
||||
Library bool
|
||||
|
||||
Sine int // TODO: how can we elegantly access global constants in template, without wrapping each one by one
|
||||
Trisaw int
|
||||
Pulse int
|
||||
Gate int
|
||||
Sample int
|
||||
Compiler
|
||||
}
|
||||
|
||||
func NewCompilerMacros(c Compiler) *CompilerMacros {
|
||||
return &CompilerMacros{
|
||||
Sine: sointu.Sine,
|
||||
Trisaw: sointu.Trisaw,
|
||||
Pulse: sointu.Pulse,
|
||||
Gate: sointu.Gate,
|
||||
Sample: sointu.Sample,
|
||||
Compiler: c,
|
||||
}
|
||||
}
|
27
compiler/featureset_macros.go
Normal file
27
compiler/featureset_macros.go
Normal file
@ -0,0 +1,27 @@
|
||||
package compiler
|
||||
|
||||
type FeatureSetMacros struct {
|
||||
FeatureSet
|
||||
}
|
||||
|
||||
func (p *FeatureSetMacros) HasOp(instruction string) bool {
|
||||
_, ok := p.Opcode(instruction)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (p *FeatureSetMacros) GetOp(instruction string) int {
|
||||
v, _ := p.Opcode(instruction)
|
||||
return v
|
||||
}
|
||||
|
||||
func (p *FeatureSetMacros) Stereo(unitType string) bool {
|
||||
return p.SupportsParamValue(unitType, "stereo", 1)
|
||||
}
|
||||
|
||||
func (p *FeatureSetMacros) Mono(unitType string) bool {
|
||||
return p.SupportsParamValue(unitType, "stereo", 0)
|
||||
}
|
||||
|
||||
func (p *FeatureSetMacros) StereoAndMono(unitType string) bool {
|
||||
return p.Stereo(unitType) && p.Mono(unitType)
|
||||
}
|
39
compiler/song_macros.go
Normal file
39
compiler/song_macros.go
Normal file
@ -0,0 +1,39 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/vsariola/sointu"
|
||||
)
|
||||
|
||||
type SongMacros struct {
|
||||
Song *sointu.Song
|
||||
VoiceTrackBitmask int
|
||||
MaxSamples int
|
||||
}
|
||||
|
||||
func NewSongMacros(s *sointu.Song) *SongMacros {
|
||||
maxSamples := s.SamplesPerRow() * s.TotalRows()
|
||||
p := SongMacros{Song: s, MaxSamples: maxSamples}
|
||||
trackVoiceNumber := 0
|
||||
for _, t := range s.Tracks {
|
||||
for b := 0; b < t.NumVoices-1; b++ {
|
||||
p.VoiceTrackBitmask += 1 << trackVoiceNumber
|
||||
trackVoiceNumber++
|
||||
}
|
||||
trackVoiceNumber++ // set all bits except last one
|
||||
}
|
||||
return &p
|
||||
}
|
||||
|
||||
func (p *SongMacros) NumDelayLines() string {
|
||||
total := 0
|
||||
for _, instr := range p.Song.Patch.Instruments {
|
||||
for _, unit := range instr.Units {
|
||||
if unit.Type == "delay" {
|
||||
total += unit.Parameters["count"] * (1 + unit.Parameters["stereo"])
|
||||
}
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%v", total)
|
||||
}
|
50
compiler/wasm_macros.go
Normal file
50
compiler/wasm_macros.go
Normal file
@ -0,0 +1,50 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
type WasmMacros struct {
|
||||
data *bytes.Buffer
|
||||
Labels map[string]int
|
||||
}
|
||||
|
||||
func NewWasmMacros() *WasmMacros {
|
||||
return &WasmMacros{
|
||||
data: new(bytes.Buffer),
|
||||
Labels: map[string]int{},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *WasmMacros) SetLabel(label string) string {
|
||||
wm.Labels[label] = wm.data.Len()
|
||||
return ""
|
||||
}
|
||||
|
||||
func (wm *WasmMacros) GetLabel(label string) int {
|
||||
return wm.Labels[label]
|
||||
}
|
||||
|
||||
func (wm *WasmMacros) DataB(value byte) string {
|
||||
binary.Write(wm.data, binary.LittleEndian, value)
|
||||
return ""
|
||||
}
|
||||
|
||||
func (wm *WasmMacros) DataW(value uint16) string {
|
||||
binary.Write(wm.data, binary.LittleEndian, value)
|
||||
return ""
|
||||
}
|
||||
|
||||
func (wm *WasmMacros) DataD(value uint32) string {
|
||||
binary.Write(wm.data, binary.LittleEndian, value)
|
||||
return ""
|
||||
}
|
||||
|
||||
func (wm *WasmMacros) ToByte(value int) byte {
|
||||
return byte(value)
|
||||
}
|
||||
|
||||
func (wm *WasmMacros) Data() []byte {
|
||||
return wm.data.Bytes()
|
||||
}
|
@ -4,74 +4,36 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/vsariola/sointu"
|
||||
)
|
||||
|
||||
type OplistEntry struct {
|
||||
Type string
|
||||
NumParams int
|
||||
}
|
||||
|
||||
type Macros struct {
|
||||
type X86Macros struct {
|
||||
Stacklocs []string
|
||||
Output16Bit bool
|
||||
Clip bool
|
||||
Library bool
|
||||
Amd64 bool
|
||||
OS string
|
||||
DisableSections bool
|
||||
Sine int // TODO: how can we elegantly access global constants in template, without wrapping each one by one
|
||||
Trisaw int
|
||||
Pulse int
|
||||
Gate int
|
||||
Sample int
|
||||
usesFloatConst map[float32]bool
|
||||
usesIntConst map[int]bool
|
||||
floatConsts []float32
|
||||
intConsts []int
|
||||
calls map[string]bool
|
||||
stackframes map[string][]string
|
||||
FeatureSet
|
||||
Compiler
|
||||
features FeatureSet
|
||||
}
|
||||
|
||||
func NewMacros(c Compiler, f FeatureSet) *Macros {
|
||||
return &Macros{
|
||||
calls: map[string]bool{},
|
||||
usesFloatConst: map[float32]bool{},
|
||||
usesIntConst: map[int]bool{},
|
||||
stackframes: map[string][]string{},
|
||||
Sine: sointu.Sine,
|
||||
Trisaw: sointu.Trisaw,
|
||||
Pulse: sointu.Pulse,
|
||||
Gate: sointu.Gate,
|
||||
Sample: sointu.Sample,
|
||||
Amd64: c.Arch == "amd64",
|
||||
Compiler: c,
|
||||
FeatureSet: f,
|
||||
func NewX86Macros(os string, Amd64 bool, features FeatureSet, DisableSections bool) *X86Macros {
|
||||
return &X86Macros{
|
||||
calls: map[string]bool{},
|
||||
usesFloatConst: map[float32]bool{},
|
||||
usesIntConst: map[int]bool{},
|
||||
stackframes: map[string][]string{},
|
||||
Amd64: Amd64,
|
||||
OS: os,
|
||||
DisableSections: DisableSections,
|
||||
features: features,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Macros) HasOp(instruction string) bool {
|
||||
_, ok := p.Opcode(instruction)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (p *Macros) Stereo(unitType string) bool {
|
||||
return p.SupportsParamValue(unitType, "stereo", 1)
|
||||
}
|
||||
|
||||
func (p *Macros) Mono(unitType string) bool {
|
||||
return p.SupportsParamValue(unitType, "stereo", 0)
|
||||
}
|
||||
|
||||
func (p *Macros) StereoAndMono(unitType string) bool {
|
||||
return p.Stereo(unitType) && p.Mono(unitType)
|
||||
}
|
||||
|
||||
// Macros and functions to accumulate constants automagically
|
||||
|
||||
func (p *Macros) Float(value float32) string {
|
||||
func (p *X86Macros) Float(value float32) string {
|
||||
if _, ok := p.usesFloatConst[value]; !ok {
|
||||
p.usesFloatConst[value] = true
|
||||
p.floatConsts = append(p.floatConsts, value)
|
||||
@ -79,7 +41,7 @@ func (p *Macros) Float(value float32) string {
|
||||
return nameForFloat(value)
|
||||
}
|
||||
|
||||
func (p *Macros) Int(value int) string {
|
||||
func (p *X86Macros) Int(value int) string {
|
||||
if _, ok := p.usesIntConst[value]; !ok {
|
||||
p.usesIntConst[value] = true
|
||||
p.intConsts = append(p.intConsts, value)
|
||||
@ -87,7 +49,7 @@ func (p *Macros) Int(value int) string {
|
||||
return nameForInt(value)
|
||||
}
|
||||
|
||||
func (p *Macros) Constants() string {
|
||||
func (p *X86Macros) Constants() string {
|
||||
var b strings.Builder
|
||||
for _, v := range p.floatConsts {
|
||||
fmt.Fprintf(&b, "%-23s dd 0x%x\n", nameForFloat(v), math.Float32bits(v))
|
||||
@ -110,105 +72,105 @@ func nameForInt(value int) string {
|
||||
return "ICONST_" + fmt.Sprintf("%d", value)
|
||||
}
|
||||
|
||||
func (p *Macros) PTRSIZE() int {
|
||||
func (p *X86Macros) PTRSIZE() int {
|
||||
if p.Amd64 {
|
||||
return 8
|
||||
}
|
||||
return 4
|
||||
}
|
||||
|
||||
func (p *Macros) DPTR() string {
|
||||
func (p *X86Macros) DPTR() string {
|
||||
if p.Amd64 {
|
||||
return "dq"
|
||||
}
|
||||
return "dd"
|
||||
}
|
||||
|
||||
func (p *Macros) PTRWORD() string {
|
||||
func (p *X86Macros) PTRWORD() string {
|
||||
if p.Amd64 {
|
||||
return "qword"
|
||||
}
|
||||
return "dword"
|
||||
}
|
||||
|
||||
func (p *Macros) AX() string {
|
||||
func (p *X86Macros) AX() string {
|
||||
if p.Amd64 {
|
||||
return "rax"
|
||||
}
|
||||
return "eax"
|
||||
}
|
||||
|
||||
func (p *Macros) BX() string {
|
||||
func (p *X86Macros) BX() string {
|
||||
if p.Amd64 {
|
||||
return "rbx"
|
||||
}
|
||||
return "ebx"
|
||||
}
|
||||
|
||||
func (p *Macros) CX() string {
|
||||
func (p *X86Macros) CX() string {
|
||||
if p.Amd64 {
|
||||
return "rcx"
|
||||
}
|
||||
return "ecx"
|
||||
}
|
||||
|
||||
func (p *Macros) DX() string {
|
||||
func (p *X86Macros) DX() string {
|
||||
if p.Amd64 {
|
||||
return "rdx"
|
||||
}
|
||||
return "edx"
|
||||
}
|
||||
|
||||
func (p *Macros) SI() string {
|
||||
func (p *X86Macros) SI() string {
|
||||
if p.Amd64 {
|
||||
return "rsi"
|
||||
}
|
||||
return "esi"
|
||||
}
|
||||
|
||||
func (p *Macros) DI() string {
|
||||
func (p *X86Macros) DI() string {
|
||||
if p.Amd64 {
|
||||
return "rdi"
|
||||
}
|
||||
return "edi"
|
||||
}
|
||||
|
||||
func (p *Macros) SP() string {
|
||||
func (p *X86Macros) SP() string {
|
||||
if p.Amd64 {
|
||||
return "rsp"
|
||||
}
|
||||
return "esp"
|
||||
}
|
||||
|
||||
func (p *Macros) BP() string {
|
||||
func (p *X86Macros) BP() string {
|
||||
if p.Amd64 {
|
||||
return "rbp"
|
||||
}
|
||||
return "ebp"
|
||||
}
|
||||
|
||||
func (p *Macros) WRK() string {
|
||||
func (p *X86Macros) WRK() string {
|
||||
return p.BP()
|
||||
}
|
||||
|
||||
func (p *Macros) VAL() string {
|
||||
func (p *X86Macros) VAL() string {
|
||||
return p.SI()
|
||||
}
|
||||
|
||||
func (p *Macros) COM() string {
|
||||
func (p *X86Macros) COM() string {
|
||||
return p.BX()
|
||||
}
|
||||
|
||||
func (p *Macros) INP() string {
|
||||
func (p *X86Macros) INP() string {
|
||||
return p.DX()
|
||||
}
|
||||
|
||||
func (p *Macros) SaveStack(scope string) string {
|
||||
func (p *X86Macros) SaveStack(scope string) string {
|
||||
p.stackframes[scope] = p.Stacklocs
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *Macros) Call(funcname string) (string, error) {
|
||||
func (p *X86Macros) Call(funcname string) (string, error) {
|
||||
p.calls[funcname] = true
|
||||
var s = make([]string, len(p.Stacklocs))
|
||||
copy(s, p.Stacklocs)
|
||||
@ -216,13 +178,13 @@ func (p *Macros) Call(funcname string) (string, error) {
|
||||
return "call " + funcname, nil
|
||||
}
|
||||
|
||||
func (p *Macros) TailCall(funcname string) (string, error) {
|
||||
func (p *X86Macros) TailCall(funcname string) (string, error) {
|
||||
p.calls[funcname] = true
|
||||
p.stackframes[funcname] = p.Stacklocs
|
||||
return "jmp " + funcname, nil
|
||||
}
|
||||
|
||||
func (p *Macros) SectText(name string) string {
|
||||
func (p *X86Macros) SectText(name string) string {
|
||||
if p.OS == "windows" {
|
||||
if p.DisableSections {
|
||||
return "section .code align=1"
|
||||
@ -238,7 +200,7 @@ func (p *Macros) SectText(name string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Macros) SectData(name string) string {
|
||||
func (p *X86Macros) SectData(name string) string {
|
||||
if p.OS == "windows" || p.OS == "darwin" {
|
||||
if p.OS == "windows" && !p.DisableSections {
|
||||
return fmt.Sprintf("section .%v data align=1", name)
|
||||
@ -252,7 +214,7 @@ func (p *Macros) SectData(name string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Macros) SectBss(name string) string {
|
||||
func (p *X86Macros) SectBss(name string) string {
|
||||
if p.OS == "windows" || p.OS == "darwin" {
|
||||
if p.OS == "windows" && !p.DisableSections {
|
||||
return fmt.Sprintf("section .%v bss align=256", name)
|
||||
@ -266,11 +228,11 @@ func (p *Macros) SectBss(name string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Macros) Data(label string) string {
|
||||
func (p *X86Macros) Data(label string) string {
|
||||
return fmt.Sprintf("%v\n%v:", p.SectData(label), label)
|
||||
}
|
||||
|
||||
func (p *Macros) Func(funcname string, scope ...string) (string, error) {
|
||||
func (p *X86Macros) Func(funcname string, scope ...string) (string, error) {
|
||||
scopeName := funcname
|
||||
if len(scope) > 1 {
|
||||
return "", fmt.Errorf(`Func macro "%v" can take only one additional scope parameter, "%v" were given`, funcname, scope)
|
||||
@ -281,16 +243,16 @@ func (p *Macros) Func(funcname string, scope ...string) (string, error) {
|
||||
return fmt.Sprintf("%v\n%v:", p.SectText(funcname), funcname), nil
|
||||
}
|
||||
|
||||
func (p *Macros) HasCall(funcname string) bool {
|
||||
func (p *X86Macros) HasCall(funcname string) bool {
|
||||
return p.calls[funcname]
|
||||
}
|
||||
|
||||
func (p *Macros) Push(value string, name string) string {
|
||||
func (p *X86Macros) Push(value string, name string) string {
|
||||
p.Stacklocs = append(p.Stacklocs, name)
|
||||
return fmt.Sprintf("push %v ; Stack: %v ", value, p.FmtStack())
|
||||
}
|
||||
|
||||
func (p *Macros) PushRegs(params ...string) string {
|
||||
func (p *X86Macros) PushRegs(params ...string) string {
|
||||
if p.Amd64 {
|
||||
var b strings.Builder
|
||||
for i := 0; i < len(params); i = i + 2 {
|
||||
@ -312,7 +274,7 @@ func (p *Macros) PushRegs(params ...string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Macros) PopRegs(params ...string) string {
|
||||
func (p *X86Macros) PopRegs(params ...string) string {
|
||||
if p.Amd64 {
|
||||
var b strings.Builder
|
||||
for i := len(params) - 1; i >= 0; i-- {
|
||||
@ -338,13 +300,13 @@ func (p *Macros) PopRegs(params ...string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Macros) Pop(register string) string {
|
||||
func (p *X86Macros) Pop(register string) string {
|
||||
last := p.Stacklocs[len(p.Stacklocs)-1]
|
||||
p.Stacklocs = p.Stacklocs[:len(p.Stacklocs)-1]
|
||||
return fmt.Sprintf("pop %v ; %v = %v, Stack: %v ", register, register, last, p.FmtStack())
|
||||
}
|
||||
|
||||
func (p *Macros) SaveFPUState() string {
|
||||
func (p *X86Macros) SaveFPUState() string {
|
||||
i := 0
|
||||
for ; i < 108; i += p.PTRSIZE() {
|
||||
p.Stacklocs = append(p.Stacklocs, fmt.Sprintf("F%v", i))
|
||||
@ -352,7 +314,7 @@ func (p *Macros) SaveFPUState() string {
|
||||
return fmt.Sprintf("sub %[1]v, %[2]v\nfsave [%[1]v]", p.SP(), i)
|
||||
}
|
||||
|
||||
func (p *Macros) LoadFPUState() string {
|
||||
func (p *X86Macros) LoadFPUState() string {
|
||||
i := 0
|
||||
for ; i < 108; i += p.PTRSIZE() {
|
||||
p.Stacklocs = p.Stacklocs[:len(p.Stacklocs)-1]
|
||||
@ -360,7 +322,7 @@ func (p *Macros) LoadFPUState() string {
|
||||
return fmt.Sprintf("frstor [%[1]v]\nadd %[1]v, %[2]v", p.SP(), i)
|
||||
}
|
||||
|
||||
func (p *Macros) Stack(name string) (string, error) {
|
||||
func (p *X86Macros) Stack(name string) (string, error) {
|
||||
for i, k := range p.Stacklocs {
|
||||
if k == name {
|
||||
pos := len(p.Stacklocs) - i - 1
|
||||
@ -378,7 +340,7 @@ func (p *Macros) Stack(name string) (string, error) {
|
||||
return "", fmt.Errorf("unknown symbol %v", name)
|
||||
}
|
||||
|
||||
func (p *Macros) FmtStack() string {
|
||||
func (p *X86Macros) FmtStack() string {
|
||||
var b strings.Builder
|
||||
last := len(p.Stacklocs) - 1
|
||||
for i := range p.Stacklocs {
|
||||
@ -390,7 +352,7 @@ func (p *Macros) FmtStack() string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (p *Macros) ExportFunc(name string, params ...string) string {
|
||||
func (p *X86Macros) ExportFunc(name string, params ...string) string {
|
||||
if !p.Amd64 {
|
||||
reverseParams := make([]string, len(params))
|
||||
for i, param := range params {
|
||||
@ -407,20 +369,20 @@ func (p *Macros) ExportFunc(name string, params ...string) string {
|
||||
return fmt.Sprintf("%[1]v\nglobal %[2]v\n%[2]v:", p.SectText(name), name)
|
||||
}
|
||||
|
||||
func (p *Macros) Input(unit string, port string) (string, error) {
|
||||
i := p.InputNumber(unit, port)
|
||||
func (p *X86Macros) Input(unit string, port string) (string, error) {
|
||||
i := p.features.InputNumber(unit, port)
|
||||
if i != 0 {
|
||||
return fmt.Sprintf("%v + %v", p.INP(), i*4), nil
|
||||
}
|
||||
return p.INP(), nil
|
||||
}
|
||||
|
||||
func (p *Macros) Modulation(unit string, port string) (string, error) {
|
||||
i := p.InputNumber(unit, port)
|
||||
func (p *X86Macros) Modulation(unit string, port string) (string, error) {
|
||||
i := p.features.InputNumber(unit, port)
|
||||
return fmt.Sprintf("%v + %v", p.WRK(), i*4+32), nil
|
||||
}
|
||||
|
||||
func (p *Macros) Prepare(value string, regs ...string) (string, error) {
|
||||
func (p *X86Macros) Prepare(value string, regs ...string) (string, error) {
|
||||
if p.Amd64 {
|
||||
if len(regs) > 1 {
|
||||
return "", fmt.Errorf("macro Prepare cannot accept more than one register parameter")
|
||||
@ -432,7 +394,7 @@ func (p *Macros) Prepare(value string, regs ...string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (p *Macros) Use(value string, regs ...string) (string, error) {
|
||||
func (p *X86Macros) Use(value string, regs ...string) (string, error) {
|
||||
if p.Amd64 {
|
||||
return "r9", nil
|
||||
}
|
||||
@ -443,39 +405,3 @@ func (p *Macros) Use(value string, regs ...string) (string, error) {
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
type PlayerMacros struct {
|
||||
Song *sointu.Song
|
||||
VoiceTrackBitmask int
|
||||
MaxSamples int
|
||||
Macros
|
||||
EncodedPatch
|
||||
}
|
||||
|
||||
func NewPlayerMacros(c Compiler, f FeatureSet, s *sointu.Song, e *EncodedPatch) *PlayerMacros {
|
||||
maxSamples := s.SamplesPerRow() * s.TotalRows()
|
||||
macros := *NewMacros(c, f)
|
||||
macros.Output16Bit = s.Output16Bit // TODO: should we actually store output16bit in Songs or not?
|
||||
p := PlayerMacros{Song: s, Macros: macros, MaxSamples: maxSamples, EncodedPatch: *e}
|
||||
trackVoiceNumber := 0
|
||||
for _, t := range s.Tracks {
|
||||
for b := 0; b < t.NumVoices-1; b++ {
|
||||
p.VoiceTrackBitmask += 1 << trackVoiceNumber
|
||||
trackVoiceNumber++
|
||||
}
|
||||
trackVoiceNumber++ // set all bits except last one
|
||||
}
|
||||
return &p
|
||||
}
|
||||
|
||||
func (p *PlayerMacros) NumDelayLines() string {
|
||||
total := 0
|
||||
for _, instr := range p.Song.Patch.Instruments {
|
||||
for _, unit := range instr.Units {
|
||||
if unit.Type == "delay" {
|
||||
total += unit.Parameters["count"] * (1 + unit.Parameters["stereo"])
|
||||
}
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%v", total)
|
||||
}
|
Reference in New Issue
Block a user