Reorganized file structure
This commit is contained in:
parent
8b595ef3ce
commit
722d07c321
57 changed files with 431 additions and 614 deletions
66
src/build/asm/Assembler.go
Normal file
66
src/build/asm/Assembler.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
package asm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/build/arch/x64"
|
||||
"git.akyoto.dev/cli/q/src/build/config"
|
||||
)
|
||||
|
||||
// Assembler contains a list of instructions.
|
||||
type Assembler struct {
|
||||
Instructions []Instruction
|
||||
}
|
||||
|
||||
// New creates a new assembler.
|
||||
func New() *Assembler {
|
||||
return &Assembler{
|
||||
Instructions: make([]Instruction, 0, 8),
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize generates the final machine code.
|
||||
func (a *Assembler) Finalize() ([]byte, []byte) {
|
||||
code := make([]byte, 0, len(a.Instructions)*8)
|
||||
data := make([]byte, 0, 16)
|
||||
pointers := []Pointer{}
|
||||
|
||||
for _, x := range a.Instructions {
|
||||
switch x.Mnemonic {
|
||||
case MOVE:
|
||||
code = x64.MoveRegNum32(code, uint8(x.Data.(RegisterNumber).Register), uint32(x.Data.(RegisterNumber).Number))
|
||||
|
||||
if x.Data.(RegisterNumber).IsPointer {
|
||||
pointers = append(pointers, Pointer{
|
||||
Position: Address(len(code) - 4),
|
||||
Address: Address(x.Data.(RegisterNumber).Number),
|
||||
})
|
||||
}
|
||||
|
||||
case SYSCALL:
|
||||
code = x64.Syscall(code)
|
||||
}
|
||||
}
|
||||
|
||||
if config.Verbose {
|
||||
for _, x := range a.Instructions {
|
||||
fmt.Println("[asm]", x.String())
|
||||
}
|
||||
}
|
||||
|
||||
dataStart := config.BaseAddress + config.CodeOffset + Address(len(code))
|
||||
|
||||
for _, pointer := range pointers {
|
||||
slice := code[pointer.Position : pointer.Position+4]
|
||||
address := dataStart + pointer.Address
|
||||
binary.LittleEndian.PutUint32(slice, address)
|
||||
}
|
||||
|
||||
return code, data
|
||||
}
|
||||
|
||||
// Merge combines the contents of this assembler with another one.
|
||||
func (a *Assembler) Merge(b *Assembler) {
|
||||
a.Instructions = append(a.Instructions, b.Instructions...)
|
||||
}
|
19
src/build/asm/Instruction.go
Normal file
19
src/build/asm/Instruction.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package asm
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Instruction represents a single instruction which can be converted to machine code.
|
||||
type Instruction struct {
|
||||
Mnemonic Mnemonic
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
// String returns a human readable version.
|
||||
func (x *Instruction) String() string {
|
||||
switch data := x.Data.(type) {
|
||||
case RegisterNumber:
|
||||
return fmt.Sprintf("%s %s, %x", x.Mnemonic, data.Register, data.Number)
|
||||
default:
|
||||
return x.Mnemonic.String()
|
||||
}
|
||||
}
|
32
src/build/asm/Instructions.go
Normal file
32
src/build/asm/Instructions.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package asm
|
||||
|
||||
import "git.akyoto.dev/cli/q/src/build/cpu"
|
||||
|
||||
// MoveRegisterNumber moves a number into the given register.
|
||||
func (a *Assembler) MoveRegisterNumber(reg cpu.Register, number uint64) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: MOVE,
|
||||
Data: RegisterNumber{
|
||||
Register: reg,
|
||||
Number: number,
|
||||
IsPointer: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// MoveRegisterAddress moves an address into the given register.
|
||||
func (a *Assembler) MoveRegisterAddress(reg cpu.Register, address Address) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: MOVE,
|
||||
Data: RegisterNumber{
|
||||
Register: reg,
|
||||
Number: uint64(address),
|
||||
IsPointer: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Syscall executes a kernel function.
|
||||
func (a *Assembler) Syscall() {
|
||||
a.Instructions = append(a.Instructions, Instruction{Mnemonic: SYSCALL})
|
||||
}
|
22
src/build/asm/Mnemonic.go
Normal file
22
src/build/asm/Mnemonic.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package asm
|
||||
|
||||
type Mnemonic uint8
|
||||
|
||||
const (
|
||||
NONE Mnemonic = iota
|
||||
MOVE
|
||||
SYSCALL
|
||||
)
|
||||
|
||||
// String returns a human readable version.
|
||||
func (m Mnemonic) String() string {
|
||||
switch m {
|
||||
case MOVE:
|
||||
return "move"
|
||||
|
||||
case SYSCALL:
|
||||
return "syscall"
|
||||
}
|
||||
|
||||
return "NONE"
|
||||
}
|
12
src/build/asm/Pointer.go
Normal file
12
src/build/asm/Pointer.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package asm
|
||||
|
||||
// Address represents a memory address.
|
||||
type Address = uint32
|
||||
|
||||
// Pointer stores a relative memory address that we can later turn into an absolute one.
|
||||
// Position: The machine code offset where the address was inserted.
|
||||
// Address: The offset inside the section.
|
||||
type Pointer struct {
|
||||
Position uint32
|
||||
Address uint32
|
||||
}
|
10
src/build/asm/RegisterNumber.go
Normal file
10
src/build/asm/RegisterNumber.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
package asm
|
||||
|
||||
import "git.akyoto.dev/cli/q/src/build/cpu"
|
||||
|
||||
// RegisterNumber operates with a register and a number.
|
||||
type RegisterNumber struct {
|
||||
Register cpu.Register
|
||||
Number uint64
|
||||
IsPointer bool
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue