dustbox/cpu/
mod.rs

1// these modules are re-exported as a single module
2
3pub use self::decoder::*;
4mod decoder;
5
6pub use self::instruction::*;
7mod instruction;
8
9pub use self::segment::*;
10mod segment;
11
12pub use self::register::*;
13mod register;
14
15pub use self::flag::*;
16mod flag;
17
18pub use self::parameter::*;
19mod parameter;
20
21pub use self::op::*;
22mod op;
23
24pub use self::encoder::*;
25mod encoder;
26
27use std::{mem, u8};
28use std::num::Wrapping;
29use std::marker::PhantomData;
30
31use crate::gpu::GPU;
32use crate::interrupt;
33use crate::machine::Machine;
34use crate::memory::{MMU, MemoryAddress};
35
36/// prints diagnostics if writes to memory close to SS:SP occurs
37const DEBUG_PARAMS_TOUCHING_STACK: bool = false;
38
39/// prints diagnostics of stack usage (push / pop)
40const DEBUG_STACK: bool = false;
41
42#[derive(Debug)]
43pub enum Exception {
44    // http://wiki.osdev.org/Interrupt_Vector_Table
45    DIV0 = 0,    // Divide by 0
46    UD = 6,      // Invalid opcode (UD2)
47    DF = 8,      // Double fault
48    TS = 10,     // Invalid TSS
49    NP = 11,     // Segment not present
50    SS = 12,     // Stack-segment fault
51    GP = 13,     // General protection fault
52    PF = 14,     // Page fault
53}
54
55pub struct CPU {
56    pub instruction_count: usize,
57    pub cycle_count: usize,
58
59    /// general purpose registers, segment registers, ip
60    pub regs: RegisterState,
61
62    /// signals to debugger we hit an error (used by debugger)
63    pub fatal_error: bool,
64
65    /// toggles non-deterministic behaviour (used by tests)
66    pub deterministic: bool,
67
68    pub decoder: Decoder,
69    pub clock_hz: usize,
70}
71
72impl CPU {
73    pub fn default() -> Self {
74        CPU {
75            instruction_count: 0,
76            cycle_count: 0,
77            regs: RegisterState::default(),
78            fatal_error: false,
79            deterministic: false,
80            decoder: Decoder::default(),
81            clock_hz: 5_000_000, // Intel 8086: 0.330 MIPS at 5.000 MHz
82        }
83    }
84
85    pub fn deterministic() -> Self {
86        let mut res = Self::default();
87        res.deterministic = true;
88        res
89    }
90
91    pub fn get_r8(&self, r: R) -> u8 {
92        self.regs.get_r8(r)
93    }
94
95    pub fn set_r8(&mut self, r: R, val: u8) {
96        self.regs.set_r8(r, val);
97    }
98
99    pub fn get_r16(&self, r: R) -> u16 {
100        self.regs.get_r16(r)
101    }
102
103    pub fn set_r16(&mut self, r: R, val: u16) {
104        self.regs.set_r16(r, val);
105    }
106
107    pub fn get_r32(&self, r: R) -> u32 {
108        self.regs.get_r32(r)
109    }
110
111    pub fn set_r32(&mut self, r: R, val: u32) {
112        self.regs.set_r32(r, val);
113    }
114
115    pub fn exception(&mut self, which: &Exception, error: usize) {
116        /*
117        #define CPU_INT_SOFTWARE    0x1
118        #define CPU_INT_EXCEPTION   0x2
119        #define CPU_INT_HAS_ERROR   0x4
120        #define CPU_INT_NOIOPLCHECK 0x8
121        */
122        println!("Exception {:?}, error {}", which, error);
123
124        // CPU_Interrupt(which,CPU_INT_EXCEPTION | ((which>=8) ? CPU_INT_HAS_ERROR : 0),reg_eip);
125    }
126
127    pub fn cmp8(&mut self, dst: usize, src: usize) {
128        let res = (Wrapping(dst) - Wrapping(src)).0;
129
130        // The CF, OF, SF, ZF, AF, and PF flags are set according to the result.
131        self.regs.flags.set_carry_u8(res);
132        self.regs.flags.set_overflow_sub_u8(res, src, dst);
133        self.regs.flags.set_sign_u8(res);
134        self.regs.flags.set_zero_u8(res);
135        self.regs.flags.set_adjust(res, src, dst);
136        self.regs.flags.set_parity(res);
137    }
138
139    pub fn cmp16(&mut self, dst: usize, src: usize) {
140        let res = (Wrapping(dst) - Wrapping(src)).0;
141
142        // The CF, OF, SF, ZF, AF, and PF flags are set according to the result.
143        self.regs.flags.set_carry_u16(res);
144        self.regs.flags.set_overflow_sub_u16(res, src, dst);
145        self.regs.flags.set_sign_u16(res);
146        self.regs.flags.set_zero_u16(res);
147        self.regs.flags.set_adjust(res, src, dst);
148        self.regs.flags.set_parity(res);
149    }
150
151    pub fn cmp32(&mut self, dst: usize, src: usize) {
152        let res = (Wrapping(dst) - Wrapping(src)).0;
153
154        // The CF, OF, SF, ZF, AF, and PF flags are set according to the result.
155        self.regs.flags.set_carry_u32(res);
156        self.regs.flags.set_overflow_sub_u32(res, src, dst);
157        self.regs.flags.set_sign_u32(res);
158        self.regs.flags.set_zero_u32(res);
159        self.regs.flags.set_adjust(res, src, dst);
160        self.regs.flags.set_parity(res);
161    }
162
163    pub fn push16(&mut self, mmu: &mut MMU, data: u16) {
164        let sp = (Wrapping(self.get_r16(R::SP)) - Wrapping(2)).0;
165        self.set_r16(R::SP, sp);
166        let ss = self.get_r16(R::SS);
167        if DEBUG_STACK {
168            println!("[{}] push16 {:04X} to {:04X}:{:04X}", self.get_memory_address(), data, ss, sp);
169        }
170        mmu.write_u16(ss, sp, data);
171    }
172
173    pub fn push32(&mut self, mmu: &mut MMU, data: u32) {
174        let sp = (Wrapping(self.get_r16(R::SP)) - Wrapping(4)).0;
175        self.set_r16(R::SP, sp);
176        let ss = self.get_r16(R::SS);
177        if DEBUG_STACK {
178            println!("[{}] push32 {:04X} to {:04X}:{:04X}", self.get_memory_address(), data, ss, sp);
179        }
180        mmu.write_u32(ss, sp, data);
181    }
182
183    pub fn pop16(&mut self, mmu: &mut MMU) -> u16 {
184        let ss = self.get_r16(R::SS);
185        let sp = self.get_r16(R::SP);
186        let data = mmu.read_u16(ss, self.get_r16(R::SP));
187        if DEBUG_STACK {
188            println!("[{}] pop16 {:04X} from {:04X}:{:04X}", self.get_memory_address(), data, ss, sp);
189        }
190        let sp = (Wrapping(sp) + Wrapping(2)).0;
191        self.set_r16(R::SP, sp);
192        data
193    }
194
195    pub fn pop32(&mut self, mmu: &mut MMU) -> u32 {
196        let ss = self.get_r16(R::SS);
197        let sp = self.get_r16(R::SP);
198        let data = mmu.read_u32(ss, sp);
199        if DEBUG_STACK {
200            println!("[{}] pop32 {:04X} from {:04X}:{:04X}", self.get_memory_address(), data, ss, sp);
201        }
202        let sp = (Wrapping(sp) + Wrapping(4)).0;
203        self.set_r16(R::SP, sp);
204        data
205    }
206
207    /// returns the absoute address of CS:IP
208    pub fn get_address(&self) -> u32 {
209        self.get_memory_address().value()
210    }
211
212    /// returns cs, ip
213    pub fn get_address_pair(&self) -> (u16, u16) {
214        (self.get_r16(R::CS), self.regs.ip)
215    }
216
217    /// returns the address of CS:IP as a MemoryAddress::RealSegmentOffset
218    pub fn get_memory_address(&self) -> MemoryAddress {
219        MemoryAddress::RealSegmentOffset(self.get_r16(R::CS), self.regs.ip)
220    }
221
222    fn read_u8(&mut self, mmu: &MMU) -> u8 {
223        let (seg, off) = self.get_address_pair();
224        let b = mmu.read_u8(seg, off);
225        self.regs.ip += 1;
226        b
227    }
228
229    fn read_u16(&mut self, mmu: &MMU) -> u16 {
230        let lo = self.read_u8(mmu);
231        let hi = self.read_u8(mmu);
232        u16::from(hi) << 8 | u16::from(lo)
233    }
234
235    fn read_s8(&mut self,  mmu: &MMU) -> i8 {
236        self.read_u8(mmu) as i8
237    }
238
239    fn read_s16(&mut self, mmu: &MMU) -> i16 {
240        self.read_u16(mmu) as i16
241    }
242
243    fn read_rel8(&mut self, mmu: &MMU) -> u16 {
244        let val = self.read_u8(mmu) as i8;
245        (self.regs.ip as i16 + i16::from(val)) as u16
246    }
247
248    fn read_rel16(&mut self, mmu: &MMU) -> u16 {
249        let val = self.read_u16(mmu) as i16;
250        (self.regs.ip as i16 + val) as u16
251    }
252
253    /// returns "segment, offset" pair
254    fn get_amode_addr(&self, amode: &AMode) -> (u16, u16) {
255        match *amode {
256            AMode::BX => (self.get_r16(R::DS), self.get_r16(R::BX)),
257            AMode::BP => (self.get_r16(R::SS), self.get_r16(R::BP)),
258            AMode::SI => (self.get_r16(R::DS), self.get_r16(R::SI)),
259            AMode::DI => (self.get_r16(R::DS), self.get_r16(R::DI)),
260            AMode::BXSI => (self.get_r16(R::DS), self.get_r16(R::BX) + self.get_r16(R::SI)),
261            AMode::BXDI => (self.get_r16(R::DS), self.get_r16(R::BX) + self.get_r16(R::DI)),
262            AMode::BPSI => (self.get_r16(R::SS), self.get_r16(R::BP) + self.get_r16(R::SI)),
263            AMode::BPDI => (self.get_r16(R::SS), self.get_r16(R::BP) + self.get_r16(R::DI)),
264            _ => panic!("xxx"),
265        }
266    }
267
268    /// used by lds, les
269    pub fn read_segment_selector(&self, mmu: &MMU, p: &Parameter) -> (u16, u16) {
270        let (segment, offset) = match *p {
271            Parameter::Ptr16(seg, imm) => (self.segment(seg), imm),
272            Parameter::Ptr16Amode(_, ref amode) => self.get_amode_addr(amode),
273            Parameter::Ptr16AmodeS8(_, ref amode, imms) => {
274                let (seg, off) = self.get_amode_addr(amode);
275                (seg, (i32::from(off) + i32::from(imms)) as u16)
276            }
277            /*
278            Parameter::Ptr16AmodeS16(_, ref amode, imms) => {
279                let (seg, off) = self.get_amode_addr(amode);
280                (seg, (i32::from(off) + i32::from(imms)) as u16)
281            }
282            */
283            _ => panic!("unhandled parameter {:?}", p),
284        };
285
286        let o_val = mmu.read_u16(segment, offset);
287        let s_val = mmu.read_u16(segment, offset + 2);
288        (s_val, o_val)
289    }
290
291    /// returns the address of pointer, used by LEA
292    pub fn read_parameter_address(&mut self, p: &Parameter) -> usize {
293        match *p {
294            Parameter::Ptr16Amode(_, ref amode) => self.amode(amode),
295            Parameter::Ptr16AmodeS8(_, ref amode, imm) => (Wrapping(self.amode(amode)) + Wrapping(imm as usize)).0,
296            Parameter::Ptr16AmodeS16(_, ref amode, imm) => (Wrapping(self.amode(amode)) + Wrapping(imm as usize)).0,
297            Parameter::Ptr16(_, imm) => imm as usize,
298            _ => panic!("unhandled parameter: {:?} at {:06X}", p, self.get_address()),
299        }
300    }
301
302    pub fn read_parameter_imm(&self, p: &Parameter) -> usize {
303        match *p {
304            Parameter::Imm8(imm) => imm as usize,
305            Parameter::Imm16(imm) => imm as usize,
306            Parameter::ImmS8(imm) => imm as usize,
307            _ => panic!("read_parameter_imm only allows imm-type params: {:?}", p),
308        }
309    }
310
311    pub fn read_parameter_value(&mut self, mmu: &MMU, p: &Parameter) -> usize {
312        match *p {
313            Parameter::Imm8(imm) => imm as usize,
314            Parameter::Imm16(imm) => imm as usize,
315            Parameter::Imm32(imm) => imm as usize,
316            Parameter::ImmS8(imm) => imm as usize,
317            Parameter::Reg8(r) => self.get_r8(r) as usize,
318            Parameter::Reg16(r) => self.get_r16(r) as usize,
319            Parameter::Reg32(r) => self.get_r32(r) as usize,
320            Parameter::SReg16(sr) => self.get_r16(sr) as usize,
321            Parameter::Ptr8(seg, imm) => mmu.read_u8(self.segment(seg), imm) as usize,
322            Parameter::Ptr8Amode(seg, ref amode) => {
323                let seg = self.segment(seg);
324                let offset = self.amode(amode) as u16;
325                mmu.read_u8(seg, offset) as usize
326            }
327            Parameter::Ptr8AmodeS8(seg, ref amode, imm) => {
328                let seg = self.segment(seg);
329                let offset = (Wrapping(self.amode(amode) as u16) + Wrapping(imm as u16)).0;
330                mmu.read_u8(seg, offset) as usize
331            }
332            Parameter::Ptr8AmodeS16(seg, ref amode, imm) => {
333                let seg = self.segment(seg);
334                let offset = (Wrapping(self.amode(amode) as u16) + Wrapping(imm as u16)).0;
335                mmu.read_u8(seg, offset) as usize
336            }
337            Parameter::Ptr16(seg, imm) => mmu.read_u16(self.segment(seg), imm) as usize,
338            Parameter::Ptr16Amode(seg, ref amode) => {
339                let seg = self.segment(seg);
340                let offset = self.amode(amode) as u16;
341                mmu.read_u16(seg, offset) as usize
342            }
343            Parameter::Ptr16AmodeS8(seg, ref amode, imm) => {
344                let seg = self.segment(seg);
345                let offset = (Wrapping(self.amode(amode) as u16) + Wrapping(imm as u16)).0;
346                mmu.read_u16(seg, offset) as usize
347            }
348            Parameter::Ptr16AmodeS16(seg, ref amode, imm) => {
349                let seg = self.segment(seg);
350                let offset = (Wrapping(self.amode(amode) as u16) + Wrapping(imm as u16)).0;
351                mmu.read_u16(seg, offset) as usize
352            }
353            Parameter::Ptr32(seg, offset) => mmu.read_u32(self.segment(seg), offset) as usize,
354            Parameter::Ptr32Amode(seg, ref amode) => {
355                let seg = self.segment(seg);
356                let offset = self.amode(amode) as u16;
357                mmu.read_u32(seg, offset) as usize
358            }
359            Parameter::Ptr32AmodeS8(seg, ref amode, imm) => {
360                let seg = self.segment(seg);
361                let offset = (Wrapping(self.amode(amode) as u16) + Wrapping(imm as u16)).0;
362                mmu.read_u32(seg, offset) as usize
363            }
364            _ => {
365                let (seg, off) = self.get_address_pair();
366                panic!("unhandled parameter: {:?} at {:04X}:{:04X} ({:06X} flat)", p, seg, off, self.get_address());
367            },
368        }
369    }
370
371    pub fn write_parameter_u8(&mut self, mmu: &mut MMU, p: &Parameter, data: u8) {
372        match *p {
373            Parameter::Reg8(r) => self.set_r8(r, data),
374            Parameter::Ptr8(seg, offset) => {
375                let seg = self.segment(seg);
376                self.debug_write_u8(seg, offset, data);
377                mmu.write_u8(seg, offset, data);
378            }
379            Parameter::Ptr8Amode(seg, ref amode) => {
380                let seg = self.segment(seg);
381                let offset = self.amode(amode) as u16;
382                self.debug_write_u8(seg, offset, data);
383                mmu.write_u8(seg, offset, data);
384            }
385            Parameter::Ptr8AmodeS8(seg, ref amode, imm) => {
386                let seg = self.segment(seg);
387                let offset = (Wrapping(self.amode(amode) as u16) + Wrapping(imm as u16)).0;
388                self.debug_write_u8(seg, offset, data);
389                mmu.write_u8(seg, offset, data);
390            }
391            Parameter::Ptr8AmodeS16(seg, ref amode, imm) => {
392                let seg = self.segment(seg);
393                let offset = (Wrapping(self.amode(amode) as u16) + Wrapping(imm as u16)).0;
394                self.debug_write_u8(seg, offset, data);
395                mmu.write_u8(seg, offset, data);
396            }
397            _ => panic!("write_parameter_u8 unhandled type {:?} at {:06X}", p, self.get_address()),
398        }
399    }
400
401    pub fn write_parameter_u16(&mut self, mmu: &mut MMU, segment: Segment, p: &Parameter, data: u16) {
402        match *p {
403            Parameter::Reg16(r) |
404            Parameter::SReg16(r) => self.set_r16(r, data),
405            Parameter::Imm16(imm) => {
406                let seg = self.segment(segment);
407                self.debug_write_u16(seg, imm, data);
408                mmu.write_u16(seg, imm, data);
409            }
410            Parameter::Ptr16(seg, offset) => {
411                let seg = self.segment(seg);
412                self.debug_write_u16(seg, offset, data);
413                mmu.write_u16(seg, offset, data);
414            }
415            Parameter::Ptr16Amode(seg, ref amode) => {
416                let seg = self.segment(seg);
417                let offset = self.amode(amode) as u16;
418                self.debug_write_u16(seg, offset, data);
419                mmu.write_u16(seg, offset, data);
420            }
421            Parameter::Ptr16AmodeS8(seg, ref amode, imm) => {
422                let seg = self.segment(seg);
423                let offset = (Wrapping(self.amode(amode) as u16) + Wrapping(imm as u16)).0;
424                self.debug_write_u16(seg, offset, data);
425                mmu.write_u16(seg, offset, data);
426            }
427            Parameter::Ptr16AmodeS16(seg, ref amode, imm) => {
428                let seg = self.segment(seg);
429                let offset = (Wrapping(self.amode(amode) as u16) + Wrapping(imm as u16)).0;
430                self.debug_write_u16(seg, offset, data);
431                mmu.write_u16(seg, offset, data);
432            }
433            _ => panic!("unhandled type {:?} at {:06X}", p, self.get_address()),
434        }
435    }
436
437    pub fn write_parameter_u32(&mut self, mmu: &mut MMU, _segment: Segment, p: &Parameter, data: u32) {
438        match *p {
439            Parameter::Reg32(r) => self.set_r32(r, data),
440            Parameter::Ptr32(seg, offset) => {
441                let seg = self.segment(seg);
442                self.debug_write_u32(seg, offset, data);
443                mmu.write_u32(seg, offset, data);
444            }
445            Parameter::Ptr32Amode(seg, ref amode) => {
446                let seg = self.segment(seg);
447                let offset = self.amode(amode);
448                self.debug_write_u32(seg, offset as u16, data);
449                mmu.write_u32(seg, offset as u16, data);
450            }
451            Parameter::Ptr32AmodeS8(seg, ref amode, imm) => {
452                let seg = self.segment(seg);
453                let offset = (Wrapping(self.amode(amode) as u16) + Wrapping(imm as u16)).0;
454                self.debug_write_u32(seg, offset as u16, data);
455                mmu.write_u32(seg, offset, data);
456            }
457            Parameter::Ptr32AmodeS16(seg, ref amode, imm) => {
458                let seg = self.segment(seg);
459                let offset = (Wrapping(self.amode(amode) as u16) + Wrapping(imm as u16)).0;
460                self.debug_write_u32(seg, offset as u16, data);
461                mmu.write_u32(seg, offset, data);
462            }
463            _ => panic!("unhandled type {:?} at {:06X}", p, self.get_address()),
464        }
465    }
466
467    fn debug_write_u8(&self, seg: u16, off: u16, data: u8) {
468        if !DEBUG_PARAMS_TOUCHING_STACK {
469            return;
470        }
471        let pos = MemoryAddress::RealSegmentOffset(seg, off).value() as isize;
472        let stack = MemoryAddress::RealSegmentOffset(self.get_r16(R::SS), self.get_r16(R::SP));
473        let code = MemoryAddress::RealSegmentOffset(self.get_r16(R::CS), self.get_r16(R::IP));
474        let dist = (pos - stack.value() as isize).abs();
475        if dist < 256 {
476            // XXX points to the instruction AFTER the one to blame
477            println!("[{}] debug_write_u8 {:04X}:{:04X} = {:02X} ... stack {} (dist {})", code, seg, off, data, stack, dist);
478        }
479    }
480
481    fn debug_write_u16(&self, seg: u16, off: u16, data: u16) {
482        if !DEBUG_PARAMS_TOUCHING_STACK {
483            return;
484        }
485        let pos = MemoryAddress::RealSegmentOffset(seg, off).value() as isize;
486        let stack = MemoryAddress::RealSegmentOffset(self.get_r16(R::SS), self.get_r16(R::SP));
487        let code = MemoryAddress::RealSegmentOffset(self.get_r16(R::CS), self.get_r16(R::IP));
488        let dist = (pos - stack.value() as isize).abs();
489        if dist < 256 {
490            // XXX points to the instruction AFTER the one to blame
491            println!("[{}] debug_write_u16 {:04X}:{:04X} = {:04X} ... stack {} (dist {})", code, seg, off, data, stack, dist);
492        }
493    }
494
495    fn debug_write_u32(&self, seg: u16, off: u16, data: u32) {
496        if !DEBUG_PARAMS_TOUCHING_STACK {
497            return;
498        }
499        let pos = MemoryAddress::RealSegmentOffset(seg, off).value() as isize;
500        let stack = MemoryAddress::RealSegmentOffset(self.get_r16(R::SS), self.get_r16(R::SP));
501        let code = MemoryAddress::RealSegmentOffset(self.get_r16(R::CS), self.get_r16(R::IP));
502        let dist = (pos - stack.value() as isize).abs();
503        if dist < 256 {
504             // XXX points to the instruction AFTER the one to blame
505            println!("[{}] debug_write_u32 {:04X}:{:04X} = {:08X} ... stack {} (dist {})", code, seg, off, data, stack, dist);
506        }
507    }
508
509    /// returns the value of the given segment register
510    pub fn segment(&self, seg: Segment) -> u16 {
511        self.get_r16(seg.as_register())
512    }
513
514    pub fn amode(&self, amode: &AMode) -> usize {
515        match *amode {
516            AMode::BXSI => (Wrapping(self.get_r16(R::BX)) + Wrapping(self.get_r16(R::SI))).0 as usize,
517            AMode::BXDI => (Wrapping(self.get_r16(R::BX)) + Wrapping(self.get_r16(R::DI))).0 as usize,
518            AMode::BPSI => (Wrapping(self.get_r16(R::BP)) + Wrapping(self.get_r16(R::SI))).0 as usize,
519            AMode::BPDI => (Wrapping(self.get_r16(R::BP)) + Wrapping(self.get_r16(R::DI))).0 as usize,
520            AMode::SI => self.get_r16(R::SI) as usize,
521            AMode::DI => self.get_r16(R::DI) as usize,
522            AMode::BP => self.get_r16(R::BP) as usize,
523            AMode::BX => self.get_r16(R::BX) as usize,
524
525            AMode::EAX => self.get_r32(R::EAX) as usize,
526            AMode::ECX => self.get_r32(R::ECX) as usize,
527            AMode::EDX => self.get_r32(R::EDX) as usize,
528            AMode::EBX => self.get_r32(R::EBX) as usize,
529            AMode::ESP => self.get_r32(R::ESP) as usize,
530            AMode::EBP => self.get_r32(R::EBP) as usize,
531            AMode::ESI => self.get_r32(R::ESI) as usize,
532            AMode::EDI => self.get_r32(R::EDI) as usize,
533        }
534    }
535
536    /// used by aaa, aas
537    pub fn adjb(&mut self, param1: i8, param2: i8) {
538        if self.regs.flags.adjust || (self.get_r8(R::AL) & 0xf) > 9 {
539            let al = (i16::from(self.get_r8(R::AL)) + i16::from(param1)) as u8;
540            let ah = (i16::from(self.get_r8(R::AH)) + i16::from(param2)) as u8;
541            self.set_r8(R::AL, al);
542            self.set_r8(R::AH, ah);
543            self.regs.flags.adjust = true;
544            self.regs.flags.carry = true;
545        } else {
546            self.regs.flags.adjust = false;
547            self.regs.flags.carry = false;
548        }
549        let al = self.get_r8(R::AL);
550        self.set_r8(R::AL, al & 0x0F);
551    }
552
553    /// used by daa, das
554    pub fn adj4(&mut self, param1: i16, param2: i16) {
555        let mut al = self.get_r8(R::AL);
556        if ((al & 0x0F) > 0x09) || self.regs.flags.adjust {
557            if (al > 0x99) || self.regs.flags.carry {
558                al = (i16::from(al) + param2) as u8;
559                self.regs.flags.carry = true;
560            } else {
561                self.regs.flags.carry = false;
562            }
563            al = (i16::from(al) + param1) as u8;
564            self.regs.flags.adjust = true;
565        } else {
566            if (al > 0x99) || self.regs.flags.carry {
567                al = (i16::from(al) + param2) as u8;
568                self.regs.flags.carry = true;
569            } else {
570                self.regs.flags.carry = false;
571            }
572            self.regs.flags.adjust = false;
573        }
574        self.set_r8(R::AL, al);
575        self.regs.flags.sign = al & 0x80 != 0;
576        self.regs.flags.zero = al == 0;
577        self.regs.flags.set_parity(al as usize);
578    }
579}