yaxpeax_core/arch/pic17/
cpu.rs

1use yaxpeax_arch::Decoder;
2use arch::MCU;
3use yaxpeax_arch::LengthedInstruction;
4use yaxpeax_arch::Arch;
5use yaxpeax_arch::ShowContextual;
6use memory::MemoryRange;
7use memory::repr::FlatMemoryRepr;
8use debug;
9use debug::DebugTarget;
10use arch::pic17;
11use arch::pic17::{FullInstructionContext, PIC17, SFRS};
12use yaxpeax_pic17::{Operand, Opcode};
13use arch::pic17::deps::{updates_of, dependencies_of};
14use arch::pic17::MergedContextTable;
15
16pub struct PIC17DebugTarget<'a> {
17    pub target: &'a mut pic17::cpu::CPU,
18    break_conditions: Vec<BreakCondition>,
19    watch_targets: Vec<WatchTarget>
20}
21
22impl <'a> PIC17DebugTarget<'a> {
23    fn check_breakpoints(&self) -> bool {
24        for bp in &self.break_conditions {
25            match bp {
26                BreakCondition::IPValue(ip) => {
27                    if &self.target.ip == ip { return true; }
28                },
29                BreakCondition::Other(f) => {
30                    if f(&self.target) { return true; }
31                },
32                BreakCondition::MemoryAccess(dest) => {
33                    /*
34                     * Needs to handle INDF0 and INDF1
35                     * potentially referencing dest
36                     */
37                    let instr = self.target.decode();
38                    match instr {
39                        Ok(instr) => {
40                            match instr.operands[0] {
41                                Operand::File(f) => {
42                                    if self.target.debank(f) == *dest {
43                                        return true;
44                                    }
45                                },
46                                _ => { }
47                            };
48
49                            match instr.operands[1] {
50                                Operand::File(f) => {
51                                    if self.target.debank(f) == *dest {
52                                        return true;
53                                    }
54                                },
55                                _ => { }
56                            };
57                        },
58                        Err(_) => { }
59                    };
60                },
61                BreakCondition::IO => {
62                    if self.target.would_IO().is_some() { return true; }
63                }
64            }
65        }
66        false
67    }
68    fn show_watches(&self) {
69        for watch in &self.watch_targets {
70            println!("WATCH: {}", watch.reify(&self.target));
71        }
72    }
73}
74
75impl WatchTarget {
76    /// Builds a pointer from the target of the watch.
77    fn pointee(&self, cpu: &pic17::cpu::CPU) -> Option<u16> {
78        match self {
79            WatchTarget::Pointee(target) => {
80                target.pointee(cpu).and_then(|value| {
81                    if value > cpu.memory.len() as u16 - 2 {
82                        return None
83                    };
84
85                    Some(cpu.get_byte_noupdate(value).unwrap() as u16 |
86                        ((cpu.get_byte_noupdate(value + 1).unwrap() as u16) << 8))
87                })
88            },
89            WatchTarget::MemoryLocation(addr) => {
90                cpu.get_byte_noupdate(*addr).and_then(|low| {
91                    cpu.get_byte_noupdate(*addr + 1).map(|high| {
92                        ((high as u16) << 8) | (low as u16)
93                    })
94                }).ok()
95            },
96            WatchTarget::W => Some(cpu.W as u16)
97        }
98    }
99    fn reify(&self, cpu: &pic17::cpu::CPU) -> String {
100        match self {
101            WatchTarget::Pointee(target) => {
102                match target.pointee(cpu) {
103                    Some(pointee) => {
104                        format!("[{}]: 0x{:x}", target.reify(cpu), pointee)
105                    }
106                    None => {
107                        format!("[{}]: invalid", target.reify(cpu))
108                    }
109                }
110            }
111            WatchTarget::MemoryLocation(addr) => {
112                format!("[{}]: 0x{:x}", pic17::named_file(*addr), cpu.get_byte_noupdate(*addr).unwrap())
113            },
114            WatchTarget::W => {
115                format!("W: 0x{:x}", cpu.W)
116            }
117        }
118    }
119}
120
121impl FullInstructionContext for pic17::cpu::CPU {
122    fn memory(&self, addr: u16) -> u8 { self.memory[addr as usize] }
123    fn bsr(&self) -> u8 {
124        self.memory[SFRS::BSR as usize]
125    }
126    fn pclath(&self) -> u8 {
127        self.memory[SFRS::PCLATH as usize]
128    }
129}
130
131#[derive(Debug)]
132pub enum WatchTarget {
133    Pointee(Box<WatchTarget>),
134    MemoryLocation(u16),
135    W
136}
137pub enum BreakCondition {
138    IPValue(u16),
139    Other(fn(&pic17::cpu::CPU) -> bool),
140    MemoryAccess(u16),
141    IO
142}
143
144impl <'a> DebugTarget<'a, pic17::cpu::CPU> for PIC17DebugTarget<'a> {
145    type WatchTarget = WatchTarget;
146    type BreakCondition = BreakCondition;
147    fn attach(cpu: &'a mut pic17::cpu::CPU) -> Self {
148        PIC17DebugTarget {
149            target: cpu,
150            break_conditions: vec![],
151            watch_targets: vec![]
152        }
153    }
154    fn single_step(&mut self) -> Result<(), String> {
155        self.show_watches();
156        self.target.emulate()
157    }
158    fn run(&mut self) -> debug::RunResult {
159        println!("Running...");
160        match self.target.emulate() {
161            Ok(()) => { },
162            Err(msg) => {
163                return debug::RunResult::ExecutionError(msg);
164            }
165        }
166        loop {
167            if self.check_breakpoints() {
168                return debug::RunResult::HitBreakCondition;
169            }
170            match self.target.emulate() {
171                Ok(()) => { },
172                Err(msg) => {
173                    return debug::RunResult::ExecutionError(msg);
174                }
175            }
176        }
177    }
178    fn add_watch(&mut self, watch: WatchTarget) -> Result<(), String> {
179        self.watch_targets.push(watch);
180        Ok(())
181    }
182    fn add_break_condition(&mut self, break_cond: Self::BreakCondition) -> Result<(), String> {
183        self.break_conditions.push(break_cond);
184        Ok(())
185    }
186}
187
188enum IOCause {
189    UART,
190    PORT
191}
192
193use arch::pic17::PartialInstructionContext;
194
195pub fn try_debank<T>(f: u8, ctx: Option<&T>) -> Option<u16> where T: PartialInstructionContext {
196    if f < 0x10 {
197        Some(f as u16)
198    } else if f < 0x18 {
199        ctx.and_then(|c| c.bsr_sfr()).map(|bank| ((bank as u16) << 8) | f as u16)
200    } else {
201        ctx.and_then(|c| c.bsr_gpr()).map(|bank| ((bank as u16) << 8) | f as u16)
202    }
203}
204
205pub fn debank(f: u8, bsr: u8) -> u16 {
206    if f < 0x10 {
207        f as u16
208    } else if f < 0x18 {
209        f as u16 | ((bsr as u16 & 0x0f) << 8)
210    } else {
211        f as u16 | ((bsr as u16 & 0xf0) << 4)
212    }
213}
214
215#[allow(non_snake_case)]
216#[derive(Debug)]
217pub struct CPU {
218    pub W: u8,
219    pub ip: u16, // might be u17?
220    psr_z: bool,
221    psr_c: bool,
222    psr_v: bool,
223    psr_dc: bool,
224    stkptr: usize,
225    stack: [u16; 16],
226    tablat: [u8; 2],
227    fsr0_post: u8,
228    fsr1_post: u8,
229    pub program: Vec<u8>,
230    pub memory: Vec<u8>,
231    pub memsize: usize,
232    tsr: u8,
233    tsr_len: u8
234}
235
236impl CPU {
237    pub fn new(progsize: u32, memsize: u32) -> Self {
238        let mut cpu = CPU {
239            W: 0,
240            ip: 0,
241            psr_z: false,
242            psr_c: false,
243            psr_v: false,
244            psr_dc: false,
245            stkptr: 0,
246            stack: [0u16; 16],
247            tablat: [0u8; 2],
248            fsr0_post: 0,
249            fsr1_post: 0,
250            program: vec![0; progsize as usize],
251            memory: vec![0; 0x1000], // not `memsize` because this makes handling FSR easier
252            memsize: memsize as usize,
253            tsr: 0,
254            tsr_len: 0
255        };
256
257        cpu.memory[SFRS::TXSTA1 as usize] |= 0b00000010;
258        cpu.memory[SFRS::TXSTA2 as usize] |= 0b00000010;
259
260        cpu
261    }
262    fn push(&mut self, value: u16) -> Result<(), String> {
263        let ptr = self.stkptr;
264        if ptr >= 16 {
265            return Err("Stack overflow".to_owned());
266        }
267
268        self.stack[ptr as usize] = value;
269
270        self.stkptr += 1;
271        Ok(())
272    }
273    fn pop(&mut self) -> Result<u16, String> {
274        let mut ptr = self.stkptr;
275        if ptr == 0 {
276            return Err("Stack underflow".to_owned());
277        }
278
279        ptr -= 1;
280
281        let result = self.stack[ptr as usize];
282
283        self.stkptr = ptr;
284        Ok(result)
285    }
286    fn txen1(&self) -> bool { self.memory[SFRS::TXSTA1 as usize] & 0b00100000 != 0 }
287    fn txen2(&self) -> bool { self.memory[SFRS::TXSTA2 as usize] & 0b00100000 != 0 }
288
289    #[allow(non_snake_case)]
290    fn would_IO(&self) -> Option<IOCause> {
291        if self.tsr_len > 0 && (self.txen1() || self.txen2()) {
292            return Some(IOCause::UART);
293        }
294
295        match self.decode() {
296            Ok(instr) => {
297                fn does_io(cpu: &CPU, op: Operand) -> Option<IOCause> {
298                    match op {
299                        Operand::File(f) => {
300                            match cpu.debank(f) {
301                                SFRS::PORTA |
302                                SFRS::PORTB |
303                                SFRS::PORTC |
304                                SFRS::PORTD |
305                                SFRS::PORTE |
306                                SFRS::PORTF |
307                                SFRS::PORTG => Some(IOCause::PORT),
308                                _ => None
309                            }
310                        },
311                        _ => None
312                    }
313                }
314
315                does_io(self, instr.operands[0]).or(does_io(self, instr.operands[1]))
316            }
317            Err(_) => {
318                return None;
319            }
320        }
321    }
322    fn set_sfr_bank(&mut self, value: u8) {
323        self.memory[SFRS::BSR as usize] &= 0xf0;
324        self.memory[SFRS::BSR as usize] |= value & 0x0f;
325    }
326    fn set_gpr_bank(&mut self, value: u8) {
327        self.memory[SFRS::BSR as usize] &= 0x0f;
328        self.memory[SFRS::BSR as usize] |= value & 0xf0;
329    }
330    /*
331    fn bank(&self) -> u8 {
332        self.memory[SFRS::BSR as usize] // TODO this should be configured somehow...
333    }
334    */
335    fn get_fsr(&self, fsr: u8) -> u16 {
336        // TODO
337        match fsr {
338            0 => {
339                self.memory[SFRS::FSR0 as usize] as u16
340            },
341            1 => {
342                self.memory[SFRS::FSR1 as usize] as u16
343            },
344            _ => { unreachable!(); }
345        }
346    }
347    pub fn debank(&self, f: u8) -> u16 {
348        pic17::cpu::debank(f, self.memory[SFRS::BSR as usize])
349    }
350    pub fn get_byte(&mut self, addr: u16) -> Result<u8, String> {
351        self.get_byte_noupdate(addr)
352    }
353    pub fn get_byte_noupdate(&self, addr: u16) -> Result<u8, String> {
354        let value = match addr {
355            SFRS::PCL => { self.ip as u8 },
356            SFRS::WREG => { self.W },
357            SFRS::ALUSTA => {
358                (self.fsr1_post << 6) |
359                    (self.fsr0_post << 4) |
360                    (if self.psr_v { 1 } else { 0 } << 3) |
361                    (if self.psr_z { 1 } else { 0 } << 2) |
362                    (if self.psr_dc { 1 } else { 0 } << 1) |
363                    (if self.psr_c { 1 } else { 0 } << 0)
364            },
365            SFRS::INDF0 => {
366                let real_addr = self.get_fsr(0);
367                self.memory[real_addr as usize]
368            },
369            SFRS::INDF1 => {
370                let real_addr = self.get_fsr(1);
371                self.memory[real_addr as usize]
372            }
373            _ => {
374                // pic17 is whack. i don't think the first 0x20 bytes
375                // for pages are counted in "data size". so just add
376                // those to the limit..
377                let real_limit = self.memsize + 0x20 +
378                    (self.memsize / 0x100) * 0x20;
379                if addr as usize > real_limit && addr as u8 >= 0x20 {
380                    return Err(format!("Invalid dest address: {:x}", addr));
381                }
382                self.memory[addr as usize]
383            }
384        };
385
386        Ok(value)
387    }
388    pub fn set_byte_noupdate(&mut self, addr: u16, what: u8) -> Result<(), String> {
389        match addr {
390            SFRS::PCL => { /* actually a nop */ },
391            SFRS::WREG => { self.W = what; },
392            SFRS::ALUSTA => {
393                self.memory[SFRS::ALUSTA as usize] = what;
394                self.fsr1_post = (what & 0xc0) >> 6;
395                self.fsr0_post = (what & 0x30) >> 6;
396                self.psr_v = (what & 0x08) == 0x08;
397                self.psr_z = (what & 0x04) == 0x04;
398                self.psr_dc = (what & 0x02) == 0x02;
399                self.psr_c = (what & 0x01) == 0x01;
400            },
401            SFRS::CPUSTA => {
402                let value = (self.memory[SFRS::CPUSTA as usize] & 0b11101100) |
403                    (what & 0b00010011);
404                self.memory[SFRS::CPUSTA as usize] = value;
405            },
406            SFRS::INDF0 => {
407                // TODO: debank real_addr
408                let real_addr = self.get_fsr(0);
409                self.memory[real_addr as usize] = what;
410            },
411            SFRS::INDF1 => {
412                let real_addr = self.get_fsr(1);
413                self.memory[real_addr as usize] = what;
414            },
415            SFRS::TXSTA1 => {
416                let masked = what & 0b11110001;
417                self.memory[SFRS::TXSTA1 as usize] = masked;
418            },
419            SFRS::TXSTA2 => {
420                let masked = what & 0b11110001;
421                self.memory[SFRS::TXSTA2 as usize] = masked;
422            },
423            _ => {
424                // pic17 is whack. i don't think the first 0x20 bytes
425                // for pages are counted in "data size". so just add
426                // those to the limit..
427                let real_limit = self.memsize + 0x20 +
428                    (self.memsize / 0x100) * 0x20;
429                if addr as usize > real_limit && addr as u8 >= 0x20 {
430                    return Err(format!("Invalid dest address: {:x}", addr));
431                }
432
433                self.memory[addr as usize] = what;
434            }
435        };
436        Ok(())
437    }
438    pub fn set_byte(&mut self, addr: u16, what: u8) -> Result<(), String> {
439        self.set_byte_noupdate(addr, what)
440    }
441    pub fn tblptr(&self) -> u16 {
442        ((self.memory[SFRS::TBLPTRL as usize] as u16)) |
443        ((self.memory[SFRS::TBLPTRH as usize] as u16) << 8)
444    }
445    pub fn set_tblptr(&mut self, tblptr: u16) {
446        self.memory[SFRS::TBLPTRL as usize] = tblptr as u8;
447        self.memory[SFRS::TBLPTRH as usize] = (tblptr >> 8) as u8;
448    }
449    pub fn describe(&self) {
450        println!("pic17: C: {}, Z: {}, DC: {}, V: {}", self.psr_c, self.psr_z, self.psr_dc, self.psr_v);
451        println!("ip=0x{:x}, W=0x{:x}, stkptr=0x{:x}", self.ip, self.W, self.stkptr);
452        match self.decode() {
453            Ok(instr) => {
454                let _ctx: Option<&pic17::cpu::CPU> = Some(self);
455                let mut s = String::new();
456                let ctx: Option<&MergedContextTable> = None;
457                instr.contextualize(&yaxpeax_arch::NoColors, self.ip, /* TODO: ctx */ ctx, &mut s).unwrap();
458                println!("instruction: {}", s);
459            },
460            Err(e) => println!("[invalid: {}]", e)
461        };
462        println!("stack:");
463        for i in 0..self.stkptr {
464            println!("  0x{:x}", self.stack[i as usize]);
465        }
466        println!("------");
467        println!("tblptr: 0x{:x}", self.tblptr());
468        println!("");
469    }
470    pub fn program<T: MemoryRange<PIC17>>(&mut self, program: Option<T>, config: Option<FlatMemoryRepr>) -> Result<(), String> {
471        match program.and_then(|x| x.as_flat()) {
472            Some(flat) => {
473                let data = flat.data();
474                if data.len() > self.program.len() {
475                    return Err(
476                        format!(
477                            "Data is larger than the chip: 0x{:x} bytes of memory but 0x{:x} available",
478                            data.len(),
479                            self.program.len()
480                        )
481                    );
482                }
483                println!("DEBUG: writing 0x{:x} bytes of program...", data.len());
484                self.program[0..data.len()].copy_from_slice(data);
485            },
486            None => {
487                println!("WARN: Provided program includes no code.");
488            }
489        };
490
491        // TODO: where do config bits show up in pic17?
492        match config {
493            Some(_config) => {
494                println!("WARN: ignoring config");
495            },
496            None => {
497            }
498        };
499
500        Ok(())
501    }
502}
503
504use data::AliasInfo;
505// TODO: this is wrong lol
506impl AliasInfo for Dependence {
507    fn aliases_of(&self) -> Vec<Self> { vec![] }
508    fn maximal_alias_of(&self) -> Self { self.clone() }
509}
510
511use data::types::{Typed, TypeAtlas, TypeSpec};
512impl Typed for Data {
513    fn type_of(&self, _: &TypeAtlas) -> TypeSpec {
514        TypeSpec::Unknown
515    }
516}
517
518#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
519pub enum Data {
520    Constant(u8)
521}
522
523use analyses::static_single_assignment::{SSAValues};
524use arch::pic17::{Dependence, Update};
525impl SSAValues for PIC17 {
526    type Data = Data; // TODO: either some id of something interesting or a value?
527}
528
529use crate::ColorSettings;
530impl<'data, 'colors> crate::analyses::static_single_assignment::DataDisplay<'data, 'colors> for Data {
531    type Displayer = &'static str;
532    fn display(&'data self, _detailed: bool, _colors: Option<&'colors ColorSettings>) -> &'static str {
533        unimplemented!()
534    }
535}
536
537use data::Direction;
538use data::ValueLocations;
539impl ValueLocations for PIC17 {
540    type Location = Dependence;
541
542    fn decompose(instr: &Self::Instruction) -> Vec<(Option<Self::Location>, Direction)> {
543        use arch::pic17::MergedContext;
544        let ctx = MergedContext {
545            computed: None,
546            user: None
547        };
548        let mut result: Vec<(Option<Self::Location>, Direction)> = Vec::new();
549        for update in updates_of(instr, &ctx).into_iter() {
550            let as_dep = match update {
551                Update::W => Some(Dependence::W),
552                Update::Memory(_) => None,
553                Update::Program(_) => None,
554//                Update::Stack(_) => None,
555                Update::Carry => Some(Dependence::Carry),
556                Update::BSR_SFR => Some(Dependence::BSR_SFR),
557                Update::BSR_GPR => Some(Dependence::BSR_GPR),
558                Update::Unknown => None
559            };
560            result.push((as_dep, Direction::Write));
561        }
562        for dependence in dependencies_of(instr, &ctx).into_iter() {
563            let as_dep = match dependence {
564                Dependence::W => Some(Dependence::W),
565                Dependence::Memory(_) => None,
566                Dependence::Program(_) => None,
567                Dependence::Stack(_) => None,
568                Dependence::Carry => Some(Dependence::Carry),
569                Dependence::BSR_SFR => Some(Dependence::BSR_SFR),
570                Dependence::BSR_GPR => Some(Dependence::BSR_GPR),
571                Dependence::Unknown => None
572            };
573            result.push((as_dep, Direction::Read));
574        }
575        result
576    }
577}
578
579
580impl MCU for CPU {
581    type Addr = u16;
582    type Instruction = <PIC17 as Arch>::Instruction;
583    fn emulate(&mut self) -> Result<(), String> {
584        fn store_operand(cpu: &mut CPU, new_value: u8, dest: Operand) {
585            match dest {
586                Operand::File(f) => {
587                    let dest_file = cpu.debank(f);
588                    cpu.set_byte_noupdate(dest_file, new_value).unwrap();
589                },
590                Operand::W => {
591                    cpu.W = new_value;
592                }
593                _ => {
594                    unreachable!();
595                }
596            }
597        }
598        let mut skip_next = false;
599        let eval_result = match self.decode() {
600            Ok(instr) => {
601                match instr.opcode {
602                    Opcode::TLRDL => {
603                        let dest_file = self.debank(instr.operands[0].file_value());
604                        let value = self.tablat[0];
605                        self.set_byte(dest_file, value).unwrap();
606                    },
607                    Opcode::TLRDH => {
608                        let dest_file = self.debank(instr.operands[0].file_value());
609                        let value = self.tablat[1];
610                        self.set_byte(dest_file, value).unwrap();
611                    },
612                    Opcode::TLWTL => {
613                        let source_file = self.debank(instr.operands[0].file_value());
614                        self.tablat[0] = self.get_byte(source_file).unwrap();
615                    },
616                    Opcode::TLWTH => {
617                        let source_file = self.debank(instr.operands[0].file_value());
618                        self.tablat[1] = self.get_byte(source_file).unwrap();
619                    },
620                    Opcode::TABLRDL => {
621                        self.tablat[0] = self.program[(self.tblptr() * 2) as usize];
622                        self.tablat[1] = self.program[(self.tblptr() * 2 + 1) as usize];
623                        let dest_file = self.debank(instr.operands[0].file_value());
624                        let value = self.tablat[0];
625                        self.set_byte(dest_file, value).unwrap();
626                    },
627                    Opcode::TABLRDLI => {
628                        let tblptr = self.tblptr();
629                        self.tablat[0] = self.program[(self.tblptr() * 2) as usize];
630                        self.tablat[1] = self.program[(self.tblptr() * 2 + 1) as usize];
631                        self.set_tblptr(tblptr + 1);
632                        let dest_file = self.debank(instr.operands[0].file_value());
633                        let value = self.tablat[0];
634                        self.set_byte(dest_file, value).unwrap();
635                    },
636                    Opcode::TABLRDH => {
637                        self.tablat[0] = self.program[(self.tblptr() * 2) as usize];
638                        self.tablat[1] = self.program[(self.tblptr() * 2 + 1) as usize];
639                        let dest_file = self.debank(instr.operands[0].file_value());
640                        let value = self.tablat[1];
641                        self.set_byte(dest_file, value).unwrap();
642                    },
643                    Opcode::TABLRDHI => {
644                        let tblptr = self.tblptr();
645                        self.tablat[0] = self.program[(self.tblptr() * 2) as usize];
646                        self.tablat[1] = self.program[(self.tblptr() * 2 + 1) as usize];
647                        self.set_tblptr(tblptr + 1);
648                        let dest_file = self.debank(instr.operands[0].file_value());
649                        let value = self.tablat[1];
650                        self.set_byte(dest_file, value).unwrap();
651                    },
652                    Opcode::TABLWTL => {
653                        let source_file = self.debank(instr.operands[0].file_value());
654                        self.tablat[0] = self.get_byte(source_file).unwrap();
655                        let tblptr = self.tblptr();
656                        self.program[(tblptr * 2) as usize] = self.tablat[0];
657                        self.program[(tblptr * 2 + 1) as usize] = self.tablat[1];
658                    },
659                    Opcode::TABLWTLI => {
660                        let source_file = self.debank(instr.operands[0].file_value());
661                        self.tablat[0] = self.get_byte(source_file).unwrap();
662                        let mut tblptr = self.tblptr();
663                        self.program[(tblptr * 2) as usize] = self.tablat[0];
664                        self.program[(tblptr * 2 + 1) as usize] = self.tablat[1];
665                        tblptr += 1;
666                        self.set_tblptr(tblptr);
667                    },
668                    Opcode::TABLWTH => {
669                        let source_file = self.debank(instr.operands[0].file_value());
670                        self.tablat[1] = self.get_byte(source_file).unwrap();
671                        let tblptr = self.tblptr();
672                        self.program[(tblptr * 2) as usize] = self.tablat[0];
673                        self.program[(tblptr * 2 + 1) as usize] = self.tablat[1];
674                    },
675                    Opcode::TABLWTHI => {
676                        let source_file = self.debank(instr.operands[0].file_value());
677                        self.tablat[1] = self.get_byte(source_file).unwrap();
678                        let mut tblptr = self.tblptr();
679                        self.program[(tblptr * 2) as usize] = self.tablat[0];
680                        self.program[(tblptr * 2 + 1) as usize] = self.tablat[1];
681                        tblptr += 1;
682                        self.set_tblptr(tblptr);
683                    },
684                    Opcode::SUBLW => {
685                        self.W = self.W.wrapping_sub(
686                            instr.operands[0].imm8_value()
687                        );
688                    }
689                    Opcode::IORLW => {
690                        self.W |= instr.operands[0].imm8_value();
691                    }
692                    Opcode::XORLW => {
693                        self.W ^= instr.operands[0].imm8_value();
694                    }
695                    Opcode::ANDLW => {
696                        self.W &= instr.operands[0].imm8_value();
697                    }
698                    Opcode::RETLW => {
699                        self.W = instr.operands[0].imm8_value();
700                        self.ip = self.pop().unwrap();
701                        return Ok(());
702                    }
703                    Opcode::MULWF => {
704                        let f = self.debank(instr.operands[0].file_value());
705
706                        let result = (self.get_byte(f).unwrap() as u16) * (self.W as u16);
707                        self.memory[SFRS::PRODH as usize] = (result >> 8) as u8;
708                        self.memory[SFRS::PRODL as usize] = result as u8;
709                    }
710                    Opcode::MULLW => {
711                        let literal = instr.operands[0].imm8_value();
712
713                        let result = (literal as u16) * (self.W as u16);
714                        self.memory[SFRS::PRODH as usize] = (result >> 8) as u8;
715                        self.memory[SFRS::PRODL as usize] = result as u8;
716                    }
717                    Opcode::MOVLW => {
718                        self.W = instr.operands[0].imm8_value();
719                    },
720                    Opcode::ADDLW => {
721                        self.W = self.W.wrapping_add(
722                            instr.operands[0].imm8_value()
723                        );
724                    }
725                    Opcode::MOVLB => {
726                        self.set_sfr_bank(
727                            instr.operands[0].imm8_value()
728                        );
729                    },
730                    Opcode::MOVLR => {
731                        self.set_gpr_bank(
732                            instr.operands[0].imm8_value()
733                        );
734                    },
735                    Opcode::GOTO => {
736                        // TODO: hmmmmmmmm..... u16?
737                        self.ip = instr.operands[0].imm32_value() as u16;
738                        return Ok(());
739                    },
740                    Opcode::CALL => {
741                        let return_address = self.ip + instr.len();
742                        self.push(return_address).unwrap();
743                        self.ip = instr.operands[0].imm32_value() as u16;
744                        return Ok(());
745                    },
746                    Opcode::RETURN => {
747                        self.ip = self.pop().unwrap();
748                        return Ok(());
749                    },
750                    Opcode::RRNCF => {
751                        let source_file = self.debank(instr.operands[0].file_value());
752
753                        let new_value = self.get_byte(source_file).unwrap()
754                            .rotate_right(1);
755
756                        store_operand(self, new_value, instr.operands[1]);
757                    },
758                    Opcode::RRCF => {
759                        let source_file = self.debank(instr.operands[0].file_value());
760
761                        let mut new_value = self.get_byte(source_file).unwrap();
762                        let new_carry = (new_value >> 7) & 0x01 == 0x01;
763                        new_value >>= 1;
764                        if self.psr_c {
765                            new_value |= 0x80;
766                        }
767
768                        self.psr_c = new_carry;
769                        store_operand(self, new_value, instr.operands[1]);
770                    },
771                    Opcode::RLNCF => {
772                        let source_file = self.debank(instr.operands[0].file_value());
773
774                        let new_value = self.get_byte(source_file).unwrap()
775                            .rotate_left(1);
776                        store_operand(self, new_value, instr.operands[1]);
777                    },
778                    Opcode::RLCF => {
779                        let source_file = self.debank(instr.operands[0].file_value());
780
781                        let mut new_value = self.get_byte(source_file).unwrap();
782                        let new_carry = new_value & 0x01 == 0x01;
783                        new_value <<= 1;
784                        if self.psr_c {
785                            new_value |= 0x01;
786                        }
787
788                        self.psr_c = new_carry;
789                        store_operand(self, new_value, instr.operands[1]);
790                    },
791                    Opcode::NOP => {
792
793                    },
794                    Opcode::DCFSNZ => {
795                        let source_file = self.debank(instr.operands[0].file_value());
796
797                        let value = self.get_byte(source_file).unwrap().wrapping_sub(1);
798                        skip_next = value != 0;
799                        store_operand(self, value, instr.operands[1]);
800                    },
801                    Opcode::INCF => {
802                        let source_file = self.debank(instr.operands[0].file_value());
803
804                        let value = self.get_byte(source_file).unwrap().wrapping_add(1);
805                        // what about C, OV, DC?
806                        self.psr_z = value == 0;
807                        self.psr_c = value == 0x00; // just rolled over.
808                        store_operand(self, value, instr.operands[1]);
809                    },
810                    Opcode::DECF => {
811                        let source_file = self.debank(instr.operands[0].file_value());
812
813                        let (value, carry) = self.get_byte(source_file).unwrap().overflowing_add(0xff);
814                        self.psr_z = value == 0;
815                        self.psr_c = carry;
816
817                        store_operand(self, value, instr.operands[1]);
818                    },
819                    Opcode::DECFSZ => {
820                        let source_file = self.debank(instr.operands[0].file_value());
821
822                        let value = self.get_byte(source_file).unwrap().wrapping_sub(1);
823                        skip_next = value == 0;
824
825                        store_operand(self, value, instr.operands[1]);
826                    },
827                    Opcode::INFSNZ => {
828                        let source_file = self.debank(instr.operands[0].file_value());
829
830                        let value = self.get_byte(source_file).unwrap().wrapping_add(1);
831                        skip_next = value != 0;
832
833                        store_operand(self, value, instr.operands[1]);
834                    },
835                    Opcode::INCFSZ => {
836                        let source_file = self.debank(instr.operands[0].file_value());
837
838                        let value = self.get_byte(source_file).unwrap().wrapping_add(1);
839                        skip_next = value == 0;
840
841                        store_operand(self, value, instr.operands[1]);
842                    },
843                    Opcode::TSTFSZ => {
844                        let source_file = self.debank(instr.operands[0].file_value());
845
846                        // TODO: verify
847                        let value = self.get_byte(source_file).unwrap();
848                        skip_next = value == 0;
849                    },
850                    Opcode::MOVWF => {
851                        let source_file = self.debank(instr.operands[0].file_value());
852
853                        let value = self.W.clone();
854                        self.set_byte(source_file, value).unwrap();
855                    },
856                    Opcode::MOVFP => {
857                        let source_file = self.debank(instr.operands[0].file_value());
858                        let dest_file = self.debank(instr.operands[1].file_value());
859
860                        // TODO: verify?
861                        let value = self.get_byte(source_file).unwrap();
862                        self.set_byte(dest_file, value).unwrap();
863                    },
864                    Opcode::MOVPF => {
865                        let source_file = self.debank(instr.operands[0].file_value());
866                        let dest_file = self.debank(instr.operands[1].file_value());
867
868                        // TODO: verify?
869                        let value = self.get_byte(source_file).unwrap();
870                        self.set_byte(dest_file, value).unwrap();
871                    },
872                    Opcode::SWAPF => {
873                        let source_file = self.debank(instr.operands[0].file_value());
874
875                        // TODO: verify?
876                        let value = self.get_byte(source_file).unwrap();
877                        let new_value = (value & 0xf0 >> 4) | (value & 0x0f << 4);
878                        self.set_byte(source_file, new_value).unwrap();
879                    }
880                    Opcode::CLRF => {
881                        let source_file = self.debank(instr.operands[0].file_value());
882
883                        self.set_byte(source_file, 0).unwrap();
884
885                        match instr.operands[1] {
886                            Operand::W => {
887                                self.W = 0;
888                            },
889                            _ => { }
890                        }
891                    },
892                    Opcode::BSF => {
893                        let source_file = self.debank(instr.operands[0].file_value());
894                        let bit = self.debank(instr.operands[1].imm8_value());
895
896                        let mut value = self.get_byte(source_file).unwrap();
897                        value |= 1 << bit;
898                        self.set_byte_noupdate(source_file, value).unwrap();
899                    }
900                    Opcode::BCF => {
901                        let source_file = self.debank(instr.operands[0].file_value());
902                        let bit = self.debank(instr.operands[1].imm8_value());
903
904                        let mut value = self.get_byte(source_file).unwrap();
905                        value &= !(1 << bit);
906                        self.set_byte_noupdate(source_file, value).unwrap();
907                    }
908                    Opcode::BTG => {
909                        let source_file = self.debank(instr.operands[0].file_value());
910                        let bit = self.debank(instr.operands[1].imm8_value());
911
912                        let mut value = self.get_byte(source_file).unwrap();
913                        value ^= 1 << bit;
914                        self.set_byte_noupdate(source_file, value).unwrap();
915                    }
916                    Opcode::BTFSS => {
917                        let source_file = self.debank(instr.operands[0].file_value());
918                        let bit = self.debank(instr.operands[1].imm8_value());
919
920                        let value = self.get_byte(source_file).unwrap();
921                        let read = value & (1 << bit);
922
923                        if read != 0 {
924                            skip_next = true;
925                        }
926                    },
927                    Opcode::BTFSC => {
928                        let source_file = self.debank(instr.operands[0].file_value());
929                        let bit = self.debank(instr.operands[1].imm8_value());
930
931                        let value = self.get_byte(source_file).unwrap();
932                        let read = value & (1 << bit);
933
934                        if read == 0 {
935                            skip_next = true;
936                        }
937                    },
938                    Opcode::ANDWF => {
939                        let source_file = self.debank(instr.operands[0].file_value());
940
941                        let value = self.get_byte(source_file).unwrap() & self.W;
942
943                        self.psr_z = value == 0;
944
945                        store_operand(self, value, instr.operands[1]);
946                    },
947                    Opcode::XORWF => {
948                        let source_file = self.debank(instr.operands[0].file_value());
949
950                        let value = self.get_byte(source_file).unwrap() ^ self.W;
951
952                        self.psr_z = value == 0;
953
954                        store_operand(self, value, instr.operands[1]);
955                    },
956                    Opcode::IORWF => {
957                        let source_file = self.debank(instr.operands[0].file_value());
958
959                        let value = self.get_byte(source_file).unwrap() | self.W;
960
961                        self.psr_z = value == 0;
962
963                        store_operand(self, value, instr.operands[1]);
964                    },
965                    Opcode::ADDWF => {
966                        let source_file = self.debank(instr.operands[0].file_value());
967
968                        let (value, carry) = self.get_byte(source_file).unwrap().overflowing_add(self.W);
969                        self.psr_c = carry;
970                        self.psr_z = value == 0;
971
972                        store_operand(self, value, instr.operands[1]);
973                    },
974                    Opcode::ADDWFC => {
975                        let source_file = self.debank(instr.operands[0].file_value());
976
977                        let (intermediate, carry1) = self.W.overflowing_add(self.get_byte(source_file).unwrap());
978                        let (value, carry2) = intermediate.overflowing_add(if self.psr_c { 1 } else { 0 });
979                        let carry = carry1 | carry2;
980
981                        self.psr_c = carry;
982                        self.psr_z = value == 0;
983
984                        store_operand(self, value, instr.operands[1]);
985                    }
986                    Opcode::SUBWF => {
987                        let source_file = self.debank(instr.operands[0].file_value());
988
989                        let (intermediate, carry1) = self.get_byte(source_file).unwrap().overflowing_add(!self.W);
990                        let (value, carry2) = intermediate.overflowing_add(1);
991                        let carry = carry1 | carry2;
992
993                        self.psr_c = carry;
994                        self.psr_z = value == 0;
995
996                        store_operand(self, value, instr.operands[1]);
997                    },
998                    Opcode::SUBWFB => {
999                        let source_file = self.debank(instr.operands[0].file_value());
1000
1001                        let (intermediate, carry1) = self.get_byte(source_file).unwrap().overflowing_add(!self.W);
1002                        let (value, carry2) = intermediate.overflowing_add(if self.psr_c { 1 } else { 0 });
1003                        let carry = carry1 | carry2;
1004
1005                        self.psr_c = carry;
1006                        self.psr_z = value == 0;
1007
1008                        store_operand(self, value, instr.operands[1]);
1009                    },
1010                    Opcode::CPFSGT => {
1011                        let source_file = self.debank(instr.operands[0].file_value());
1012
1013                        if source_file != SFRS::WREG {
1014                            let value = self.get_byte(source_file).unwrap().wrapping_add(1);
1015                            skip_next = value > self.W;
1016                        }
1017                    },
1018                    Opcode::CPFSEQ => {
1019                        let source_file = self.debank(instr.operands[0].file_value());
1020
1021                        if source_file != SFRS::WREG {
1022                            let value = self.get_byte(source_file).unwrap().wrapping_add(1);
1023                            skip_next = value == self.W;
1024                        }
1025                    },
1026                    Opcode::CPFSLT => {
1027                        let source_file = self.debank(instr.operands[0].file_value());
1028
1029                        if source_file != SFRS::WREG {
1030                            let value = self.get_byte(source_file).unwrap().wrapping_add(1);
1031                            skip_next = value < self.W;
1032                        }
1033                    },
1034                    _ => {
1035                        return Err(format!("unhandled opcode: {:?}", instr.opcode));
1036                    }
1037                };
1038                self.ip += instr.len();
1039                Ok(())
1040            },
1041            Err(msg) => { std::panic::panic_any(msg); }
1042        };
1043        if skip_next {
1044            match self.decode() {
1045                Ok(next_instr) => {
1046                    self.ip += next_instr.len();
1047                    Ok(())
1048                },
1049                Err(msg) => { std::panic::panic_any(msg); }
1050            }
1051        } else {
1052            eval_result
1053        }
1054    }
1055
1056    fn decode(&self) -> Result<Self::Instruction, String> {
1057        let cursor: crate::memory::repr::cursor::ReadCursor<PIC17, Vec<u8>> = self.memory.range_from(self.ip).unwrap();
1058        <PIC17 as Arch>::Decoder::default().decode(&mut cursor.to_reader())
1059            .map_err(|err| {
1060                format!(
1061                    "Unable to decode bytes at 0x{:x}: {:x?}, {}",
1062                    self.ip,
1063                    self.program[(self.ip as usize)..((self.ip + 4) as usize)].iter().collect::<Vec<&u8>>(),
1064                    err
1065                )
1066            })
1067    }
1068}