LCOV - code coverage report
Current view: top level - src/arch - instruction_specified_shift.rs (source / functions) Hit Total Coverage
Test: lcov Lines: 0 40 0.0 %
Date: 2023-12-07 18:49:03 Functions: 0 4 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //! Utils for instruction specified shift operations, instruction specified
       2             : //! meaning a shift amount that's encoded in an Risc instruction. See: [ARM7TDMI
       3             : //! Datasheet Page.36-38]
       4             : //!
       5             : //! [ARM7TDMI Datasheet Page.36-38]:https://github.com/gregorygaines/gopherboyadvance/blob/main/docs/references/arm7tdmi-datasheet.pdf
       6             : 
       7             : use crate::arch::ShiftResults;
       8             : use crate::util::bit_manipulation::is_bit_set_32;
       9             : 
      10             : /// Shifts bits left by an instruction specified amount.
      11             : ///
      12             : /// Bits are moved out of the left-hand end and zeros are filled into the
      13             : /// right-hand end. If the shift amount is zero, the carry out is the old carry
      14             : /// flag and val is unchanged.
      15           0 : pub fn shift_left(val: u32, shift_amount: u32, carry_flag: bool) -> ShiftResults {
      16           0 :     if shift_amount == 0 {
      17           0 :         ShiftResults { val, carry_out: carry_flag }
      18             :     } else {
      19           0 :         ShiftResults {
      20           0 :             val: val << shift_amount,
      21           0 :             carry_out: is_bit_set_32(val, (32 - shift_amount) as i32),
      22           0 :         }
      23             :     }
      24           0 : }
      25             : 
      26             : /// Shifts bits right by an instruction specified amount.
      27             : ///
      28             : /// Bits are moved out of the right-hand end and zeros are filled in the left
      29             : /// hand end. If the shift amount is zero, the shift is interpreted as LSR#32 or
      30             : /// shift right by 32 which produces a result val of zero, and the carry out
      31             : /// being bit 31 of val of the original val.
      32           0 : pub fn shift_right(val: u32, shift_amount: u32) -> ShiftResults {
      33           0 :     if shift_amount == 0 {
      34           0 :         ShiftResults { val: 0, carry_out: is_bit_set_32(val, /* bit_idx= */ 31) }
      35             :     } else {
      36           0 :         ShiftResults {
      37           0 :             val: val >> shift_amount,
      38           0 :             carry_out: is_bit_set_32(val, (shift_amount - 1) as i32),
      39           0 :         }
      40             :     }
      41           0 : }
      42             : 
      43             : /// Rotates bits right by an instruction specified amount.
      44             : ///
      45             : /// Bits moved out of the right-hand end are rotated back into the left-hand
      46             : /// end. If the shift amount is zero, the instruction becomes a RRX or rotate
      47             : /// right extended. A RRX is a shift right by 1 bit, with bit 0 being the carry
      48             : /// out and bit 31 being the carry flag.
      49           0 : pub fn rotate_right(val: u32, shift_amount: u32, carry_flag: bool) -> ShiftResults {
      50           0 :     if shift_amount == 0 {
      51           0 :         ShiftResults {
      52           0 :             val: ((carry_flag as u32) << 31) | (val >> 1),
      53           0 :             carry_out: is_bit_set_32(val, /* bit_idx= */ 0),
      54           0 :         }
      55             :     } else {
      56           0 :         ShiftResults {
      57           0 :             val: (val >> shift_amount) | (val << (32 - shift_amount)),
      58           0 :             carry_out: is_bit_set_32(val, (shift_amount - 1) as i32),
      59           0 :         }
      60             :     }
      61           0 : }
      62             : 
      63             : /// Shifts bits right by an instruction specified amount while preserving the
      64             : /// sign of the val.
      65             : ///
      66             : /// Bits are moved out of the right-hand end and bit 31 of the val are filled in
      67             : /// the left-hand end to preserves the sign in 2's complement notation. If the
      68             : /// shift amount is zero, the shift is interpreted as ASR#32 or arithmetic shift
      69             : /// right by 32. The bits of the result val becomes all ones or zeros, according
      70             : /// to bit 31 in val; either 0xFFFF_FFFF or 0x0 and the carry out is bit 31 of
      71             : /// original val.
      72           0 : pub fn arithmetic_shift_right(val: u32, shift_amount: u32) -> ShiftResults {
      73           0 :     if shift_amount == 0 {
      74           0 :         let carry_out = is_bit_set_32(val, /* bit_idx= */ 31);
      75           0 :         if carry_out {
      76           0 :             ShiftResults { val: 0xFFFF_FFFF, carry_out }
      77             :         } else {
      78           0 :             ShiftResults { val: 0, carry_out }
      79             :         }
      80             :     } else {
      81             :         // Preserve the most significant bit (msb) of the val as a integer.
      82           0 :         let preserved_msb = val & 0x8000_0000;
      83           0 : 
      84           0 :         let mut res = val;
      85           0 :         for _ in 0..shift_amount {
      86             :             // Shift right and set the msb to the preserved msb.
      87           0 :             res = (res >> 1) | preserved_msb
      88             :         }
      89             : 
      90           0 :         ShiftResults { val: res, carry_out: is_bit_set_32(val, (shift_amount - 1) as i32) }
      91             :     }
      92           0 : }

Generated by: LCOV version 1.16