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:
parent
b80c337bc7
commit
be6cd181b1
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user