From b018d8de61771cd8954f580f9b208eeca0a77ae3 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Mon, 24 Jun 2024 16:55:15 +0200 Subject: [PATCH] Implemented subtraction --- examples/hello/hello.q | 6 ++-- src/build/Function.go | 10 +++++-- src/build/arch/x64/Add.go | 18 ----------- src/build/arch/x64/Math.go | 15 ++++++++++ src/build/arch/x64/numberToRegister.go | 41 ++++++++++++++++++++++++++ src/build/asm/Assembler.go | 9 ++++-- src/build/asm/Instructions.go | 15 ++++++++-- src/build/asm/Mnemonic.go | 4 +++ src/build/asm/RegisterNumber.go | 2 +- 9 files changed, 92 insertions(+), 28 deletions(-) delete mode 100644 src/build/arch/x64/Add.go create mode 100644 src/build/arch/x64/Math.go create mode 100644 src/build/arch/x64/numberToRegister.go diff --git a/examples/hello/hello.q b/examples/hello/hello.q index 126c5b5..c5324ab 100644 --- a/examples/hello/hello.q +++ b/examples/hello/hello.q @@ -5,11 +5,13 @@ main() { hello() { write := 1 stdout := 1 - address := 4194304 + address := 0 length := 0 + address += 4194304 address += 1 - length += 3 + length += 5 + length -= 2 loop { syscall(write, stdout, address, length) diff --git a/src/build/Function.go b/src/build/Function.go index 2e82577..58e7cee 100644 --- a/src/build/Function.go +++ b/src/build/Function.go @@ -118,7 +118,13 @@ func (f *Function) CompileInstruction(line token.List) error { case "+=": name := expr.Children[0].Token.Text() number, _ := strconv.Atoi(expr.Children[1].Token.Text()) - f.Assembler.AddRegisterNumber(f.Variables[name].Register, uint64(number)) + f.Assembler.AddRegisterNumber(f.Variables[name].Register, number) + return nil + + case "-=": + name := expr.Children[0].Token.Text() + number, _ := strconv.Atoi(expr.Children[1].Token.Text()) + f.Assembler.SubRegisterNumber(f.Variables[name].Register, number) return nil } } @@ -158,7 +164,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error { return err } - f.Assembler.MoveRegisterNumber(register, uint64(n)) + f.Assembler.MoveRegisterNumber(register, n) return nil case token.String: diff --git a/src/build/arch/x64/Add.go b/src/build/arch/x64/Add.go deleted file mode 100644 index 234142b..0000000 --- a/src/build/arch/x64/Add.go +++ /dev/null @@ -1,18 +0,0 @@ -package x64 - -import "git.akyoto.dev/cli/q/src/build/cpu" - -// AddRegNum8 adds a byte to the given register. -func AddRegNum8(code []byte, destination cpu.Register, number uint8) []byte { - if destination >= 8 { - code = append(code, REX(0, 0, 0, 1)) - destination -= 8 - } - - return append( - code, - 0x83, - ModRM(0b11, 0b000, byte(destination)), - byte(number), - ) -} diff --git a/src/build/arch/x64/Math.go b/src/build/arch/x64/Math.go new file mode 100644 index 0000000..92a7137 --- /dev/null +++ b/src/build/arch/x64/Math.go @@ -0,0 +1,15 @@ +package x64 + +import ( + "git.akyoto.dev/cli/q/src/build/cpu" +) + +// AddRegNum adds a number to the given register. +func AddRegNum(code []byte, destination cpu.Register, number int) []byte { + return numberToRegister(0x83, 0x81, 0b000, code, destination, number) +} + +// SubRegNum subtracts a number from the given register. +func SubRegNum(code []byte, destination cpu.Register, number int) []byte { + return numberToRegister(0x83, 0x81, 0b101, code, destination, number) +} diff --git a/src/build/arch/x64/numberToRegister.go b/src/build/arch/x64/numberToRegister.go new file mode 100644 index 0000000..025a2ec --- /dev/null +++ b/src/build/arch/x64/numberToRegister.go @@ -0,0 +1,41 @@ +package x64 + +import ( + "math" + + "git.akyoto.dev/cli/q/src/build/cpu" +) + +// numberToRegister encodes an instruction with a register and a number parameter. +func numberToRegister(opCode8 byte, opCode32 byte, reg byte, code []byte, destination cpu.Register, number int) []byte { + b := byte(0) + + if destination >= 8 { + b = 1 + destination -= 8 + } + + rex := REX(1, 0, 0, b) + modRM := ModRM(0b11, reg, byte(destination)) + + if number >= math.MinInt8 && number <= math.MaxInt8 { + return append( + code, + rex, + opCode8, + modRM, + byte(number), + ) + } + + return append( + code, + rex, + opCode32, + modRM, + byte(number), + byte(number>>8), + byte(number>>16), + byte(number>>24), + ) +} diff --git a/src/build/asm/Assembler.go b/src/build/asm/Assembler.go index 5eb7b2b..6dbb8bd 100644 --- a/src/build/asm/Assembler.go +++ b/src/build/asm/Assembler.go @@ -30,10 +30,13 @@ func (a *Assembler) Finalize() ([]byte, []byte) { case ADD: switch operands := x.Data.(type) { case *RegisterNumber: - code = x64.AddRegNum8(code, operands.Register, uint8(operands.Number)) + code = x64.AddRegNum(code, operands.Register, operands.Number) + } - case *RegisterRegister: - // code = x64.AddRegReg64(code, operands.Destination, operands.Source) + case SUB: + switch operands := x.Data.(type) { + case *RegisterNumber: + code = x64.SubRegNum(code, operands.Register, operands.Number) } case CALL: diff --git a/src/build/asm/Instructions.go b/src/build/asm/Instructions.go index 091b9d4..efd6920 100644 --- a/src/build/asm/Instructions.go +++ b/src/build/asm/Instructions.go @@ -3,7 +3,7 @@ package asm import "git.akyoto.dev/cli/q/src/build/cpu" // AddRegisterNumber adds a number to the given register. -func (a *Assembler) AddRegisterNumber(reg cpu.Register, number uint64) { +func (a *Assembler) AddRegisterNumber(reg cpu.Register, number int) { a.Instructions = append(a.Instructions, Instruction{ Mnemonic: ADD, Data: &RegisterNumber{ @@ -13,8 +13,19 @@ func (a *Assembler) AddRegisterNumber(reg cpu.Register, number uint64) { }) } +// SubRegisterNumber subtracts a number from the given register. +func (a *Assembler) SubRegisterNumber(reg cpu.Register, number int) { + a.Instructions = append(a.Instructions, Instruction{ + Mnemonic: SUB, + Data: &RegisterNumber{ + Register: reg, + Number: number, + }, + }) +} + // MoveRegisterNumber moves a number into the given register. -func (a *Assembler) MoveRegisterNumber(reg cpu.Register, number uint64) { +func (a *Assembler) MoveRegisterNumber(reg cpu.Register, number int) { a.Instructions = append(a.Instructions, Instruction{ Mnemonic: MOVE, Data: &RegisterNumber{ diff --git a/src/build/asm/Mnemonic.go b/src/build/asm/Mnemonic.go index 55f1dba..c5309eb 100644 --- a/src/build/asm/Mnemonic.go +++ b/src/build/asm/Mnemonic.go @@ -10,6 +10,7 @@ const ( LABEL MOVE RETURN + SUB SYSCALL ) @@ -34,6 +35,9 @@ func (m Mnemonic) String() string { case RETURN: return "return" + case SUB: + return "sub" + case SYSCALL: return "syscall" } diff --git a/src/build/asm/RegisterNumber.go b/src/build/asm/RegisterNumber.go index 6484e08..5040b53 100644 --- a/src/build/asm/RegisterNumber.go +++ b/src/build/asm/RegisterNumber.go @@ -9,7 +9,7 @@ import ( // RegisterNumber operates with a register and a number. type RegisterNumber struct { Register cpu.Register - Number uint64 + Number int } // String returns a human readable version.