1
0
mirror of https://github.com/taigrr/gopher-os synced 2025-01-18 04:43:13 -08:00

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)
This commit is contained in:
Achilleas Anagnostopoulos 2017-12-31 07:40:53 +00:00
parent b80c337bc7
commit be6cd181b1

View File

@ -65,6 +65,15 @@ func newCompilerContext(rootNS entity.Container) *compilerContext {
entity.OpNot: {opNot, compileUnaryOperator}, entity.OpNot: {opNot, compileUnaryOperator},
entity.OpFindSetLeftBit: {opFindSlb, compileUnaryOperator}, entity.OpFindSetLeftBit: {opFindSlb, compileUnaryOperator},
entity.OpFindSetRightBit: {opFindSrb, 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 return compCtx
@ -246,6 +255,65 @@ func compileBinaryOperator(compCtx *compilerContext, vmOp uint8, ent entity.Enti
return nil 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 // compileDivisionOperator generates the appropriate opcode stream for a
// division operator that optionally stores the remainder and the quotient to // division operator that optionally stores the remainder and the quotient to
// the optional third and fourth operands. // the optional third and fourth operands.