From be6cd181b124331ef0761e8ee3e163d4d0fdd6e0 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Sun, 31 Dec 2017 07:40:53 +0000 Subject: [PATCH] acpi: support compilation of logic operators to VM opcodes The compiler will use the following template for compiling expressions that involve comparisons: 00 push op1 01 push op2 02 je/jg/jl true_label 03 push_0 04 jmp done_label 05 true_label: 06 push_1 07 done_label: The jmp instruction type used for L02 depends on the AML opcode that is compiled. To conserve space, the ACPI spec only defines opcodes for the following comparison operations: equal, less, greater. All other comparisons are constructed by combining one of the above opcodes with a logical not opcode (e.g. greaterOrEqual = !(less)). The VM opcode exploits the fact the comparison expressions always push a 0/1 value on the stack and uses bitwise operations to emulate some additional logic opcodes: - logic not: 0/1 (on stack) XOR 1 - logic and: 0/1 (left expr on stack) AND 0/1 (right expr on stack) - logic or : 0/1 (left expr on stack) OR 0/1 (right expr on stack) --- src/gopheros/device/acpi/aml/vm/compiler.go | 68 +++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/gopheros/device/acpi/aml/vm/compiler.go b/src/gopheros/device/acpi/aml/vm/compiler.go index c3234f1..1182e08 100644 --- a/src/gopheros/device/acpi/aml/vm/compiler.go +++ b/src/gopheros/device/acpi/aml/vm/compiler.go @@ -65,6 +65,15 @@ func newCompilerContext(rootNS entity.Container) *compilerContext { entity.OpNot: {opNot, compileUnaryOperator}, entity.OpFindSetLeftBit: {opFindSlb, compileUnaryOperator}, entity.OpFindSetRightBit: {opFindSrb, compileUnaryOperator}, + // Logic opcodes + entity.OpLEqual: {opJe, compileLogicOperator}, + entity.OpLGreater: {opJg, compileLogicOperator}, + entity.OpLLess: {opJl, compileLogicOperator}, + entity.OpLnot: {opXor, compileLogicNotOperator}, + // Logic and/or is modelled as a bitwise AND/OR on the output + // of two logic expressions + entity.OpLand: {opAnd, compileBinaryOperator}, + entity.OpLor: {opOr, compileBinaryOperator}, } return compCtx @@ -246,6 +255,65 @@ func compileBinaryOperator(compCtx *compilerContext, vmOp uint8, ent entity.Enti return nil } +// compileLogicOperator generates a stream of conditional jump opcodes that +// implement a logic operator. +func compileLogicOperator(compCtx *compilerContext, vmJmpOp uint8, ent entity.Entity) *kernel.Error { + operands := ent.Args() + if len(operands) < 2 { + return &kernel.Error{ + Module: "acpi_aml_compiler", + Message: "unexpected operand count for logic operator " + ent.Opcode().String(), + } + } + + // To emulate the logic operation the following sequence of + // instructions gets generated: + // + // push op1 + // push op2 + // vmJmpOp true_label ; IP += 11 + // push_0 ; cmp evaluated to false + // jmp done_label ; IP += 6 + // true_label: push_1 ; cmp evaluated to true + // done_label: + for opIndex := 0; opIndex < 2; opIndex++ { + if err := compileOperand(compCtx, operands[opIndex], opDirectionIn); err != nil { + return err + } + } + + emit32(compCtx, vmJmpOp, uint32(len(compCtx.vmCtx.bytecode))+11) + emit8(compCtx, opPushZero) + emit32(compCtx, opJmp, uint32(len(compCtx.vmCtx.bytecode))+6) + emit8(compCtx, opPushOne) + + return nil +} + +// compileLogicNotOperator generates the appropriate opcode stream for toggling +// the top-most stack entry between 0 and 1. +func compileLogicNotOperator(compCtx *compilerContext, _ uint8, ent entity.Entity) *kernel.Error { + operands := ent.Args() + if len(operands) < 1 { + return &kernel.Error{ + Module: "acpi_aml_compiler", + Message: "unexpected operand count for operator " + ent.Opcode().String(), + } + } + + // Compile operand + if err := compileOperand(compCtx, operands[0], opDirectionIn); err != nil { + return err + } + + // The top of the stack will now be a 0/1 value. By XOR-ing with 1 + // we can toggle the value + emit8(compCtx, opPushOne) + emit8(compCtx, opXor) + + return nil +} + // compileDivisionOperator generates the appropriate opcode stream for a // division operator that optionally stores the remainder and the quotient to // the optional third and fourth operands.