@@ -412,6 +412,19 @@ where
412
412
let kind = FieldUnitKind :: Bank { region, bank, bank_value } ;
413
413
self . parse_field_list ( & mut context, kind, * start_pc, * pkg_length, field_flags) ?;
414
414
}
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
+ }
415
428
_ => panic ! ( "Unexpected operation has created in-flight op!" ) ,
416
429
}
417
430
}
@@ -493,6 +506,15 @@ where
493
506
494
507
continue ;
495
508
}
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
+ }
496
518
}
497
519
}
498
520
Err ( other_err) => return Err ( other_err) ,
@@ -868,7 +890,6 @@ where
868
890
Opcode :: ObjectType => context. start_in_flight_op ( OpInFlight :: new ( opcode, 1 ) ) ,
869
891
Opcode :: CopyObject => todo ! ( ) ,
870
892
Opcode :: Mid => context. start_in_flight_op ( OpInFlight :: new ( Opcode :: Mid , 4 ) ) ,
871
- Opcode :: Continue => todo ! ( ) ,
872
893
Opcode :: If => {
873
894
let start_pc = context. current_block . pc ;
874
895
let then_length = context. pkglength ( ) ?;
@@ -879,10 +900,43 @@ where
879
900
) ) ;
880
901
}
881
902
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
+ }
884
938
Opcode :: Return => context. start_in_flight_op ( OpInFlight :: new ( Opcode :: Return , 1 ) ) ,
885
- Opcode :: Break => todo ! ( ) ,
939
+ Opcode :: Noop => { }
886
940
Opcode :: Breakpoint => {
887
941
self . handler . breakpoint ( ) ;
888
942
}
@@ -1276,6 +1330,9 @@ pub enum BlockKind {
1276
1330
/// Used for executing the then-branch of an `DefIfElse`. After finishing, it will check for
1277
1331
/// and skip over an else-branch, if present.
1278
1332
IfThenBranch ,
1333
+ While {
1334
+ start_pc : usize ,
1335
+ } ,
1279
1336
}
1280
1337
1281
1338
impl OpInFlight {
@@ -1760,6 +1817,8 @@ pub enum AmlError {
1760
1817
1761
1818
NoCurrentOp ,
1762
1819
ElseFoundWithoutCorrespondingIf ,
1820
+ ContinueOutsideOfWhile ,
1821
+ BreakOutsideOfWhile ,
1763
1822
1764
1823
MethodArgCountIncorrect ,
1765
1824
0 commit comments