diff --git a/assembler/asm.go b/assembler/asm.go index 8b37851..cd758af 100644 --- a/assembler/asm.go +++ b/assembler/asm.go @@ -96,6 +96,41 @@ func (p *Builder) Not() *Builder { return p } +func (p *Builder) And() *Builder { + p.writeU16(von.AND) + return p +} + +func (p *Builder) Or() *Builder { + p.writeU16(von.OR) + return p +} + +func (p *Builder) Xor() *Builder { + p.writeU16(von.XOR) + return p +} + +func (p *Builder) ShiftLeft() *Builder { + p.writeU16(von.SHL) + return p +} + +func (p *Builder) ShiftRight() *Builder { + p.writeU16(von.SHR) + return p +} + +func (p *Builder) GreaterThanInt() *Builder { + p.writeU16(von.GTI) + return p +} + +func (p *Builder) GreaterThanString() *Builder { + p.writeU16(von.GTS) + return p +} + func (p *Builder) Concat() *Builder { p.writeU16(von.CONCAT) return p diff --git a/assembler/asm_test.go b/assembler/asm_test.go index fcf85e0..b1635cb 100644 --- a/assembler/asm_test.go +++ b/assembler/asm_test.go @@ -63,6 +63,119 @@ func TestInt(t *testing.T) { } } +func TestBitwiseAnd(t *testing.T) { + asm := New(nil) + asm.PushInt(0b1100). + PushInt(0b1010). + And() + ret := run(asm).Top(1) + if ret != int64(0b1000) { // 12 & 10 = 8 + t.Fatal("TestBitwiseAnd:", ret) + } +} + +func TestBitwiseOr(t *testing.T) { + asm := New(nil) + asm.PushInt(0b1100). + PushInt(0b1010). + Or() + ret := run(asm).Top(1) + if ret != int64(0b1110) { // 12 | 10 = 14 + t.Fatal("TestBitwiseOr:", ret) + } +} + +func TestBitwiseXor(t *testing.T) { + asm := New(nil) + asm.PushInt(0b1100). + PushInt(0b1010). + Xor() + ret := run(asm).Top(1) + if ret != int64(0b0110) { // 12 ^ 10 = 6 + t.Fatal("TestBitwiseXor:", ret) + } +} + +func TestShiftLeft(t *testing.T) { + asm := New(nil) + asm.PushInt(1). + PushInt(4). + ShiftLeft() + ret := run(asm).Top(1) + if ret != int64(16) { // 1 << 4 = 16 + t.Fatal("TestShiftLeft:", ret) + } +} + +func TestShiftRight(t *testing.T) { + asm := New(nil) + asm.PushInt(16). + PushInt(2). + ShiftRight() + ret := run(asm).Top(1) + if ret != int64(4) { // 16 >> 2 = 4 + t.Fatal("TestShiftRight:", ret) + } +} + +func TestShiftRightNegative(t *testing.T) { + asm := New(nil) + asm.PushInt(-1). + PushInt(1). + ShiftRight() + ret := run(asm).Top(1) + // -1 is all 1s in two's complement + // Logical shift right fills with 0s: 0x7FFFFFFFFFFFFFFF + expected := int64(0x7FFFFFFFFFFFFFFF) + if ret != expected { + t.Fatal("TestShiftRightNegative:", ret, "expected:", expected) + } +} + +func TestGreaterThanInt_True(t *testing.T) { + asm := New(nil) + asm.PushInt(5). + PushInt(3). + GreaterThanInt() + ret := run(asm).Top(1) + if ret != int64(1) { // 5 > 3 = true + t.Fatal("TestGreaterThanInt_True:", ret) + } +} + +func TestGreaterThanInt_False(t *testing.T) { + asm := New(nil) + asm.PushInt(3). + PushInt(5). + GreaterThanInt() + ret := run(asm).Top(1) + if ret != int64(0) { // 3 > 5 = false + t.Fatal("TestGreaterThanInt_False:", ret) + } +} + +func TestGreaterThanString_True(t *testing.T) { + asm := New(nil) + asm.PushString("World"). + PushString("Hello"). + GreaterThanString() + ret := run(asm).Top(1) + if ret != int64(1) { // "World" > "Hello" = true + t.Fatal("TestGreaterThanString_True:", ret) + } +} + +func TestGreaterThanString_False(t *testing.T) { + asm := New(nil) + asm.PushString("Apple"). + PushString("Banana"). + GreaterThanString() + ret := run(asm).Top(1) + if ret != int64(0) { // "Apple" > "Banana" = false + t.Fatal("TestGreaterThanString_False:", ret) + } +} + func TestString(t *testing.T) { asm := New(nil) asm.PushString("Hello, "). @@ -196,7 +309,7 @@ func TestKeyboardAndConsole(t *testing.T) { SetArg(4). // i += 2 Jmp("loop"). Label("done"). - PushString(string(con.PUTS)). + PushString(string(rune(con.PUTS))). PushArg(1). Concat(). PushString("\n"). diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c41d286 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/qiniu/arch + +go 1.25.5 diff --git a/von/cpu.go b/von/cpu.go index 65127a6..71f8a6c 100644 --- a/von/cpu.go +++ b/von/cpu.go @@ -34,6 +34,13 @@ const ( EQI // 等于 (arg1, arg2 int64) EQS // 等于 (arg1, arg2 []byte) NOT // 非 (arg1 int64) + AND // 位与 (arg1, arg2 int64) + OR // 位或 (arg1, arg2 int64) + XOR // 位异或 (arg1, arg2 int64) + SHL // 左移 (arg1, arg2 int64) + SHR // 右移 (arg1, arg2 int64) - 逻辑右移 + GTI // 大于 (arg1, arg2 int64) + GTS // 大于 (arg1, arg2 []byte) CONCAT // 字符串连接 (arg1, arg2 []byte) INDEX // 取字符 (s []byte, index int64) STRING // 字符转为字符串 (ch int64) @@ -136,6 +143,48 @@ func (p *CPU) Run(pc int64) { *ret = not((*ret).(int64)) pc += 2 debug("NOT:", p.stk) + case AND: + v := p.pop().(int64) + ret := p.top(1) + *ret = (*ret).(int64) & v + pc += 2 + debug("AND:", p.stk) + case OR: + v := p.pop().(int64) + ret := p.top(1) + *ret = (*ret).(int64) | v + pc += 2 + debug("OR:", p.stk) + case XOR: + v := p.pop().(int64) + ret := p.top(1) + *ret = (*ret).(int64) ^ v + pc += 2 + debug("XOR:", p.stk) + case SHL: + v := p.pop().(int64) + ret := p.top(1) + *ret = (*ret).(int64) << uint(v) + pc += 2 + debug("SHL:", p.stk) + case SHR: + v := p.pop().(int64) + ret := p.top(1) + *ret = int64(uint64((*ret).(int64)) >> uint(v)) + pc += 2 + debug("SHR:", p.stk) + case GTI: + v := p.pop().(int64) + ret := p.top(1) + *ret = fromBool((*ret).(int64) > v) + pc += 2 + debug("GTI:", p.stk) + case GTS: + v := p.pop().([]byte) + ret := p.top(1) + *ret = fromBool(bytes.Compare((*ret).([]byte), v) > 0) + pc += 2 + debug("GTS:", p.stk) case CONCAT: v := p.pop().([]byte) ret := p.top(1)