Implemented bit shifting on arm64
This commit is contained in:
@ -6,8 +6,8 @@ import (
|
||||
|
||||
// AndRegisterNumber performs a bitwise AND using a register and a number.
|
||||
func AndRegisterNumber(destination cpu.Register, source cpu.Register, number int) (uint32, bool) {
|
||||
imm13, encodable := encodeLogicalImmediate(uint(number))
|
||||
return 0b100100100<<23 | reg2BitmaskImm(destination, source, imm13), encodable
|
||||
n, immr, imms, encodable := encodeLogicalImmediate(uint(number))
|
||||
return 0b100100100<<23 | reg2BitmaskImm(destination, source, n, immr, imms), encodable
|
||||
}
|
||||
|
||||
// AndRegisterRegister performs a bitwise AND using two registers.
|
||||
|
@ -4,8 +4,8 @@ import "git.urbach.dev/cli/q/src/cpu"
|
||||
|
||||
// OrRegisterNumber performs a bitwise OR using a register and a number.
|
||||
func OrRegisterNumber(destination cpu.Register, source cpu.Register, number int) (uint32, bool) {
|
||||
imm13, encodable := encodeLogicalImmediate(uint(number))
|
||||
return 0b101100100<<23 | reg2BitmaskImm(destination, source, imm13), encodable
|
||||
n, immr, imms, encodable := encodeLogicalImmediate(uint(number))
|
||||
return 0b101100100<<23 | reg2BitmaskImm(destination, source, n, immr, imms), encodable
|
||||
}
|
||||
|
||||
// OrRegisterRegister performs a bitwise OR using two registers.
|
||||
|
15
src/arm/Shift.go
Normal file
15
src/arm/Shift.go
Normal file
@ -0,0 +1,15 @@
|
||||
package arm
|
||||
|
||||
import (
|
||||
"git.urbach.dev/cli/q/src/cpu"
|
||||
)
|
||||
|
||||
// ShiftLeftNumber shifts the register value a specified amount of bits to the left.
|
||||
func ShiftLeftNumber(destination cpu.Register, source cpu.Register, bits int) uint32 {
|
||||
return 0b110100110<<23 | reg2BitmaskImm(destination, source, 1, 64-bits, (^bits)&mask6)
|
||||
}
|
||||
|
||||
// ShiftRightSignedNumber shifts the signed register value a specified amount of bits to the right.
|
||||
func ShiftRightSignedNumber(destination cpu.Register, source cpu.Register, bits int) uint32 {
|
||||
return 0b100100110<<23 | reg2BitmaskImm(destination, source, 1, bits&mask6, 0b111111)
|
||||
}
|
52
src/arm/Shift_test.go
Normal file
52
src/arm/Shift_test.go
Normal file
@ -0,0 +1,52 @@
|
||||
package arm_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.urbach.dev/cli/q/src/arm"
|
||||
"git.urbach.dev/cli/q/src/cpu"
|
||||
"git.urbach.dev/go/assert"
|
||||
)
|
||||
|
||||
func TestShiftLeftNumber(t *testing.T) {
|
||||
usagePatterns := []struct {
|
||||
Destination cpu.Register
|
||||
Source cpu.Register
|
||||
Bits int
|
||||
Code uint32
|
||||
}{
|
||||
{arm.X0, arm.X0, 0, 0xD340FC00},
|
||||
{arm.X0, arm.X0, 1, 0xD37FF800},
|
||||
{arm.X0, arm.X0, 8, 0xD378DC00},
|
||||
{arm.X0, arm.X0, 16, 0xD370BC00},
|
||||
{arm.X0, arm.X0, 63, 0xD3410000},
|
||||
}
|
||||
|
||||
for _, pattern := range usagePatterns {
|
||||
t.Logf("%b", pattern.Code)
|
||||
t.Logf("lsl %s, %s, %x", pattern.Destination, pattern.Source, pattern.Bits)
|
||||
code := arm.ShiftLeftNumber(pattern.Destination, pattern.Source, pattern.Bits)
|
||||
assert.DeepEqual(t, code, pattern.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShiftRightSignedNumber(t *testing.T) {
|
||||
usagePatterns := []struct {
|
||||
Destination cpu.Register
|
||||
Source cpu.Register
|
||||
Bits int
|
||||
Code uint32
|
||||
}{
|
||||
{arm.X0, arm.X0, 0, 0x9340FC00},
|
||||
{arm.X0, arm.X0, 1, 0x9341FC00},
|
||||
{arm.X0, arm.X0, 8, 0x9348FC00},
|
||||
{arm.X0, arm.X0, 16, 0x9350FC00},
|
||||
{arm.X0, arm.X0, 63, 0x937FFC00},
|
||||
}
|
||||
|
||||
for _, pattern := range usagePatterns {
|
||||
t.Logf("asr %s, %s, %x", pattern.Destination, pattern.Source, pattern.Bits)
|
||||
code := arm.ShiftRightSignedNumber(pattern.Destination, pattern.Source, pattern.Bits)
|
||||
assert.DeepEqual(t, code, pattern.Code)
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@ import "git.urbach.dev/cli/q/src/cpu"
|
||||
|
||||
// XorRegisterNumber performs a bitwise XOR using a register and a number.
|
||||
func XorRegisterNumber(destination cpu.Register, source cpu.Register, number int) (uint32, bool) {
|
||||
imm13, encodable := encodeLogicalImmediate(uint(number))
|
||||
return 0b110100100<<23 | reg2BitmaskImm(destination, source, imm13), encodable
|
||||
n, immr, imms, encodable := encodeLogicalImmediate(uint(number))
|
||||
return 0b110100100<<23 | reg2BitmaskImm(destination, source, n, immr, imms), encodable
|
||||
}
|
||||
|
||||
// XorRegisterRegister performs a bitwise XOR using two registers.
|
||||
|
@ -7,9 +7,24 @@ import (
|
||||
"git.urbach.dev/go/assert"
|
||||
)
|
||||
|
||||
func TestARM(t *testing.T) {
|
||||
func TestGeneral(t *testing.T) {
|
||||
assert.DeepEqual(t, arm.Call(0), 0x94000000)
|
||||
assert.DeepEqual(t, arm.Nop(), 0xD503201F)
|
||||
assert.DeepEqual(t, arm.Return(), 0xD65F03C0)
|
||||
assert.DeepEqual(t, arm.Syscall(), 0xD4000001)
|
||||
}
|
||||
|
||||
func TestNotEncodable(t *testing.T) {
|
||||
_, encodable := arm.AndRegisterNumber(arm.X0, arm.X0, 0)
|
||||
assert.False(t, encodable)
|
||||
_, encodable = arm.OrRegisterNumber(arm.X0, arm.X0, 0)
|
||||
assert.False(t, encodable)
|
||||
_, encodable = arm.XorRegisterNumber(arm.X0, arm.X0, 0)
|
||||
assert.False(t, encodable)
|
||||
_, encodable = arm.AndRegisterNumber(arm.X0, arm.X0, -1)
|
||||
assert.False(t, encodable)
|
||||
_, encodable = arm.OrRegisterNumber(arm.X0, arm.X0, -1)
|
||||
assert.False(t, encodable)
|
||||
_, encodable = arm.XorRegisterNumber(arm.X0, arm.X0, -1)
|
||||
assert.False(t, encodable)
|
||||
}
|
||||
|
@ -4,9 +4,9 @@ import "math/bits"
|
||||
|
||||
// encodeLogicalImmediate encodes a bitmask immediate.
|
||||
// The algorithm used here was made by Dougall Johnson.
|
||||
func encodeLogicalImmediate(val uint) (int, bool) {
|
||||
func encodeLogicalImmediate(val uint) (N int, immr int, imms int, encodable bool) {
|
||||
if val == 0 || ^val == 0 {
|
||||
return 0, false
|
||||
return 0, 0, 0, false
|
||||
}
|
||||
|
||||
rotation := bits.TrailingZeros(clearTrailingOnes(val))
|
||||
@ -16,15 +16,15 @@ func encodeLogicalImmediate(val uint) (int, bool) {
|
||||
ones := bits.TrailingZeros(^normalized)
|
||||
size := zeroes + ones
|
||||
|
||||
immr := -rotation & (size - 1)
|
||||
imms := -(size << 1) | (ones - 1)
|
||||
N := (size >> 6)
|
||||
immr = -rotation & (size - 1)
|
||||
imms = -(size << 1) | (ones - 1)
|
||||
N = (size >> 6)
|
||||
|
||||
if bits.RotateLeft(val, -(size&63)) != val {
|
||||
return 0, false
|
||||
return 0, 0, 0, false
|
||||
}
|
||||
|
||||
return N<<12 | immr<<6 | (imms & 0x3f), true
|
||||
return N, immr, (imms & 0x3f), true
|
||||
}
|
||||
|
||||
// clearTrailingOnes clears trailing one bits.
|
||||
|
@ -39,8 +39,8 @@ func reg2Imm(d cpu.Register, n cpu.Register, imm12 int) uint32 {
|
||||
}
|
||||
|
||||
// reg2BitmaskImm encodes an instruction with 2 registers and a bitmask immediate.
|
||||
func reg2BitmaskImm(d cpu.Register, n cpu.Register, imm13 int) uint32 {
|
||||
return uint32(imm13)<<10 | uint32(n)<<5 | uint32(d)
|
||||
func reg2BitmaskImm(d cpu.Register, n cpu.Register, N int, immr int, imms int) uint32 {
|
||||
return uint32(N)<<22 | uint32(immr)<<16 | uint32(imms)<<10 | uint32(n)<<5 | uint32(d)
|
||||
}
|
||||
|
||||
// reg3 encodes an instruction with 3 registers.
|
||||
|
@ -256,6 +256,24 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
||||
}
|
||||
}
|
||||
|
||||
case asm.SHIFTL:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.append(arm.ShiftLeftNumber(operands.Register, operands.Register, operands.Number&0b111111))
|
||||
case asm.TypeRegisterRegister:
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
case asm.SHIFTRS:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.append(arm.ShiftRightSignedNumber(operands.Register, operands.Register, operands.Number&0b111111))
|
||||
case asm.TypeRegisterRegister:
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
case asm.RETURN:
|
||||
c.append(arm.LoadPair(arm.FP, arm.LR, arm.SP, 16))
|
||||
c.append(arm.Return())
|
||||
|
@ -155,6 +155,8 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.ShiftLeftNumber(c.code, operands.Register, byte(operands.Number)&0b111111)
|
||||
case asm.TypeRegisterRegister:
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
case asm.SHIFTRS:
|
||||
@ -162,6 +164,8 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.ShiftRightSignedNumber(c.code, operands.Register, byte(operands.Number)&0b111111)
|
||||
case asm.TypeRegisterRegister:
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
case asm.STORE:
|
||||
|
Reference in New Issue
Block a user