Implemented instruction lists

This commit is contained in:
2023-10-21 17:46:20 +02:00
parent 4967719902
commit a54c62f6e0
12 changed files with 165 additions and 23 deletions

23
src/asm/Base.go Normal file
View File

@ -0,0 +1,23 @@
package asm
import (
"io"
"git.akyoto.dev/cli/q/src/asm/x64"
)
// Base represents the data that is common among all instructions.
type Base struct {
Mnemonic Mnemonic
}
func (x *Base) Write(w io.ByteWriter) {
switch x.Mnemonic {
case SYSCALL:
x64.Syscall(w)
}
}
func (x *Base) String() string {
return x.Mnemonic.String()
}

8
src/asm/Instruction.go Normal file
View File

@ -0,0 +1,8 @@
package asm
import "io"
type Instruction interface {
Write(io.ByteWriter)
String() string
}

View File

@ -0,0 +1,47 @@
package asm
import (
"fmt"
"git.akyoto.dev/cli/q/src/register"
)
type InstructionList struct {
Instructions []Instruction
}
// Finalize generates the final assembly code.
func (list *InstructionList) Finalize() *Result {
final := Result{}
for _, instr := range list.Instructions {
instr.Write(&final.Code)
fmt.Println(instr.String())
}
return &final
}
func (list *InstructionList) MoveRegisterNumber(reg register.Register, number uint64) {
list.addRegisterNumber(MOV, reg, number)
}
func (list *InstructionList) Syscall() {
list.add(SYSCALL)
}
// add adds an instruction without any operands.
func (list *InstructionList) add(mnemonic Mnemonic) {
list.Instructions = append(list.Instructions, &Base{Mnemonic: mnemonic})
}
// addRegisterNumber adds an instruction using a register and a number.
func (list *InstructionList) addRegisterNumber(mnemonic Mnemonic, reg register.Register, number uint64) {
list.Instructions = append(list.Instructions, &RegisterNumber{
Base: Base{
Mnemonic: mnemonic,
},
Register: reg,
Number: number,
})
}

21
src/asm/Mnemonic.go Normal file
View File

@ -0,0 +1,21 @@
package asm
type Mnemonic uint8
const (
NONE Mnemonic = iota
MOV
SYSCALL
)
func (m Mnemonic) String() string {
switch m {
case MOV:
return "mov"
case SYSCALL:
return "syscall"
}
return "NONE"
}

26
src/asm/RegisterNumber.go Normal file
View File

@ -0,0 +1,26 @@
package asm
import (
"fmt"
"io"
"git.akyoto.dev/cli/q/src/asm/x64"
"git.akyoto.dev/cli/q/src/register"
)
type RegisterNumber struct {
Base
Register register.Register
Number uint64
}
func (x *RegisterNumber) Write(w io.ByteWriter) {
switch x.Mnemonic {
case MOV:
x64.MoveRegNum32(w, uint8(x.Register), uint32(x.Number))
}
}
func (x *RegisterNumber) String() string {
return fmt.Sprintf("%s %s, %x", x.Mnemonic, x.Register, x.Number)
}

View File

@ -2,7 +2,7 @@ package asm
import "bytes"
type Assembler struct {
type Result struct {
Code bytes.Buffer
Data bytes.Buffer
}

View File

@ -2,7 +2,7 @@ package x64
import "io"
// AppendUint32 appends a 32 bit number in Little Endian to the given writer.
// AppendUint32 appends a 32 bit integer in Little Endian to the given writer.
func AppendUint32(w io.ByteWriter, number uint32) {
w.WriteByte(byte(number))
w.WriteByte(byte(number >> 8))

View File

@ -4,7 +4,8 @@ import (
"io"
)
func MoveRegNum32(w io.ByteWriter, register byte, number uint32) {
// MoveRegNum32 moves a 32 bit integer into the given register.
func MoveRegNum32(w io.ByteWriter, register uint8, number uint32) {
w.WriteByte(0xb8 + register)
AppendUint32(w, number)
}

View File

@ -4,6 +4,7 @@ import (
"io"
)
// Syscall is the primary way to communicate with the OS kernel.
func Syscall(w io.ByteWriter) {
w.WriteByte(0x0f)
w.WriteByte(0x05)