use super::{inst_len_for_ea, *};
impl<'a> Emitter<'a> {
pub(super) fn emit_movep_0(&mut self, space: MemSpace, pp_offset: u8, reg_idx: u8, w: bool) {
self.set_inst_len(1);
self.set_cycles(1);
let pp_addr = 0xFFFFC0 + pp_offset as u32;
let reg_idx = reg_idx as usize;
if w {
let val = self.read_reg_for_move(reg_idx);
self.write_mem(space, pp_addr, val);
} else {
let val = self.read_mem(space, pp_addr);
self.write_reg_for_move(reg_idx, val);
}
}
pub(super) fn emit_movep_1(
&mut self,
space: MemSpace,
pp_offset: u8,
ea_mode: u8,
w: bool,
next_word: u32,
) {
self.set_inst_len(1);
self.set_cycles(6);
let pp_addr = 0xFFFFC0 + pp_offset as u32;
let (p_addr, _) = self.emit_calc_ea_ext(ea_mode as u32, next_word);
self.set_inst_len(inst_len_for_ea(ea_mode));
if w {
let val = self.read_mem_dyn(MemSpace::P, p_addr);
self.write_mem(space, pp_addr, val);
} else {
let val = self.read_mem(space, pp_addr);
self.write_mem_dyn(MemSpace::P, p_addr, val);
}
}
pub(super) fn emit_movep_23(
&mut self,
pp_offset: u8,
ea_mode: u8,
w: bool,
perspace: MemSpace,
easpace: MemSpace,
next_word: u32,
) {
self.set_inst_len(1);
self.set_cycles(2);
let pp_addr = 0xFFFFC0 + pp_offset as u32;
let (addr, is_imm) = self.emit_calc_ea_ext(ea_mode as u32, next_word);
self.set_inst_len(inst_len_for_ea(ea_mode));
if w {
let val = if is_imm {
addr } else {
self.read_mem_dyn(easpace, addr)
};
self.write_mem(perspace, pp_addr, val);
} else {
let val = self.read_mem(perspace, pp_addr);
self.write_mem_dyn(easpace, addr, val);
}
}
pub(super) fn emit_movep_qq(
&mut self,
qq_offset: u8,
ea_mode: u8,
w: bool,
qqspace: MemSpace,
easpace: MemSpace,
next_word: u32,
) {
self.set_cycles(2);
let qq_addr = 0xFFFF80 + qq_offset as u32;
self.set_inst_len(inst_len_for_ea(ea_mode));
let (ea_addr, is_immediate) = self.emit_calc_ea_ext(ea_mode as u32, next_word);
if w {
if is_immediate {
self.write_mem(qqspace, qq_addr, ea_addr);
} else {
let val = self.read_mem_dyn(easpace, ea_addr);
self.write_mem(qqspace, qq_addr, val);
}
} else {
let val = self.read_mem(qqspace, qq_addr);
self.write_mem_dyn(easpace, ea_addr, val);
}
}
pub(super) fn emit_movep_qq_pea(
&mut self,
qq_offset: u8,
ea_mode: u8,
w: bool,
space: MemSpace,
next_word: u32,
) {
self.set_cycles(6);
let qq_addr = 0xFFFF80 + qq_offset as u32;
self.set_inst_len(inst_len_for_ea(ea_mode));
let (ea_addr, _) = self.emit_calc_ea_ext(ea_mode as u32, next_word);
if w {
let val = self.read_mem_dyn(MemSpace::P, ea_addr);
self.write_mem(space, qq_addr, val);
} else {
let val = self.read_mem(space, qq_addr);
self.write_mem_dyn(MemSpace::P, ea_addr, val);
}
}
pub(super) fn emit_movep_qq_r(&mut self, qq_offset: u8, reg_idx: u8, w: bool, space: MemSpace) {
self.set_inst_len(1);
self.set_cycles(1);
let qq_addr = 0xFFFF80 + qq_offset as u32;
let reg_idx = reg_idx as usize;
if w {
let val = self.read_reg_for_move(reg_idx);
self.write_mem(space, qq_addr, val);
} else {
let val = self.read_mem(space, qq_addr);
self.write_reg_for_move(reg_idx, val);
}
}
pub(super) fn emit_movec_imm(&mut self, imm: u8, dest: u8) {
self.set_inst_len(1);
self.set_cycles(1);
let val = self.builder.ins().iconst(types::I32, imm as i64);
self.write_reg_for_move(dest as usize, val);
}
pub(super) fn emit_movec_reg(&mut self, src_reg: u8, dst_reg: u8, w: bool) {
self.set_inst_len(1);
self.set_cycles(1);
let src_reg = src_reg as usize;
let dst_reg = dst_reg as usize;
if w {
let val = self.read_reg_for_move(src_reg);
self.write_reg_for_move(dst_reg, val);
} else {
let val = self.read_reg_for_move(dst_reg);
self.write_reg_for_move(src_reg, val);
}
}
pub(super) fn emit_movec_ea(
&mut self,
ea_mode: u8,
numreg: u8,
w: bool,
space: MemSpace,
next_word: u32,
) {
self.set_cycles(1);
self.set_inst_len(inst_len_for_ea(ea_mode));
let dst_reg = numreg as usize;
let (addr, is_imm) = self.emit_calc_ea_ext(ea_mode as u32, next_word);
if w {
if is_imm {
self.write_reg_for_move(dst_reg, addr);
} else {
let val = self.read_mem_dyn(space, addr);
self.write_reg_for_move(dst_reg, val);
}
} else {
let val = self.read_reg_for_move(dst_reg);
self.write_mem_dyn(space, addr, val);
}
}
pub(super) fn emit_movec_aa(&mut self, addr: u8, numreg: u8, w: bool, space: MemSpace) {
self.set_inst_len(1);
self.set_cycles(1);
let addr = addr as u32;
let dst_reg = numreg as usize;
if w {
let val = self.read_mem(space, addr);
self.write_reg_for_move(dst_reg, val);
} else {
let val = self.read_reg_for_move(dst_reg);
self.write_mem(space, addr, val);
}
}
pub(super) fn emit_movem_ea(&mut self, ea_mode: u8, numreg: u8, w: bool, next_word: u32) {
self.set_cycles(6);
self.set_inst_len(inst_len_for_ea(ea_mode));
let numreg = numreg as usize;
let (addr, _) = self.emit_calc_ea_ext(ea_mode as u32, next_word);
if w {
let val = self.read_mem_dyn(MemSpace::P, addr);
self.write_reg_for_move(numreg, val);
} else {
let val = self.read_reg_for_move(numreg);
self.write_mem_dyn(MemSpace::P, addr, val);
}
}
pub(super) fn emit_movem_aa(&mut self, addr: u8, numreg: u8, w: bool) {
self.set_inst_len(1);
self.set_cycles(6);
let numreg = numreg as usize;
let addr_val = self.builder.ins().iconst(types::I32, addr as i64);
if w {
let val = self.read_mem_dyn(MemSpace::P, addr_val);
self.write_reg_for_move(numreg, val);
} else {
let val = self.read_reg_for_move(numreg);
self.write_mem_dyn(MemSpace::P, addr_val, val);
}
}
pub(super) fn emit_parallel(
&mut self,
opcode: u32,
move_type: ParallelMoveType,
alu: &ParallelAlu,
next_word: u32,
) {
self.set_inst_len(1);
self.set_cycles(1);
match move_type {
ParallelMoveType::Pm0 => self.emit_pm_0(opcode, alu, next_word),
ParallelMoveType::Pm1 => self.emit_pm_1(opcode, alu, next_word),
ParallelMoveType::Pm2 => self.emit_pm_2(opcode, alu),
ParallelMoveType::Pm3 => self.emit_pm_3(opcode, alu),
ParallelMoveType::Pm4 => self.emit_pm_4(opcode, alu, next_word),
ParallelMoveType::Pm5 => self.emit_pm_5(opcode, alu, next_word),
ParallelMoveType::Pm8 => self.emit_pm_8(opcode, alu),
}
}
pub(super) fn emit_pm_0(&mut self, opcode: u32, alu: &ParallelAlu, next_word: u32) {
let d_bit = (opcode >> 16) & 1;
let memspace = MemSpace::xy((opcode >> 15) & 1);
let ea_field = (opcode >> 8) & 0x3F;
let (ea_addr, _) = self.emit_calc_ea_ext(ea_field, next_word);
if (ea_field >> 3) & 0x7 == 6 {
self.set_inst_len(2);
}
let acc = reg::A + d_bit as usize;
let acc_enum = if d_bit == 0 {
Accumulator::A
} else {
Accumulator::B
};
let xy0_reg = if memspace == MemSpace::X {
reg::X0
} else {
reg::Y0
};
let save_acc = self.read_reg_for_move(acc); let save_xy0 = self.load_reg(xy0_reg);
let pre = self.load_acc(acc_enum);
self.emit_parallel_alu(alu);
let post = self.load_acc(acc_enum);
self.write_mem_dyn(memspace, ea_addr, save_acc);
self.write_reg_for_move(acc, save_xy0);
let alu_mod = self.builder.ins().icmp(IntCC::NotEqual, pre, post);
let cur = self.load_acc(acc_enum);
let final_acc = self.builder.ins().select(alu_mod, post, cur);
self.store_acc(acc_enum, final_acc);
}
pub(super) fn emit_pm_1(&mut self, opcode: u32, alu: &ParallelAlu, next_word: u32) {
let ea_field = (opcode >> 8) & 0x3F;
let (ea_addr, is_imm) = self.emit_calc_ea_ext(ea_field, next_word);
if (ea_field >> 3) & 0x7 == 6 {
self.set_inst_len(2);
}
let memspace = MemSpace::xy((opcode >> 14) & 1);
let numreg1 = if memspace == MemSpace::Y {
match (opcode >> 16) & 3 {
0 => reg::Y0,
1 => reg::Y1,
2 => reg::A,
3 => reg::B,
_ => unreachable!(),
}
} else {
match (opcode >> 18) & 3 {
0 => reg::X0,
1 => reg::X1,
2 => reg::A,
3 => reg::B,
_ => unreachable!(),
}
};
let w = (opcode >> 15) & 1;
let save_1 = if w == 1 {
if is_imm {
ea_addr
} else {
self.read_mem_dyn(memspace, ea_addr)
}
} else {
self.read_reg_for_move(numreg1)
};
let numreg2_src = if memspace == MemSpace::Y {
reg::A + ((opcode >> 19) & 1) as usize
} else {
reg::A + ((opcode >> 17) & 1) as usize
};
let save_2 = self.read_reg_for_move(numreg2_src);
self.emit_parallel_alu(alu);
if w == 1 {
self.write_reg_for_move(numreg1, save_1);
} else {
self.write_mem_dyn(memspace, ea_addr, save_1);
}
let numreg2_dst = if memspace == MemSpace::Y {
reg::X0 + ((opcode >> 18) & 1) as usize
} else {
reg::Y0 + ((opcode >> 16) & 1) as usize
};
self.store_reg(numreg2_dst, save_2);
}
pub(super) fn emit_pm_2(&mut self, opcode: u32, alu: &ParallelAlu) {
if (opcode & 0xFFFF00) == 0x200000 {
self.emit_parallel_alu(alu);
return;
}
if (opcode & 0xFFE000) == 0x204000 {
let ea_mode = (opcode >> 8) & 0x1F;
let (_addr, _) = self.emit_calc_ea(ea_mode);
self.emit_parallel_alu(alu);
return;
}
if (opcode & 0xFFF000) == 0x202000 {
self.emit_ifcc(opcode, alu, false);
return;
}
if (opcode & 0xFFF000) == 0x203000 {
self.emit_ifcc(opcode, alu, true);
return;
}
if (opcode & 0xFC0000) == 0x200000 {
self.emit_pm_2_2(opcode, alu);
return;
}
self.emit_pm_3(opcode, alu);
}
pub(super) fn emit_pm_2_2(&mut self, opcode: u32, alu: &ParallelAlu) {
let src_reg = ((opcode >> 13) & 0x1F) as usize;
let dst_reg = ((opcode >> 8) & 0x1F) as usize;
let save_val = self.read_reg_for_move(src_reg);
self.emit_parallel_alu(alu);
self.write_reg_for_move(dst_reg, save_val);
}
pub(super) fn emit_pm_3(&mut self, opcode: u32, alu: &ParallelAlu) {
let dst_reg = ((opcode >> 16) & 0x1F) as usize;
let mut imm_val = (opcode >> 8) & 0xFF;
match dst_reg {
reg::X0 | reg::X1 | reg::Y0 | reg::Y1 | reg::A | reg::B => {
imm_val <<= 16;
}
_ => {}
}
self.emit_parallel_alu(alu);
let v = self.builder.ins().iconst(types::I32, imm_val as i64);
self.write_reg_for_move(dst_reg, v);
}
pub(super) fn emit_pm_4(&mut self, opcode: u32, alu: &ParallelAlu, next_word: u32) {
if (opcode & 0xF40000) == 0x400000 {
self.emit_pm_4x(opcode, alu, next_word);
} else {
self.emit_pm_5(opcode, alu, next_word);
}
}
pub(super) fn emit_pm_4x(&mut self, opcode: u32, alu: &ParallelAlu, next_word: u32) {
let ea_field = (opcode >> 8) & 0x3F;
let numreg = ((opcode >> 16) & 0x3) | (((opcode >> 19) & 1) << 2);
let w = (opcode >> 15) & 1;
if (opcode >> 14) & 1 != 0 {
let (addr, _) = self.emit_calc_ea_ext(ea_field, next_word);
if (ea_field >> 3) & 0x7 == 6 {
self.set_inst_len(2);
}
if w == 1 {
let save_lx = self.read_mem_dyn(MemSpace::X, addr);
let save_ly = self.read_mem_dyn(MemSpace::Y, addr);
self.emit_parallel_alu(alu);
self.write_l_reg(numreg, save_lx, save_ly);
} else {
let (save_lx, save_ly) = self.read_l_reg(numreg);
self.emit_parallel_alu(alu);
self.write_mem_dyn(MemSpace::X, addr, save_lx);
self.write_mem_dyn(MemSpace::Y, addr, save_ly);
}
} else {
let addr = ea_field;
if w == 1 {
let save_lx = self.read_mem(MemSpace::X, addr);
let save_ly = self.read_mem(MemSpace::Y, addr);
self.emit_parallel_alu(alu);
self.write_l_reg(numreg, save_lx, save_ly);
} else {
let (save_lx, save_ly) = self.read_l_reg(numreg);
self.emit_parallel_alu(alu);
self.write_mem(MemSpace::X, addr, save_lx);
self.write_mem(MemSpace::Y, addr, save_ly);
}
}
}
pub(super) fn emit_pm_5(&mut self, opcode: u32, alu: &ParallelAlu, next_word: u32) {
let memspace = MemSpace::xy((opcode >> 19) & 1);
let numreg_raw = ((opcode >> 16) & 0x7) | ((opcode >> 17) & (0x3 << 3));
let numreg = numreg_raw as usize;
let w = (opcode >> 15) & 1;
let ea_field = (opcode >> 8) & 0x3F;
if (opcode >> 14) & 1 == 0 {
let addr = ea_field;
if w == 1 {
let save_val = self.read_mem(memspace, addr);
self.emit_parallel_alu(alu);
self.write_reg_for_move(numreg, save_val);
} else {
let save_val = self.read_reg_for_move(numreg);
self.emit_parallel_alu(alu);
self.write_mem(memspace, addr, save_val);
}
} else {
let (addr, is_imm) = self.emit_calc_ea_ext(ea_field, next_word);
if (ea_field >> 3) & 0x7 == 6 {
self.set_inst_len(2);
}
if w == 1 {
let save_val = if is_imm {
addr
} else {
self.read_mem_dyn(memspace, addr)
};
self.emit_parallel_alu(alu);
self.write_reg_for_move(numreg, save_val);
} else {
let save_val = self.read_reg_for_move(numreg);
self.emit_parallel_alu(alu);
self.write_mem_dyn(memspace, addr, save_val);
}
}
}
pub(super) fn emit_pm_8(&mut self, opcode: u32, alu: &ParallelAlu) {
let mut ea1 = (opcode >> 8) & 0x1F;
if (ea1 >> 3) == 0 {
ea1 |= 1 << 5;
}
let mut ea2 = ((opcode >> 13) & 0x3) | ((opcode >> 17) & (0x3 << 3));
if (ea1 & (1 << 2)) == 0 {
ea2 |= 1 << 2;
}
if (ea2 >> 3) == 0 {
ea2 |= 1 << 5;
}
let (x_addr, _) = self.emit_calc_ea(ea1);
let (y_addr, _) = self.emit_calc_ea(ea2);
let numreg1 = match (opcode >> 18) & 0x3 {
0 => reg::X0,
1 => reg::X1,
2 => reg::A,
3 => reg::B,
_ => unreachable!(),
};
let numreg2 = match (opcode >> 16) & 0x3 {
0 => reg::Y0,
1 => reg::Y1,
2 => reg::A,
3 => reg::B,
_ => unreachable!(),
};
let save_reg1 = if (opcode >> 15) & 1 == 1 {
self.read_mem_dyn(MemSpace::X, x_addr)
} else {
self.read_reg_for_move(numreg1)
};
let save_reg2 = if (opcode >> 22) & 1 == 1 {
self.read_mem_dyn(MemSpace::Y, y_addr)
} else {
self.read_reg_for_move(numreg2)
};
self.emit_parallel_alu(alu);
if (opcode >> 15) & 1 == 1 {
self.write_reg_for_move(numreg1, save_reg1);
} else {
self.write_mem_dyn(MemSpace::X, x_addr, save_reg1);
}
if (opcode >> 22) & 1 == 1 {
self.write_reg_for_move(numreg2, save_reg2);
} else {
self.write_mem_dyn(MemSpace::Y, y_addr, save_reg2);
}
}
pub(super) fn emit_move_long_disp(
&mut self,
space: MemSpace,
w: bool,
offreg_idx: u8,
numreg: u8,
next_word: u32,
) {
self.set_inst_len(2);
self.set_cycles(3);
let offreg = reg::R0 + offreg_idx as usize;
let numreg = numreg as usize;
let rn = self.load_reg(offreg);
let offset = self.builder.ins().iconst(types::I32, next_word as i64);
let addr = self.builder.ins().iadd(rn, offset);
let addr = self.mask24(addr);
if w {
let val = self.read_mem_dyn(space, addr);
self.write_reg_for_move(numreg, val);
} else {
let val = self.read_reg_for_move(numreg);
self.write_mem_dyn(space, addr, val);
}
}
pub(super) fn emit_move_short_disp(
&mut self,
offset: u8,
w: bool,
offreg_idx: u8,
numreg: u8,
space: MemSpace,
) {
self.set_inst_len(1);
self.set_cycles(2);
let offreg = reg::R0 + offreg_idx as usize;
let numreg = numreg as usize;
let sext_xxx = ((offset as i32) << 25) >> 25;
let rn = self.load_reg(offreg);
let off_val = self.builder.ins().iconst(types::I32, sext_xxx as i64);
let addr = self.builder.ins().iadd(rn, off_val);
let addr = self.mask24(addr);
if w {
let val = self.read_mem_dyn(space, addr);
self.write_reg_for_move(numreg, val);
} else {
let val = self.read_reg_for_move(numreg);
self.write_mem_dyn(space, addr, val);
}
}
pub(super) fn emit_vsl(&mut self, s: Accumulator, ea_mode: u8, i_bit: u8, next_word: u32) {
let mode = (ea_mode >> 3) & 0x7;
self.set_inst_len(if mode == 6 { 2 } else { 1 });
self.set_cycles(1);
let (addr, _) = self.emit_calc_ea_ext(ea_mode as u32, next_word);
let acc = self.load_acc(s);
let upper = self.extract_acc_mid(acc);
self.write_mem_dyn(MemSpace::X, addr, upper);
let lower = self.extract_acc_lo(acc);
let c1 = self.builder.ins().iconst(types::I32, 1);
let shifted = self.builder.ins().ishl(lower, c1);
let i_val = self.builder.ins().iconst(types::I32, i_bit as i64);
let result = self.builder.ins().bor(shifted, i_val);
let result = self.mask24(result);
self.write_mem_dyn(MemSpace::Y, addr, result);
}
pub(super) fn emit_lua(&mut self, ea_mode: u8, dst_reg: u8) {
self.set_inst_len(1);
self.set_cycles(3);
let srcreg = (ea_mode & 0x7) as usize;
let dstreg = (dst_reg & 0x7) as usize;
let saved_rn = self.load_reg(reg::R0 + srcreg);
let (_addr, _) = self.emit_calc_ea(ea_mode as u32);
let new_rn = self.load_reg(reg::R0 + srcreg);
self.store_reg(reg::R0 + srcreg, saved_rn);
if dst_reg & 8 != 0 {
self.store_reg(reg::N0 + dstreg, new_rn);
} else {
self.store_reg(reg::R0 + dstreg, new_rn);
}
}
pub(super) fn emit_lua_rel(&mut self, aa: u8, addr_reg: u8, dst_reg: u8, dest_is_n: bool) {
self.set_inst_len(1);
self.set_cycles(3);
let aa_signed = if aa & 0x40 != 0 {
aa as i32 | !0x7F
} else {
aa as i32
};
let rn = self.load_reg(reg::R0 + addr_reg as usize);
let off = self.builder.ins().iconst(types::I32, aa_signed as i64);
let result = self.builder.ins().iadd(rn, off);
let result = self.mask24(result);
if dest_is_n {
self.store_reg(reg::N0 + dst_reg as usize, result);
} else {
self.store_reg(reg::R0 + dst_reg as usize, result);
}
}
pub(super) fn emit_lra_rn(&mut self, addr_reg: u8, dst_reg: u8, pc: u32) {
self.set_inst_len(1);
self.set_cycles(3);
let rn = self.load_reg(reg::R0 + addr_reg as usize);
let pc_val = self.builder.ins().iconst(types::I32, pc as i64);
let result = self.builder.ins().iadd(rn, pc_val);
let result = self.mask24(result);
self.write_reg_for_move(dst_reg as usize, result);
}
pub(super) fn emit_lra_disp(&mut self, dst_reg: u8, pc: u32, next_word: u32) {
self.set_inst_len(2);
self.set_cycles(3);
let target = mask_pc(pc.wrapping_add(next_word));
let v = self.builder.ins().iconst(types::I32, target as i64);
self.write_reg_for_move(dst_reg as usize, v);
}
}