1use super::environment::Environment;
2use super::registers::Reg16;
3
4type OpcodeFn = dyn Fn(&mut Environment) + Send + Sync;
5
6pub struct Opcode {
7 pub name: String,
8 pub cycles: u8,
9 pub cycles_conditional: u8,
10 pub action: Box<OpcodeFn>,
11}
12
13impl Opcode {
14 pub(crate) fn new<T>(name: String, action: T) -> Opcode
15 where T: Fn(&mut Environment) + Send + Sync + 'static {
16 Opcode {
17 name,
18 cycles: 0,
19 cycles_conditional: 0,
20 action: Box::new(action),
21 }
22 }
23
24 pub fn execute(&self, env: &mut Environment) {
25 (self.action)(env);
26 }
27
28 pub fn disasm(&self, env: &Environment) -> String {
29 let name = if self.name.contains("__index") {
30 self.name.replace("__index", &env.index_description())
31 } else {
32 self.name.clone()
33 };
34
35 if self.name.contains("nn") {
36 let nn = env.peek16_pc();
38 let nn_str = format!("{nn:04x}h");
39 name.replace("nn", &nn_str)
40 } else if self.name.contains('n') {
41 let n = env.peek_pc();
43 let n_str = format!("{n:02x}h");
44 name.replace('n', &n_str)
45 } else if self.name.contains('d') {
46 let d = env.peek_pc() as i8 as i16 + 2;
49 let d_str = format!("{d:+x}");
50 name.replace('d', &d_str)
51 } else {
52 name
53 }
54 }
55}
56
57pub fn build_not_an_opcode() -> Opcode {
58 Opcode::new(
59 "NOT_AN_OPCODE".to_string(),
60 |_: &mut Environment| {
61 panic!("Not an opcode")
62 }
63 )
64}
65
66pub fn build_nop() -> Opcode {
67 Opcode::new(
68 "NOP".to_string(),
69 |_: &mut Environment| {
70 }
72 )
73}
74
75pub fn build_noni_nop() -> Opcode {
76 Opcode::new(
77 "NONINOP".to_string(),
78 |_: &mut Environment| {
79 }
81 )
82}
83
84pub fn build_halt() -> Opcode {
85 Opcode::new(
86 "HALT".to_string(),
87 |env: &mut Environment| {
88 env.state.halted = true;
89 }
90 )
91}
92
93pub fn build_pop_rr(rr: Reg16) -> Opcode {
94 Opcode::new(
95 format!("POP {rr:?}"),
96 move |env: &mut Environment| {
97 let value = env.pop();
98 env.set_reg16(rr, value);
99 }
100 )
101}
102
103pub fn build_push_rr(rr: Reg16) -> Opcode {
104 Opcode::new(
105 format!("PUSH {rr:?}"),
106 move |env: &mut Environment| {
107 let value = env.reg16_ext(rr);
108 env.push(value);
109 }
110 )
111}
112
113pub fn build_disable_interrupts() -> Opcode {
114 Opcode::new(
115 "DI".to_string(),
116 |env: &mut Environment| {
117 env.state.reg.set_interrupts(false);
118 }
119 )
120}
121
122pub fn build_enable_interrupts() -> Opcode {
123 Opcode::new(
124 "EI".to_string(),
125 |env: &mut Environment| {
126 env.state.reg.set_interrupts(true);
127 env.state.int_just_enabled = true;
128 }
129 )
130}
131
132pub fn build_im(im: u8) -> Opcode {
133 Opcode::new(
134 format!("IM {im}"),
135 move |env: &mut Environment| {
136 env.state.reg.set_interrupt_mode(im);
137 }
138 )
139}