1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
use super::*;
impl<'a> Emitter<'a> {
/// Calculate effective address from 6-bit EA mode field.
/// Returns (address_value, is_immediate).
/// Updates Rn registers as a side effect (for post-increment etc.)
pub(super) fn emit_calc_ea(&mut self, ea_mode: u32) -> (Value, bool) {
self.emit_calc_ea_ext(ea_mode, 0)
}
pub(super) fn emit_calc_ea_ext(&mut self, ea_mode: u32, next_word: u32) -> (Value, bool) {
let mode = (ea_mode >> 3) & 0x7;
let numreg = (ea_mode & 0x7) as usize;
match mode {
0 => {
// (Rn)-Nn : return Rn, then update Rn with -Nn modifier
let rn = self.load_reg(reg::R0 + numreg);
let nn = self.load_nn_signed(numreg);
let neg_nn = self.builder.ins().ineg(nn);
self.emit_update_rn(numreg, neg_nn);
(rn, false)
}
1 => {
// (Rn)+Nn : return Rn, then update Rn with +Nn modifier
let rn = self.load_reg(reg::R0 + numreg);
let nn = self.load_nn_signed(numreg);
self.emit_update_rn(numreg, nn);
(rn, false)
}
2 => {
// (Rn)- : return Rn, then update Rn with -1 modifier
let rn = self.load_reg(reg::R0 + numreg);
let neg_one = self.builder.ins().iconst(types::I32, -1i32 as i64);
self.emit_update_rn(numreg, neg_one);
(rn, false)
}
3 => {
// (Rn)+ : return Rn, then update Rn with +1 modifier
let rn = self.load_reg(reg::R0 + numreg);
let one = self.builder.ins().iconst(types::I32, 1);
self.emit_update_rn(numreg, one);
(rn, false)
}
4 => {
// (Rn) : return Rn, no update
let rn = self.load_reg(reg::R0 + numreg);
(rn, false)
}
5 => {
// (Rn+Nn) : Compute effective address using update_rn logic,
// but restore Rn afterwards (transient address, no side-effect).
self.pending_cycles += 1;
let rn = self.load_reg(reg::R0 + numreg);
let nn = self.load_nn_signed(numreg);
// Update Rn to compute the modulo-aware address
self.emit_update_rn(numreg, nn);
let addr = self.load_reg(reg::R0 + numreg);
// Restore original Rn
self.store_reg(reg::R0 + numreg, rn);
(addr, false)
}
6 => {
// Absolute (RRR=0) or immediate (RRR=4): value from next program word
self.pending_cycles += 1;
let val = self.builder.ins().iconst(types::I32, next_word as i64);
(val, numreg != 0) // RRR!=0 means immediate value
}
7 => {
// -(Rn) : update Rn with -1 modifier, then return Rn
self.pending_cycles += 1;
let neg_one = self.builder.ins().iconst(types::I32, -1i32 as i64);
self.emit_update_rn(numreg, neg_one);
let new_rn = self.load_reg(reg::R0 + numreg);
(new_rn, false)
}
_ => unreachable!(),
}
}
/// Load N register and sign-extend from 24-bit to i32.
///
/// N registers are 24-bit unsigned values stored in u32. When used as
/// address modifiers for modulo addressing, they must be sign-extended
/// so negative offsets (e.g., $FFFFDF = -33) are treated correctly.
/// Without sign extension, $FFFFDF is interpreted as +16,777,183,
/// causing modulo wrapping to produce wildly wrong addresses.
fn load_nn_signed(&mut self, numreg: usize) -> Value {
let nn = self.load_reg(reg::N0 + numreg);
let c8 = self.builder.ins().iconst(types::I32, 8);
let shifted = self.builder.ins().ishl(nn, c8);
self.builder.ins().sshr(shifted, c8)
}
/// Emit address register update with modulo/bit-reverse support.
///
/// Fast path (M[numreg] == $FFFFFF): inline linear `Rn += modifier`.
/// Slow path: call `jit_update_rn` helper for modulo/bit-reverse.
pub(super) fn emit_update_rn(&mut self, numreg: usize, modifier: Value) {
let mn = self.load_reg(reg::M0 + numreg);
let linear_mode = self
.builder
.ins()
.iconst(types::I32, REG_MASKS[reg::M0] as i64);
let is_linear = self.builder.ins().icmp(IntCC::Equal, mn, linear_mode);
let linear_blk = self.builder.create_block();
let nonlinear_blk = self.builder.create_block();
let merge_blk = self.builder.create_block();
// Flush R/M/N[numreg] to memory before the branch so the nonlinear
// C helper sees current values.
let r_idx = reg::R0 + numreg;
self.flush_reg(r_idx);
self.flush_reg(reg::M0 + numreg);
self.flush_reg(reg::N0 + numreg);
// Clear Rn's dirty flag after flushing so the linear arm's store_reg
// is detected as "newly dirty" by end_conditional_arm. Without this,
// Rn stays dirty from before the branch, neither arm marks it as
// modified, merge_conditional never invalidates it, and subsequent
// code keeps using the stale promoted value -- overwriting whatever
// jit_update_rn wrote in the nonlinear path.
self.promoted.dirty[r_idx] = false;
let mut cond_state = self.begin_conditional();
self.builder
.ins()
.brif(is_linear, linear_blk, &[], nonlinear_blk, &[]);
// Fast path: linear addressing
self.builder.switch_to_block(linear_blk);
self.builder.seal_block(linear_blk);
let rn = self.load_reg(reg::R0 + numreg);
let new_rn = self.builder.ins().iadd(rn, modifier);
let r_mask = self
.builder
.ins()
.iconst(types::I32, REG_MASKS[reg::R0] as i64);
let new_rn = self.builder.ins().band(new_rn, r_mask);
self.store_reg(reg::R0 + numreg, new_rn);
self.end_conditional_arm(&mut cond_state);
self.builder.ins().jump(merge_blk, &[]);
// Slow path: call jit_update_rn(state_ptr, numreg, modifier)
// jit_update_rn reads R/M/N[numreg] from memory (flushed above)
// and writes R[numreg] back.
self.builder.switch_to_block(nonlinear_blk);
self.builder.seal_block(nonlinear_blk);
let fn_ptr = self
.builder
.ins()
.iconst(self.ptr_ty, jit_update_rn as *const () as usize as i64);
let mut sig = Signature::new(HOST_CALL_CONV);
sig.params.push(AbiParam::new(self.ptr_ty)); // *mut DspState
sig.params.push(AbiParam::new(types::I32)); // numreg
sig.params.push(AbiParam::new(types::I32)); // modifier (i16 sign-extended to i32)
let sig_ref = self.builder.import_signature(sig);
let numreg_val = self.builder.ins().iconst(types::I32, numreg as i64);
self.builder
.ins()
.call_indirect(sig_ref, fn_ptr, &[self.state_ptr, numreg_val, modifier]);
self.end_conditional_arm(&mut cond_state);
self.builder.ins().jump(merge_blk, &[]);
self.builder.switch_to_block(merge_blk);
self.builder.seal_block(merge_blk);
self.merge_conditional(&cond_state);
}
}