@@ -1374,6 +1374,33 @@ where
13741374 let ( _, data) = namespace. search ( & data_name, & context. current_scope ) ?;
13751375 ( index, data)
13761376 } ;
1377+
1378+ if let Object :: FieldUnit ( ref data_fu) = * data {
1379+ if data_fu. flags . access_type_bytes ( ) ? < FieldFlags ( field_flags) . access_type_bytes ( ) ? {
1380+ // On ACPICA this causes reads/writes to be truncated to the width of
1381+ // the data register.
1382+ //
1383+ // The issue comes from this part of the spec:
1384+ // "The value written to the IndexName register is defined to be a byte
1385+ // offset that is aligned on an AccessType boundary."
1386+ //
1387+ // Consider the case where the index field is WordAcc but the data
1388+ // register is ByteAcc. Only even numbers could be written to the index
1389+ // register - multiples of width of word (2 bytes). But to access the
1390+ // high byte of the word for the field, we'd need to write an odd number
1391+ // to the index register. Which is not compatible with the spec.
1392+ //
1393+ // The ASL writer shouldn't have allowed this. And it seems that most
1394+ // uses of IndexField are ByteAcc all around. So whatever strange
1395+ // behaviour we allow is probably OK.
1396+ //
1397+ // But warn the user, just in case.
1398+ warn ! ( "Data field access width is smaller than normal field width at {:?}" , start_pc) ;
1399+ }
1400+ } else {
1401+ warn ! ( "Wrong data field type in IndexField: {:?}" , data) ;
1402+ } ;
1403+
13771404 let kind = FieldUnitKind :: Index { index, data } ;
13781405 self . parse_field_list ( & mut context, kind, start_pc, pkg_length, field_flags) ?;
13791406 }
@@ -2376,17 +2403,19 @@ where
23762403 Output :: Integer ( value) => value,
23772404 } ;
23782405
2379- let read_region = match field. kind {
2380- FieldUnitKind :: Normal { ref region } => region,
2381- // FieldUnitKind::Bank { ref region, ref bank, bank_value } => {
2382- FieldUnitKind :: Bank { .. } => {
2383- // TODO: put the bank_value in the bank
2384- todo ! ( ) ;
2406+ let ( read_region, index_field_idx) = match field. kind {
2407+ FieldUnitKind :: Normal { ref region } => ( region, 0 ) ,
2408+ FieldUnitKind :: Bank { ref region, ref bank, bank_value } => {
2409+ let Object :: FieldUnit ( ref bank) = * * bank else { panic ! ( ) } ;
2410+ assert ! ( matches!( bank. kind, FieldUnitKind :: Normal { .. } ) ) ;
2411+ self . do_field_write ( bank, Object :: Integer ( bank_value) . wrap ( ) ) ?;
2412+ ( region, 0 )
23852413 }
2386- // FieldUnitKind::Index { ref index, ref data } => {
2387- FieldUnitKind :: Index { .. } => {
2388- // TODO: configure the correct index
2389- todo ! ( ) ;
2414+ FieldUnitKind :: Index { index : _, ref data } => {
2415+ let Object :: FieldUnit ( ref data) = * * data else { panic ! ( ) } ;
2416+ let FieldUnitKind :: Normal { region } = & data. kind else { panic ! ( ) } ;
2417+ let reg_idx = field. bit_index / 8 ;
2418+ ( region, reg_idx)
23902419 }
23912420 } ;
23922421 let Object :: OpRegion ( ref read_region) = * * read_region else { panic ! ( ) } ;
@@ -2406,7 +2435,27 @@ where
24062435 / access_width_bits;
24072436 let mut read_so_far = 0 ;
24082437 for i in 0 ..native_accesses_needed {
2409- let aligned_offset = object:: align_down ( field. bit_index + i * access_width_bits, access_width_bits) ;
2438+ // Advance the read pointer. For Index fields, this also means updating the Index
2439+ // register.
2440+ let aligned_offset = match field. kind {
2441+ FieldUnitKind :: Normal { .. } | FieldUnitKind :: Bank { .. } => {
2442+ object:: align_down ( field. bit_index + i * access_width_bits, access_width_bits)
2443+ }
2444+ FieldUnitKind :: Index { ref index, ref data } => {
2445+ // Update index register
2446+ let Object :: FieldUnit ( ref index) = * * index else { panic ! ( ) } ;
2447+ let Object :: FieldUnit ( ref data) = * * data else { panic ! ( ) } ;
2448+ self . do_field_write (
2449+ index,
2450+ Object :: Integer ( ( index_field_idx + i * ( access_width_bits / 8 ) ) as u64 ) . wrap ( ) ,
2451+ ) ?;
2452+
2453+ // The offset is always that of the data register, as we always read from the
2454+ // base of the data register.
2455+ data. bit_index
2456+ }
2457+ } ;
2458+
24102459 let raw = self . do_native_region_read ( read_region, aligned_offset / 8 , access_width_bits / 8 ) ?;
24112460 let src_index = if i == 0 { field. bit_index % access_width_bits } else { 0 } ;
24122461 let remaining_length = field. bit_length - read_so_far;
@@ -2436,17 +2485,23 @@ where
24362485 } ;
24372486 let access_width_bits = field. flags . access_type_bytes ( ) ? * 8 ;
24382487
2439- let write_region = match field. kind {
2440- FieldUnitKind :: Normal { ref region } => region,
2441- // FieldUnitKind::Bank { ref region, ref bank, bank_value } => {
2442- FieldUnitKind :: Bank { .. } => {
2443- // TODO: put the bank_value in the bank
2444- todo ! ( ) ;
2488+ // In this tuple:
2489+ // - write_region is the region that the data will be written to.
2490+ // - index_field_idx is the initial index to write into the Index register of an index
2491+ // field. For all other field types it is unused and set to zero.
2492+ let ( write_region, index_field_idx) = match field. kind {
2493+ FieldUnitKind :: Normal { ref region } => ( region, 0 ) ,
2494+ FieldUnitKind :: Bank { ref region, ref bank, bank_value } => {
2495+ let Object :: FieldUnit ( ref bank) = * * bank else { panic ! ( ) } ;
2496+ assert ! ( matches!( bank. kind, FieldUnitKind :: Normal { .. } ) ) ;
2497+ self . do_field_write ( bank, Object :: Integer ( bank_value) . wrap ( ) ) ?;
2498+ ( region, 0 )
24452499 }
2446- // FieldUnitKind::Index { ref index, ref data } => {
2447- FieldUnitKind :: Index { .. } => {
2448- // TODO: configure the correct index
2449- todo ! ( ) ;
2500+ FieldUnitKind :: Index { index : _, ref data } => {
2501+ let Object :: FieldUnit ( ref data) = * * data else { panic ! ( ) } ;
2502+ let FieldUnitKind :: Normal { region : data_region } = & data. kind else { panic ! ( ) } ;
2503+ let reg_idx = field. bit_index / 8 ;
2504+ ( data_region, reg_idx)
24502505 }
24512506 } ;
24522507 let Object :: OpRegion ( ref write_region) = * * write_region else { panic ! ( ) } ;
@@ -2461,7 +2516,26 @@ where
24612516 let mut written_so_far = 0 ;
24622517
24632518 for i in 0 ..native_accesses_needed {
2464- let aligned_offset = object:: align_down ( field. bit_index + i * access_width_bits, access_width_bits) ;
2519+ // Advance the write pointer... For normal and bank fields this is straightforward. For
2520+ // Index fields, this involves updating the index register.
2521+ let aligned_offset = match field. kind {
2522+ FieldUnitKind :: Normal { .. } | FieldUnitKind :: Bank { .. } => {
2523+ object:: align_down ( field. bit_index + i * access_width_bits, access_width_bits)
2524+ }
2525+ FieldUnitKind :: Index { ref index, ref data } => {
2526+ // Update index register
2527+ let Object :: FieldUnit ( ref index) = * * index else { panic ! ( ) } ;
2528+ let Object :: FieldUnit ( ref data) = * * data else { panic ! ( ) } ;
2529+ self . do_field_write (
2530+ index,
2531+ Object :: Integer ( ( index_field_idx + i * ( access_width_bits / 8 ) ) as u64 ) . wrap ( ) ,
2532+ ) ?;
2533+
2534+ // The offset is always that of the data register, as we always read from the
2535+ // base of the data register.
2536+ data. bit_index
2537+ }
2538+ } ;
24652539 let dst_index = if i == 0 { field. bit_index % access_width_bits } else { 0 } ;
24662540
24672541 /*
0 commit comments