bits.rsannotatedbits.rssource316 lines · 9.0 KB · raw
1#[allow(clippy::wildcard_imports)]
2use super::*;
3
4impl_modify_op!(
5    [
6        accumulator -> asl_a,
7        direct_page -> asl_dp,
8        direct_page_x -> asl_dpx,
9        absolute -> asl_abs,
10    ]
11    (|registers, value| {
12        registers.psw.carry = value.sign_bit();
13
14        let result = value << 1;
15        registers.psw.zero = result == 0;
16        registers.psw.negative = result.sign_bit();
17        result
18    })
19);
20
21impl_modify_op!(
22    [
23        accumulator -> lsr_a,
24        direct_page -> lsr_dp,
25        direct_page_x -> lsr_dpx,
26        absolute -> lsr_abs,
27    ]
28    (|registers, value| {
29        registers.psw.carry = value.bit(0);
30
31        let result = value >> 1;
32        registers.psw.zero = result == 0;
33        registers.psw.negative = result.sign_bit();
34        result
35    })
36);
37
38impl_modify_op!(
39    [
40        accumulator -> rol_a,
41        direct_page -> rol_dp,
42        direct_page_x -> rol_dpx,
43        absolute -> rol_abs,
44    ]
45    (|registers, value| {
46        let result = (value << 1) | u8::from(registers.psw.carry);
47        registers.psw.zero = result == 0;
48        registers.psw.negative = result.sign_bit();
49        registers.psw.carry = value.sign_bit();
50        result
51    })
52);
53
54impl_modify_op!(
55    [
56        accumulator -> ror_a,
57        direct_page -> ror_dp,
58        direct_page_x -> ror_dpx,
59        absolute -> ror_abs,
60    ]
61    (|registers, value| {
62        let result = (value >> 1) | (u8::from(registers.psw.carry) << 7);
63        registers.psw.zero = result == 0;
64        registers.psw.negative = result.sign_bit();
65        registers.psw.carry = value.bit(0);
66        result
67    })
68);
69
70macro_rules! bit_op {
71    (set $value:expr, $bit:expr) => {
72        $value | (1 << $bit)
73    };
74    (clear $value:expr, $bit:expr) => {
75        $value & !(1 << $bit)
76    };
77}
78
79macro_rules! impl_set_bit {
80    ($name:ident, $op:tt) => {
81        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B, bit: u8) {
82            match cpu.state.cycle {
83                1 => {
84                    cpu.state.t0 = fetch_operand(cpu, bus);
85                }
86                2 => {
87                    let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]);
88                    cpu.state.t1 = bus.read(address);
89                }
90                3 => {
91                    cpu.final_cycle();
92
93                    let value = bit_op!($op cpu.state.t1, bit);
94
95                    let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]);
96                    bus.write(address, value);
97                }
98                _ => invalid_cycle!(cpu)
99            }
100        }
101    };
102}
103
104impl_set_bit!(set1, set);
105impl_set_bit!(clr1, clear);
106
107macro_rules! impl_and1 {
108    ($name:ident $($not:tt)?) => {
109        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
110            match cpu.state.cycle {
111                1 => {
112                    cpu.state.t0 = fetch_operand(cpu, bus);
113                }
114                2 => {
115                    cpu.state.t1 = fetch_operand(cpu, bus);
116                }
117                3 => {
118                    cpu.final_cycle();
119
120                    let address_msb = cpu.state.t1 & 0x1F;
121                    let address = u16::from_le_bytes([cpu.state.t0, address_msb]);
122                    let value = bus.read(address);
123
124                    let bit_index = cpu.state.t1 >> 5;
125                    let bit = value.bit(bit_index);
126
127                    cpu.registers.psw.carry &= $($not)? bit;
128                }
129                _ => invalid_cycle!(cpu)
130            }
131        }
132    }
133}
134
135impl_and1!(and1);
136impl_and1!(and1_cpl !);
137
138macro_rules! impl_or1 {
139    ($name:ident, $op:tt $(, $not:tt)?) => {
140        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
141            match cpu.state.cycle {
142                1 => {
143                    cpu.state.t0 = fetch_operand(cpu, bus);
144                }
145                2 => {
146                    cpu.state.t1 = fetch_operand(cpu, bus);
147                }
148                3 => {
149                    let address_msb = cpu.state.t1 & 0x1F;
150                    let address = u16::from_le_bytes([cpu.state.t0, address_msb]);
151                    cpu.state.t2 = bus.read(address);
152                }
153                4 => {
154                    cpu.final_cycle();
155                    bus.idle();
156
157                    let bit_index = cpu.state.t1 >> 5;
158                    let bit = cpu.state.t2.bit(bit_index);
159
160                    cpu.registers.psw.carry $op $($not)? bit;
161                }
162                _ => invalid_cycle!(cpu)
163            }
164        }
165    }
166}
167
168impl_or1!(or1, |=);
169impl_or1!(or1_cpl, |=, !);
170impl_or1!(eor1, ^=);
171
172pub(crate) fn not1<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
173    match cpu.state.cycle {
174        1 => {
175            cpu.state.t0 = fetch_operand(cpu, bus);
176        }
177        2 => {
178            cpu.state.t1 = fetch_operand(cpu, bus);
179        }
180        3 => {
181            let address_msb = cpu.state.t1 & 0x1F;
182            let address = u16::from_le_bytes([cpu.state.t0, address_msb]);
183            cpu.state.t2 = bus.read(address);
184        }
185        4 => {
186            cpu.final_cycle();
187
188            let bit_index = cpu.state.t1 >> 5;
189            let value = cpu.state.t2 ^ (1 << bit_index);
190
191            let address_msb = cpu.state.t1 & 0x1F;
192            let address = u16::from_le_bytes([cpu.state.t0, address_msb]);
193            bus.write(address, value);
194        }
195        _ => invalid_cycle!(cpu),
196    }
197}
198
199pub(crate) fn mov1_c_bit<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
200    match cpu.state.cycle {
201        1 => {
202            cpu.state.t0 = fetch_operand(cpu, bus);
203        }
204        2 => {
205            cpu.state.t1 = fetch_operand(cpu, bus);
206        }
207        3 => {
208            cpu.final_cycle();
209
210            let address_msb = cpu.state.t1 & 0x1F;
211            let address = u16::from_le_bytes([cpu.state.t0, address_msb]);
212            let value = bus.read(address);
213
214            let bit_index = cpu.state.t1 >> 5;
215            cpu.registers.psw.carry = value.bit(bit_index);
216        }
217        _ => invalid_cycle!(cpu),
218    }
219}
220
221pub(crate) fn mov1_bit_c<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
222    match cpu.state.cycle {
223        1 => {
224            cpu.state.t0 = fetch_operand(cpu, bus);
225        }
226        2 => {
227            cpu.state.t1 = fetch_operand(cpu, bus);
228        }
229        3 => {
230            let address_msb = cpu.state.t1 & 0x1F;
231            let address = u16::from_le_bytes([cpu.state.t0, address_msb]);
232            cpu.state.t2 = bus.read(address);
233        }
234        4 => {
235            bus.idle();
236        }
237        5 => {
238            cpu.final_cycle();
239
240            let bit_index = cpu.state.t1 >> 5;
241            let value = (cpu.state.t2 & !(1 << bit_index))
242                | (u8::from(cpu.registers.psw.carry) << bit_index);
243
244            let address_msb = cpu.state.t1 & 0x1F;
245            let address = u16::from_le_bytes([cpu.state.t0, address_msb]);
246            bus.write(address, value);
247        }
248        _ => invalid_cycle!(cpu),
249    }
250}
251
252macro_rules! bits_op {
253    (set $value:expr, $a:expr) => {
254        $value | $a
255    };
256    (clear $value:expr, $a:expr) => {
257        $value & !$a
258    };
259}
260
261macro_rules! impl_test_and_set_bits {
262    ($name:ident, $op:tt) => {
263        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
264            match cpu.state.cycle {
265                1 => {
266                    cpu.state.t0 = fetch_operand(cpu, bus);
267                }
268                2 => {
269                    cpu.state.t1 = fetch_operand(cpu, bus);
270                }
271                3 => {
272                    // No-op read
273                    let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]);
274                    bus.read(address);
275                }
276                4 => {
277                    let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]);
278                    cpu.state.t2 = bus.read(address);
279                }
280                5 => {
281                    cpu.final_cycle();
282
283                    // Z and N flags are set based on (A - value)
284                    let difference = cpu.registers.a.wrapping_sub(cpu.state.t2);
285                    cpu.registers.psw.zero = difference == 0;
286                    cpu.registers.psw.negative = difference.sign_bit();
287
288                    let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]);
289                    let value = bits_op!($op cpu.state.t2, cpu.registers.a);
290                    bus.write(address, value);
291                }
292                _ => invalid_cycle!(cpu)
293            }
294        }
295    }
296}
297
298impl_test_and_set_bits!(tset1, set);
299impl_test_and_set_bits!(tclr1, clear);
300
301pub(crate) fn xcn<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
302    match cpu.state.cycle {
303        1..=3 => {
304            bus.idle();
305        }
306        4 => {
307            cpu.final_cycle();
308            bus.idle();
309
310            cpu.registers.a = cpu.registers.a.rotate_left(4);
311            cpu.registers.psw.zero = cpu.registers.a == 0;
312            cpu.registers.psw.negative = cpu.registers.a.sign_bit();
313        }
314        _ => invalid_cycle!(cpu),
315    }
316}