@@ -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 }
@@ -2374,17 +2401,19 @@ where
23742401 Output :: Integer ( value) => value,
23752402 } ;
23762403
2377- let read_region = match field. kind {
2378- FieldUnitKind :: Normal { ref region } => region,
2379- // FieldUnitKind::Bank { ref region, ref bank, bank_value } => {
2380- FieldUnitKind :: Bank { .. } => {
2381- // TODO: put the bank_value in the bank
2382- todo ! ( ) ;
2404+ let ( read_region, index_field_idx) = match field. kind {
2405+ FieldUnitKind :: Normal { ref region } => ( region, 0 ) ,
2406+ FieldUnitKind :: Bank { ref region, ref bank, bank_value } => {
2407+ let Object :: FieldUnit ( ref bank) = * * bank else { panic ! ( ) } ;
2408+ assert ! ( matches!( bank. kind, FieldUnitKind :: Normal { .. } ) ) ;
2409+ self . do_field_write ( bank, Object :: Integer ( bank_value) . wrap ( ) ) ?;
2410+ ( region, 0 )
23832411 }
2384- // FieldUnitKind::Index { ref index, ref data } => {
2385- FieldUnitKind :: Index { .. } => {
2386- // TODO: configure the correct index
2387- todo ! ( ) ;
2412+ FieldUnitKind :: Index { index : _, ref data } => {
2413+ let Object :: FieldUnit ( ref data) = * * data else { panic ! ( ) } ;
2414+ let FieldUnitKind :: Normal { region } = & data. kind else { panic ! ( ) } ;
2415+ let reg_idx = field. bit_index / 8 ;
2416+ ( region, reg_idx)
23882417 }
23892418 } ;
23902419 let Object :: OpRegion ( ref read_region) = * * read_region else { panic ! ( ) } ;
@@ -2404,7 +2433,27 @@ where
24042433 / access_width_bits;
24052434 let mut read_so_far = 0 ;
24062435 for i in 0 ..native_accesses_needed {
2407- let aligned_offset = object:: align_down ( field. bit_index + i * access_width_bits, access_width_bits) ;
2436+ // Advance the read pointer. For Index fields, this also means updating the Index
2437+ // register.
2438+ let aligned_offset = match field. kind {
2439+ FieldUnitKind :: Normal { .. } | FieldUnitKind :: Bank { .. } => {
2440+ object:: align_down ( field. bit_index + i * access_width_bits, access_width_bits)
2441+ }
2442+ FieldUnitKind :: Index { ref index, ref data } => {
2443+ // Update index register
2444+ let Object :: FieldUnit ( ref index) = * * index else { panic ! ( ) } ;
2445+ let Object :: FieldUnit ( ref data) = * * data else { panic ! ( ) } ;
2446+ self . do_field_write (
2447+ index,
2448+ Object :: Integer ( ( index_field_idx + i * ( access_width_bits / 8 ) ) as u64 ) . wrap ( ) ,
2449+ ) ?;
2450+
2451+ // The offset is always that of the data register, as we always read from the
2452+ // base of the data register.
2453+ data. bit_index
2454+ }
2455+ } ;
2456+
24082457 let raw = self . do_native_region_read ( read_region, aligned_offset / 8 , access_width_bits / 8 ) ?;
24092458 let src_index = if i == 0 { field. bit_index % access_width_bits } else { 0 } ;
24102459 let remaining_length = field. bit_length - read_so_far;
@@ -2434,17 +2483,23 @@ where
24342483 } ;
24352484 let access_width_bits = field. flags . access_type_bytes ( ) ? * 8 ;
24362485
2437- let write_region = match field. kind {
2438- FieldUnitKind :: Normal { ref region } => region,
2439- // FieldUnitKind::Bank { ref region, ref bank, bank_value } => {
2440- FieldUnitKind :: Bank { .. } => {
2441- // TODO: put the bank_value in the bank
2442- todo ! ( ) ;
2486+ // In this tuple:
2487+ // - write_region is the region that the data will be written to.
2488+ // - index_field_idx is the initial index to write into the Index register of an index
2489+ // field. For all other field types it is unused and set to zero.
2490+ let ( write_region, index_field_idx) = match field. kind {
2491+ FieldUnitKind :: Normal { ref region } => ( region, 0 ) ,
2492+ FieldUnitKind :: Bank { ref region, ref bank, bank_value } => {
2493+ let Object :: FieldUnit ( ref bank) = * * bank else { panic ! ( ) } ;
2494+ assert ! ( matches!( bank. kind, FieldUnitKind :: Normal { .. } ) ) ;
2495+ self . do_field_write ( bank, Object :: Integer ( bank_value) . wrap ( ) ) ?;
2496+ ( region, 0 )
24432497 }
2444- // FieldUnitKind::Index { ref index, ref data } => {
2445- FieldUnitKind :: Index { .. } => {
2446- // TODO: configure the correct index
2447- todo ! ( ) ;
2498+ FieldUnitKind :: Index { index : _, ref data } => {
2499+ let Object :: FieldUnit ( ref data) = * * data else { panic ! ( ) } ;
2500+ let FieldUnitKind :: Normal { region : data_region } = & data. kind else { panic ! ( ) } ;
2501+ let reg_idx = field. bit_index / 8 ;
2502+ ( data_region, reg_idx)
24482503 }
24492504 } ;
24502505 let Object :: OpRegion ( ref write_region) = * * write_region else { panic ! ( ) } ;
@@ -2459,7 +2514,26 @@ where
24592514 let mut written_so_far = 0 ;
24602515
24612516 for i in 0 ..native_accesses_needed {
2462- let aligned_offset = object:: align_down ( field. bit_index + i * access_width_bits, access_width_bits) ;
2517+ // Advance the write pointer... For normal and bank fields this is straightforward. For
2518+ // Index fields, this involves updating the index register.
2519+ let aligned_offset = match field. kind {
2520+ FieldUnitKind :: Normal { .. } | FieldUnitKind :: Bank { .. } => {
2521+ object:: align_down ( field. bit_index + i * access_width_bits, access_width_bits)
2522+ }
2523+ FieldUnitKind :: Index { ref index, ref data } => {
2524+ // Update index register
2525+ let Object :: FieldUnit ( ref index) = * * index else { panic ! ( ) } ;
2526+ let Object :: FieldUnit ( ref data) = * * data else { panic ! ( ) } ;
2527+ self . do_field_write (
2528+ index,
2529+ Object :: Integer ( ( index_field_idx + i * ( access_width_bits / 8 ) ) as u64 ) . wrap ( ) ,
2530+ ) ?;
2531+
2532+ // The offset is always that of the data register, as we always read from the
2533+ // base of the data register.
2534+ data. bit_index
2535+ }
2536+ } ;
24632537 let dst_index = if i == 0 { field. bit_index % access_width_bits } else { 0 } ;
24642538
24652539 /*
0 commit comments