Skip to content

Commit aee45b3

Browse files
committed
aml: implement DefWhile,DefBreak,DefContinue
1 parent 9795a38 commit aee45b3

File tree

2 files changed

+83
-24
lines changed

2 files changed

+83
-24
lines changed

aml/src/lib.rs

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,19 @@ where
412412
let kind = FieldUnitKind::Bank { region, bank, bank_value };
413413
self.parse_field_list(&mut context, kind, *start_pc, *pkg_length, field_flags)?;
414414
}
415+
Opcode::While => {
416+
/*
417+
* We've just evaluated the predicate for an iteration of a while loop. If
418+
* false, skip over the rest of the loop, otherwise carry on.
419+
*/
420+
let [Argument::Object(predicate)] = &op.arguments[..] else { panic!() };
421+
let predicate = predicate.as_integer()?;
422+
423+
if predicate == 0 {
424+
// Exit from the while loop by skipping out of the current block
425+
context.current_block = context.block_stack.pop().unwrap();
426+
}
427+
}
415428
_ => panic!("Unexpected operation has created in-flight op!"),
416429
}
417430
}
@@ -493,6 +506,15 @@ where
493506

494507
continue;
495508
}
509+
BlockKind::While { start_pc } => {
510+
/*
511+
* Go round again, and create a new in-flight op to have a look at the
512+
* predicate.
513+
*/
514+
context.current_block.pc = start_pc;
515+
context.start_in_flight_op(OpInFlight::new(Opcode::While, 1));
516+
continue;
517+
}
496518
}
497519
}
498520
Err(other_err) => return Err(other_err),
@@ -868,7 +890,6 @@ where
868890
Opcode::ObjectType => context.start_in_flight_op(OpInFlight::new(opcode, 1)),
869891
Opcode::CopyObject => todo!(),
870892
Opcode::Mid => context.start_in_flight_op(OpInFlight::new(Opcode::Mid, 4)),
871-
Opcode::Continue => todo!(),
872893
Opcode::If => {
873894
let start_pc = context.current_block.pc;
874895
let then_length = context.pkglength()?;
@@ -879,10 +900,43 @@ where
879900
));
880901
}
881902
Opcode::Else => return Err(AmlError::ElseFoundWithoutCorrespondingIf),
882-
Opcode::While => todo!(),
883-
Opcode::Noop => {}
903+
Opcode::While => {
904+
let start_pc = context.current_block.pc;
905+
let pkg_length = context.pkglength()?;
906+
let remaining_length = pkg_length - (context.current_block.pc - start_pc);
907+
context.start_new_block(
908+
BlockKind::While { start_pc: context.current_block.pc },
909+
remaining_length,
910+
);
911+
context.start_in_flight_op(OpInFlight::new(Opcode::While, 1));
912+
}
913+
Opcode::Continue => {
914+
let BlockKind::While { start_pc } = &context.current_block.kind else {
915+
Err(AmlError::ContinueOutsideOfWhile)?
916+
};
917+
context.current_block.pc = *start_pc;
918+
context.start_in_flight_op(OpInFlight::new(Opcode::While, 1));
919+
}
920+
Opcode::Break => {
921+
/*
922+
* Break out of the innermost `DefWhile`.
923+
*/
924+
if let BlockKind::While { .. } = &context.current_block.kind {
925+
context.current_block = context.block_stack.pop().unwrap();
926+
} else {
927+
loop {
928+
let Some(block) = context.block_stack.pop() else {
929+
Err(AmlError::BreakOutsideOfWhile)?
930+
};
931+
if let BlockKind::While { .. } = block.kind {
932+
break;
933+
}
934+
}
935+
context.current_block = context.block_stack.pop().unwrap();
936+
}
937+
}
884938
Opcode::Return => context.start_in_flight_op(OpInFlight::new(Opcode::Return, 1)),
885-
Opcode::Break => todo!(),
939+
Opcode::Noop => {}
886940
Opcode::Breakpoint => {
887941
self.handler.breakpoint();
888942
}
@@ -1276,6 +1330,9 @@ pub enum BlockKind {
12761330
/// Used for executing the then-branch of an `DefIfElse`. After finishing, it will check for
12771331
/// and skip over an else-branch, if present.
12781332
IfThenBranch,
1333+
While {
1334+
start_pc: usize,
1335+
},
12791336
}
12801337

12811338
impl OpInFlight {
@@ -1760,6 +1817,8 @@ pub enum AmlError {
17601817

17611818
NoCurrentOp,
17621819
ElseFoundWithoutCorrespondingIf,
1820+
ContinueOutsideOfWhile,
1821+
BreakOutsideOfWhile,
17631822

17641823
MethodArgCountIncorrect,
17651824

tests/while.asl

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
DefinitionBlock("while.aml", "DSDT", 1, "RSACPI", "WHILE", 1) {
2-
Name(X, 0)
3-
While (X < 5) {
4-
X++
5-
}
2+
Name(X, 0)
3+
While (X < 5) {
4+
X++
5+
}
66

7-
// Test `DefBreak` - Y should only make it to 5
8-
Name(Y, 0)
9-
While (Y < 10) {
10-
If (Y >= 5) {
11-
Break
12-
}
7+
// Test `DefBreak` - Y should only make it to 5
8+
Name(Y, 0)
9+
While (Y < 10) {
10+
If (Y >= 5) {
11+
Break
12+
}
1313

14-
Y++
15-
}
14+
Y++
15+
}
1616

17-
// Test `DefContinue` - Z should remain at zero
18-
Name(CNT, 0)
19-
Name(Z, 0)
20-
While (CNT < 5) {
21-
CNT++
22-
Continue
23-
Z++
24-
}
17+
// Test `DefContinue` - Z should remain at zero
18+
Name(CNT, 0)
19+
Name(Z, 0)
20+
While (CNT < 5) {
21+
CNT++
22+
Continue
23+
Z++
24+
}
2525
}

0 commit comments

Comments
 (0)