@@ -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
12811338impl OpInFlight {
@@ -1760,6 +1817,8 @@ pub enum AmlError {
17601817
17611818 NoCurrentOp ,
17621819 ElseFoundWithoutCorrespondingIf ,
1820+ ContinueOutsideOfWhile ,
1821+ BreakOutsideOfWhile ,
17631822
17641823 MethodArgCountIncorrect ,
17651824
0 commit comments