bits.rsannotatedbits.rssource657 lines · 23.6 KB · raw
1use crate::core::instructions::{ShiftCount, ShiftDirection};
2use crate::core::{
3    AddressingMode, ConditionCodes, DataRegister, Exception, ExecuteResult, InstructionExecutor,
4    OpSize,
5};
6use crate::traits::BusInterface;
7use jgenesis_common::num::{GetBit, SignBit};
8
9macro_rules! impl_bit_op {
10    ($name:ident, $operator:tt, $read_method:ident, $read_resolved_method:ident, $write_method:ident, $size:expr) => {
11        pub(super) fn $name(&mut self, source: AddressingMode, dest: AddressingMode) -> ExecuteResult<u32> {
12            let operand_l = self.$read_method(source)?;
13
14            let dest_resolved = self.resolve_address_with_post(dest, $size)?;
15            let operand_r = self.$read_resolved_method(dest_resolved)?;
16
17            let value = operand_l $operator operand_r;
18
19            self.cpu.registers.ccr = ConditionCodes {
20                carry: false,
21                overflow: false,
22                zero: value == 0,
23                negative: value.sign_bit(),
24                ..self.cpu.registers.ccr
25            };
26
27            self.$write_method(dest_resolved, value)?;
28
29            Ok(super::binary_op_cycles($size, source, dest))
30        }
31    }
32}
33
34macro_rules! impl_bit_op_all_sizes {
35    ($byte_name:ident, $word_name:ident, $long_word_name:ident, $operator:tt) => {
36        impl_bit_op!(
37            $byte_name,
38            $operator,
39            read_byte,
40            read_byte_resolved_as_result,
41            write_byte_resolved_as_result,
42            OpSize::Byte
43        );
44        impl_bit_op!(
45            $word_name,
46            $operator,
47            read_word,
48            read_word_resolved,
49            write_word_resolved,
50            OpSize::Word
51        );
52        impl_bit_op!(
53            $long_word_name,
54            $operator,
55            read_long_word,
56            read_long_word_resolved,
57            write_long_word_resolved,
58            OpSize::LongWord
59        );
60    };
61}
62
63macro_rules! impl_bit_op_to_ccr {
64    ($name:ident, $operator:tt) => {
65        pub(super) fn $name(&mut self) -> ExecuteResult<u32> {
66            let byte = self.read_byte(AddressingMode::Immediate)?;
67            let value = byte $operator (u8::from(self.cpu.registers.ccr));
68            self.cpu.registers.ccr = value.into();
69
70            Ok(20)
71        }
72    }
73}
74
75macro_rules! impl_bit_op_to_sr {
76    ($name:ident, $operator:tt) => {
77        pub(super) fn $name(&mut self) -> ExecuteResult<u32> {
78            if !self.cpu.registers.supervisor_mode {
79                return Err(Exception::PrivilegeViolation);
80            }
81
82            let word = self.read_word(AddressingMode::Immediate)?;
83            let value = word $operator self.cpu.registers.status_register();
84            self.cpu.registers.set_status_register(value);
85
86            Ok(20)
87        }
88    }
89}
90
91macro_rules! impl_not {
92    ($name:ident, $read_method:ident, $write_method:ident, $size:expr) => {
93        pub(super) fn $name(&mut self, dest: AddressingMode) -> ExecuteResult<u32> {
94            let dest_resolved = self.resolve_address_with_post(dest, $size)?;
95            let value = self.$read_method(dest_resolved)?;
96            let negated = !value;
97
98            self.cpu.registers.ccr = ConditionCodes {
99                carry: false,
100                overflow: false,
101                zero: negated == 0,
102                negative: negated.sign_bit(),
103                ..self.cpu.registers.ccr
104            };
105
106            self.$write_method(dest_resolved, negated)?;
107
108            Ok(super::unary_op_cycles($size, dest))
109        }
110    };
111}
112
113macro_rules! impl_clr {
114    ($name:ident, $read_method:ident, $write_method:ident, $size:expr) => {
115        pub(super) fn $name(&mut self, dest: AddressingMode) -> ExecuteResult<u32> {
116            let dest_resolved = self.resolve_address_with_post(dest, $size)?;
117            // No-op read
118            self.$read_method(dest_resolved)?;
119
120            self.cpu.registers.ccr = ConditionCodes {
121                carry: false,
122                overflow: false,
123                zero: true,
124                negative: false,
125                ..self.cpu.registers.ccr
126            };
127
128            self.$write_method(dest_resolved, 0)?;
129
130            Ok(super::unary_op_cycles($size, dest))
131        }
132    };
133}
134
135macro_rules! impl_bit_test_op {
136    (@cycle_count $source:expr, $dest:expr, $bit:expr $(, $extra_d_write_cycles:expr)?) => {
137        {
138            let dest_cycles = if $dest.is_data_direct() {
139                2 $(+ $extra_d_write_cycles)? + if $bit % 32 < 16 { 0 } else { 2 }
140            } else {
141                4 + $dest.address_calculation_cycles(OpSize::Byte)
142            };
143
144            let source_cycles = match $source {
145                AddressingMode::Immediate => 4,
146                _ => 0
147            };
148
149            4 + source_cycles + dest_cycles
150        }
151    };
152    ($name:ident, |$value:ident, $bit:ident| $body:block $(, extra_d_write_cycles: $extra_d_write_cycles:expr)?) => {
153        pub(super) fn $name(&mut self, source: AddressingMode, dest: AddressingMode) -> ExecuteResult<u32> {
154            let bit_index = self.read_byte(source)?;
155
156            match dest {
157                AddressingMode::DataDirect(register) => {
158                    let $value = register.read_from(&self.cpu.registers);
159                    let $bit = bit_index % 32;
160                    self.cpu.registers.ccr.zero = !$value.bit($bit);
161
162                    let value = $body;
163                    register.write_long_word_to(&mut self.cpu.registers, value);
164                }
165                _ => {
166                    let dest_resolved = self.resolve_address_with_post(dest, OpSize::Byte)?;
167                    let $value = self.read_byte_resolved(dest_resolved);
168                    let $bit = bit_index % 8;
169                    self.cpu.registers.ccr.zero = !$value.bit($bit);
170
171                    let value = $body;
172                    self.write_byte_resolved(dest_resolved, value);
173                }
174            }
175
176            let cycles = impl_bit_test_op!(@cycle_count source, dest, bit_index $(, $extra_d_write_cycles)?);
177            Ok(cycles)
178        }
179    };
180}
181
182macro_rules! impl_shift_register_op {
183    (
184        $name:ident,
185        $operator:tt,
186        $signed_t:ty,
187        $unsigned_t:ty,
188        $register_write_method:ident,
189        carry: $carry_bit:expr
190        $(, set $overflow:ident)?
191    ) => {
192        fn $name(&mut self, register: DataRegister, count: ShiftCount) -> u32 {
193            let shifts = count.get(&self.cpu.registers) % 64;
194
195            self.cpu.registers.ccr.carry = false;
196            self.cpu.registers.ccr.overflow = false;
197
198            let mut value = register.read_from(&self.cpu.registers) as $signed_t;
199
200            for _ in 0..shifts {
201                let carry = value.bit($carry_bit);
202                self.cpu.registers.ccr.carry = carry;
203                self.cpu.registers.ccr.extend = carry;
204
205                $(
206                    if value.sign_bit() != (value $operator 1).sign_bit() {
207                        self.cpu.registers.ccr.$overflow = true;
208                    }
209                )?
210
211                value = value $operator 1;
212            }
213
214            register.$register_write_method(&mut self.cpu.registers, value as $unsigned_t);
215
216            self.cpu.registers.ccr.zero = value == 0;
217            self.cpu.registers.ccr.negative = value.sign_bit();
218
219            shifts.into()
220        }
221    }
222}
223
224macro_rules! impl_rotate_register_op {
225    (@set_initial_carry) => {
226        false
227    };
228    (@set_initial_carry $extend:expr) => {
229        $extend
230    };
231    (@set_carry $carry:expr) => {
232        $carry
233    };
234    (@set_carry $carry:expr, $extend:expr) => {
235        $extend
236    };
237    (
238        $name:ident,
239        $operator:tt,
240        $t:ty,
241        $register_write_method:ident,
242        carry: $carry_bit:expr
243        $(, rotate_in: $opposite_op:tt $opposite_shift:expr)?
244        $(, thru $extend:ident)?
245    ) => {
246        fn $name(&mut self, register: DataRegister, count: ShiftCount) -> u32 {
247            let rotates = count.get(&self.cpu.registers) % 64;
248
249            self.cpu.registers.ccr.overflow = false;
250            self.cpu.registers.ccr.carry = impl_rotate_register_op!(@set_initial_carry $( self.cpu.registers.ccr.$extend )?);
251
252            let mut value = register.read_from(&self.cpu.registers) as $t;
253            for _ in 0..rotates {
254                let carry = value.bit($carry_bit);
255                let rotating_in = impl_rotate_register_op!(@set_carry carry $(, self.cpu.registers.ccr.$extend )?);
256
257                value = (value $operator 1) | (<$t>::from(rotating_in) $( $opposite_op $opposite_shift )? );
258
259                self.cpu.registers.ccr.carry = carry;
260                $(
261                    self.cpu.registers.ccr.$extend = carry;
262                )?
263            }
264
265            register.$register_write_method(&mut self.cpu.registers, value);
266
267            self.cpu.registers.ccr.zero = value == 0;
268            self.cpu.registers.ccr.negative = value.sign_bit();
269
270            rotates.into()
271        }
272    };
273}
274
275macro_rules! impl_tst {
276    ($name:ident, $read_method:ident, $size:expr) => {
277        pub(super) fn $name(&mut self, source: AddressingMode) -> ExecuteResult<u32> {
278            let value = self.$read_method(source)?;
279
280            self.cpu.registers.ccr = ConditionCodes {
281                carry: false,
282                overflow: false,
283                zero: value == 0,
284                negative: value.sign_bit(),
285                ..self.cpu.registers.ccr
286            };
287
288            Ok(4 + source.address_calculation_cycles($size))
289        }
290    };
291}
292
293#[allow(clippy::assign_op_pattern)]
294impl<B: BusInterface> InstructionExecutor<'_, '_, B> {
295    impl_bit_op_all_sizes!(and_byte, and_word, and_long_word, &);
296    impl_bit_op_all_sizes!(or_byte, or_word, or_long_word, |);
297    impl_bit_op_all_sizes!(eor_byte, eor_word, eor_long_word, ^);
298
299    impl_bit_op_to_ccr!(andi_to_ccr, &);
300    impl_bit_op_to_ccr!(ori_to_ccr, |);
301    impl_bit_op_to_ccr!(eori_to_ccr, ^);
302
303    impl_bit_op_to_sr!(andi_to_sr, &);
304    impl_bit_op_to_sr!(ori_to_sr, |);
305    impl_bit_op_to_sr!(eori_to_sr, ^);
306
307    pub(super) fn btst(
308        &mut self,
309        source: AddressingMode,
310        dest: AddressingMode,
311    ) -> ExecuteResult<u32> {
312        let bit_index = self.read_byte(source)?;
313
314        match dest {
315            AddressingMode::DataDirect(register) => {
316                let value = register.read_from(&self.cpu.registers);
317                let bit = bit_index % 32;
318                self.cpu.registers.ccr.zero = !value.bit(bit);
319            }
320            _ => {
321                let dest_resolved = self.resolve_address_with_post(dest, OpSize::Byte)?;
322                let value = self.read_byte_resolved(dest_resolved);
323                let bit = bit_index % 8;
324                self.cpu.registers.ccr.zero = !value.bit(bit);
325            }
326        }
327
328        let dest_cycles = match dest {
329            AddressingMode::DataDirect(..) => 2,
330            AddressingMode::Immediate => 6,
331            _ => dest.address_calculation_cycles(OpSize::Byte),
332        };
333
334        let source_cycles = match source {
335            AddressingMode::Immediate => 4,
336            _ => 0,
337        };
338
339        Ok(4 + source_cycles + dest_cycles)
340    }
341
342    impl_bit_test_op!(bclr, |value, bit| { value & !(1 << bit) }, extra_d_write_cycles: 2);
343    impl_bit_test_op!(bset, |value, bit| { value | (1 << bit) });
344    impl_bit_test_op!(bchg, |value, bit| {
345        if value.bit(bit) { value & !(1 << bit) } else { value | (1 << bit) }
346    });
347
348    impl_shift_register_op!(asl_register_u8, <<, i8, u8, write_byte_to, carry: 7, set overflow);
349    impl_shift_register_op!(asl_register_u16, <<, i16, u16, write_word_to, carry: 15, set overflow);
350    impl_shift_register_op!(asl_register_u32, <<, i32, u32, write_long_word_to, carry: 31, set overflow);
351
352    impl_shift_register_op!(asr_register_u8, >>, i8, u8, write_byte_to, carry: 0, set overflow);
353    impl_shift_register_op!(asr_register_u16, >>, i16, u16, write_word_to, carry: 0, set overflow);
354    impl_shift_register_op!(asr_register_u32, >>, i32, u32, write_long_word_to, carry: 0, set overflow);
355
356    impl_shift_register_op!(lsl_register_u8, <<, u8, u8, write_byte_to, carry: 7);
357    impl_shift_register_op!(lsl_register_u16, <<, u16, u16, write_word_to, carry: 15);
358    impl_shift_register_op!(lsl_register_u32, <<, u32, u32, write_long_word_to, carry: 31);
359
360    impl_shift_register_op!(lsr_register_u8, >>, u8, u8, write_byte_to, carry: 0);
361    impl_shift_register_op!(lsr_register_u16, >>, u16, u16, write_word_to, carry: 0);
362    impl_shift_register_op!(lsr_register_u32, >>, u32, u32, write_long_word_to, carry: 0);
363
364    impl_rotate_register_op!(rol_register_u8, <<, u8, write_byte_to, carry: 7);
365    impl_rotate_register_op!(rol_register_u16, <<, u16, write_word_to, carry: 15);
366    impl_rotate_register_op!(rol_register_u32, <<, u32, write_long_word_to, carry: 31);
367
368    impl_rotate_register_op!(ror_register_u8, >>, u8, write_byte_to, carry: 0, rotate_in: << 7);
369    impl_rotate_register_op!(ror_register_u16, >>, u16, write_word_to, carry: 0, rotate_in: << 15);
370    impl_rotate_register_op!(ror_register_u32, >>, u32, write_long_word_to, carry: 0, rotate_in: << 31);
371
372    impl_rotate_register_op!(roxl_register_u8, <<, u8, write_byte_to, carry: 7, thru extend);
373    impl_rotate_register_op!(roxl_register_u16, <<, u16, write_word_to, carry: 15, thru extend);
374    impl_rotate_register_op!(roxl_register_u32, <<, u32, write_long_word_to, carry: 31, thru extend);
375
376    impl_rotate_register_op!(roxr_register_u8, >>, u8, write_byte_to, carry: 0, rotate_in: << 7, thru extend);
377    impl_rotate_register_op!(roxr_register_u16, >>, u16, write_word_to, carry: 0, rotate_in: << 15, thru extend);
378    impl_rotate_register_op!(roxr_register_u32, >>, u32, write_long_word_to, carry: 0, rotate_in: << 31, thru extend);
379
380    impl_not!(not_byte, read_byte_resolved_as_result, write_byte_resolved_as_result, OpSize::Byte);
381    impl_not!(not_word, read_word_resolved, write_word_resolved, OpSize::Word);
382    impl_not!(not_long_word, read_long_word_resolved, write_long_word_resolved, OpSize::LongWord);
383
384    impl_clr!(clr_byte, read_byte_resolved_as_result, write_byte_resolved_as_result, OpSize::Byte);
385    impl_clr!(clr_word, read_word_resolved, write_word_resolved, OpSize::Word);
386    impl_clr!(clr_long_word, read_long_word_resolved, write_long_word_resolved, OpSize::LongWord);
387
388    pub(super) fn ext(&mut self, size: OpSize, register: DataRegister) -> u32 {
389        let (zero, sign) = match size {
390            OpSize::Word => {
391                let byte = register.read_from(&self.cpu.registers) as u8;
392                let sign_extended = byte as i8 as u16;
393                register.write_word_to(&mut self.cpu.registers, sign_extended);
394                (sign_extended == 0, sign_extended.sign_bit())
395            }
396            OpSize::LongWord => {
397                let word = register.read_from(&self.cpu.registers) as u16;
398                let sign_extended = word as i16 as u32;
399                register.write_long_word_to(&mut self.cpu.registers, sign_extended);
400                (sign_extended == 0, sign_extended.sign_bit())
401            }
402            OpSize::Byte => panic!("EXT does not support size byte"),
403        };
404
405        self.cpu.registers.ccr = ConditionCodes {
406            carry: false,
407            overflow: false,
408            zero,
409            negative: sign,
410            ..self.cpu.registers.ccr
411        };
412
413        4
414    }
415
416    pub(super) fn swap(&mut self, register: DataRegister) -> u32 {
417        let [b3, b2, b1, b0] = register.read_from(&self.cpu.registers).to_be_bytes();
418        let value = u32::from_be_bytes([b1, b0, b3, b2]);
419        register.write_long_word_to(&mut self.cpu.registers, value);
420
421        self.cpu.registers.ccr = ConditionCodes {
422            carry: false,
423            overflow: false,
424            zero: value == 0,
425            negative: value.sign_bit(),
426            ..self.cpu.registers.ccr
427        };
428
429        4
430    }
431
432    pub(super) fn asd_register(
433        &mut self,
434        size: OpSize,
435        direction: ShiftDirection,
436        register: DataRegister,
437        count: ShiftCount,
438    ) -> u32 {
439        let shifts = match (size, direction) {
440            (OpSize::Byte, ShiftDirection::Left) => self.asl_register_u8(register, count),
441            (OpSize::Byte, ShiftDirection::Right) => self.asr_register_u8(register, count),
442            (OpSize::Word, ShiftDirection::Left) => self.asl_register_u16(register, count),
443            (OpSize::Word, ShiftDirection::Right) => self.asr_register_u16(register, count),
444            (OpSize::LongWord, ShiftDirection::Left) => self.asl_register_u32(register, count),
445            (OpSize::LongWord, ShiftDirection::Right) => self.asr_register_u32(register, count),
446        };
447
448        shift_register_cycles(size, shifts)
449    }
450
451    pub(super) fn asd_memory(
452        &mut self,
453        direction: ShiftDirection,
454        dest: AddressingMode,
455    ) -> ExecuteResult<u32> {
456        let dest_resolved = self.resolve_address_with_post(dest, OpSize::Word)?;
457        let original = self.read_word_resolved(dest_resolved)?;
458
459        let (value, carry) = match direction {
460            ShiftDirection::Left => (original << 1, original.bit(15)),
461            ShiftDirection::Right => ((original >> 1) | (original & 0x8000), original.bit(0)),
462        };
463
464        let overflow = original.sign_bit() != value.sign_bit();
465
466        self.cpu.registers.ccr = ConditionCodes {
467            carry,
468            overflow,
469            zero: value == 0,
470            negative: value.sign_bit(),
471            extend: carry,
472        };
473
474        self.write_word_resolved(dest_resolved, value)?;
475
476        Ok(shift_memory_cycles(dest))
477    }
478
479    pub(super) fn lsd_register(
480        &mut self,
481        size: OpSize,
482        direction: ShiftDirection,
483        register: DataRegister,
484        count: ShiftCount,
485    ) -> u32 {
486        let shifts = match (size, direction) {
487            (OpSize::Byte, ShiftDirection::Left) => self.lsl_register_u8(register, count),
488            (OpSize::Byte, ShiftDirection::Right) => self.lsr_register_u8(register, count),
489            (OpSize::Word, ShiftDirection::Left) => self.lsl_register_u16(register, count),
490            (OpSize::Word, ShiftDirection::Right) => self.lsr_register_u16(register, count),
491            (OpSize::LongWord, ShiftDirection::Left) => self.lsl_register_u32(register, count),
492            (OpSize::LongWord, ShiftDirection::Right) => self.lsr_register_u32(register, count),
493        };
494
495        shift_register_cycles(size, shifts)
496    }
497
498    pub(super) fn lsd_memory(
499        &mut self,
500        direction: ShiftDirection,
501        dest: AddressingMode,
502    ) -> ExecuteResult<u32> {
503        let dest_resolved = self.resolve_address_with_post(dest, OpSize::Word)?;
504        let original = self.read_word_resolved(dest_resolved)?;
505
506        let (value, carry) = match direction {
507            ShiftDirection::Left => (original << 1, original.bit(15)),
508            ShiftDirection::Right => (original >> 1, original.bit(0)),
509        };
510
511        self.cpu.registers.ccr = ConditionCodes {
512            carry,
513            overflow: false,
514            zero: value == 0,
515            negative: value.sign_bit(),
516            extend: carry,
517        };
518
519        self.write_word_resolved(dest_resolved, value)?;
520
521        Ok(shift_memory_cycles(dest))
522    }
523
524    pub(super) fn rod_register(
525        &mut self,
526        size: OpSize,
527        direction: ShiftDirection,
528        register: DataRegister,
529        count: ShiftCount,
530    ) -> u32 {
531        let rotates = match (size, direction) {
532            (OpSize::Byte, ShiftDirection::Left) => self.rol_register_u8(register, count),
533            (OpSize::Byte, ShiftDirection::Right) => self.ror_register_u8(register, count),
534            (OpSize::Word, ShiftDirection::Left) => self.rol_register_u16(register, count),
535            (OpSize::Word, ShiftDirection::Right) => self.ror_register_u16(register, count),
536            (OpSize::LongWord, ShiftDirection::Left) => self.rol_register_u32(register, count),
537            (OpSize::LongWord, ShiftDirection::Right) => self.ror_register_u32(register, count),
538        };
539
540        shift_register_cycles(size, rotates)
541    }
542
543    pub(super) fn rod_memory(
544        &mut self,
545        direction: ShiftDirection,
546        dest: AddressingMode,
547    ) -> ExecuteResult<u32> {
548        let dest_resolved = self.resolve_address_with_post(dest, OpSize::Word)?;
549        let original = self.read_word_resolved(dest_resolved)?;
550
551        let (value, carry) = match direction {
552            ShiftDirection::Left => {
553                ((original << 1) | u16::from(original.sign_bit()), original.sign_bit())
554            }
555            ShiftDirection::Right => {
556                ((original >> 1) | (u16::from(original.bit(0)) << 15), original.bit(0))
557            }
558        };
559
560        self.cpu.registers.ccr = ConditionCodes {
561            carry,
562            overflow: false,
563            zero: value == 0,
564            negative: value.sign_bit(),
565            ..self.cpu.registers.ccr
566        };
567
568        self.write_word_resolved(dest_resolved, value)?;
569
570        Ok(shift_memory_cycles(dest))
571    }
572
573    pub(super) fn roxd_register(
574        &mut self,
575        size: OpSize,
576        direction: ShiftDirection,
577        register: DataRegister,
578        count: ShiftCount,
579    ) -> u32 {
580        let rotates = match (size, direction) {
581            (OpSize::Byte, ShiftDirection::Left) => self.roxl_register_u8(register, count),
582            (OpSize::Byte, ShiftDirection::Right) => self.roxr_register_u8(register, count),
583            (OpSize::Word, ShiftDirection::Left) => self.roxl_register_u16(register, count),
584            (OpSize::Word, ShiftDirection::Right) => self.roxr_register_u16(register, count),
585            (OpSize::LongWord, ShiftDirection::Left) => self.roxl_register_u32(register, count),
586            (OpSize::LongWord, ShiftDirection::Right) => self.roxr_register_u32(register, count),
587        };
588
589        shift_register_cycles(size, rotates)
590    }
591
592    pub(super) fn roxd_memory(
593        &mut self,
594        direction: ShiftDirection,
595        dest: AddressingMode,
596    ) -> ExecuteResult<u32> {
597        let dest_resolved = self.resolve_address_with_post(dest, OpSize::Word)?;
598        let original = self.read_word_resolved(dest_resolved)?;
599
600        let extend = self.cpu.registers.ccr.extend;
601        let (value, carry) = match direction {
602            ShiftDirection::Left => ((original << 1) | u16::from(extend), original.bit(15)),
603            ShiftDirection::Right => ((original >> 1) | (u16::from(extend) << 15), original.bit(0)),
604        };
605
606        self.cpu.registers.ccr = ConditionCodes {
607            carry,
608            overflow: false,
609            zero: value == 0,
610            negative: value.sign_bit(),
611            extend: carry,
612        };
613
614        self.write_word_resolved(dest_resolved, value)?;
615
616        Ok(shift_memory_cycles(dest))
617    }
618
619    impl_tst!(tst_byte, read_byte, OpSize::Byte);
620    impl_tst!(tst_word, read_word, OpSize::Word);
621    impl_tst!(tst_long_word, read_long_word, OpSize::LongWord);
622
623    pub(super) fn tas(&mut self, dest: AddressingMode) -> ExecuteResult<u32> {
624        let dest_resolved = self.resolve_address_with_post(dest, OpSize::Byte)?;
625        let value = self.read_byte_resolved(dest_resolved);
626
627        self.cpu.registers.ccr = ConditionCodes {
628            carry: false,
629            overflow: false,
630            zero: value == 0,
631            negative: value.sign_bit(),
632            ..self.cpu.registers.ccr
633        };
634
635        if dest.is_data_direct() || self.cpu.allow_tas_writes {
636            self.write_byte_resolved(dest_resolved, value | 0x80);
637        }
638
639        Ok(if dest.is_data_direct() {
640            4
641        } else {
642            10 + dest.address_calculation_cycles(OpSize::Byte)
643        })
644    }
645}
646
647fn shift_register_cycles(size: OpSize, shifts: u32) -> u32 {
648    let base_cycles = match size {
649        OpSize::Byte | OpSize::Word => 6,
650        OpSize::LongWord => 8,
651    };
652    base_cycles + 2 * shifts
653}
654
655fn shift_memory_cycles(dest: AddressingMode) -> u32 {
656    8 + dest.address_calculation_cycles(OpSize::Word)
657}