1use crate::Sh2; 2 3#[derive(Debug, Clone, Copy, PartialEq, Eq)] 4pub enum MemoryAccessSize { 5 Byte, 6 Word, 7 Longword, 8} 9 10#[derive(Debug, Clone, Copy)] 11pub enum Displacement { 12 Immediate(u32), 13 Register(u16), 14} 15 16impl Displacement { 17 #[must_use] 18 pub fn resolve(self, size: MemoryAccessSize, cpu: &Sh2) -> u32 { 19 match self { 20 Self::Immediate(displacement) => match size { 21 MemoryAccessSize::Byte => displacement, 22 MemoryAccessSize::Word => displacement << 1, 23 MemoryAccessSize::Longword => displacement << 2, 24 }, 25 Self::Register(r) => cpu.registers.gpr[r as usize], 26 } 27 } 28} 29 30impl Displacement { 31 fn none() -> Self { 32 Self::Immediate(0) 33 } 34} 35 36#[derive(Debug, Clone, Copy, PartialEq, Eq)] 37pub enum ReadType { 38 Load, 39 EffectiveAddress, // MOVA, JMP, JSR, BRAF, BSRF 40} 41 42#[derive(Debug, Clone, Copy)] 43pub enum MemoryAccess { 44 IndirectR { register: u16, displacement: Displacement }, 45 IndirectRPredecrement { register: u16 }, 46 IndirectGbr { displacement: Displacement }, 47 PcRelative { pc: u32, displacement: Displacement }, 48} 49 50impl MemoryAccess { 51 #[must_use] 52 pub fn resolve_address(self, size: MemoryAccessSize, cpu: &Sh2) -> u32 { 53 match self { 54 Self::IndirectR { register, displacement } => { 55 cpu.registers().gpr[register as usize].wrapping_add(displacement.resolve(size, cpu)) 56 } 57 Self::IndirectRPredecrement { register } => { 58 let address = cpu.registers.gpr[register as usize]; 59 match size { 60 MemoryAccessSize::Byte => address.wrapping_sub(1), 61 MemoryAccessSize::Word => address.wrapping_sub(2), 62 MemoryAccessSize::Longword => address.wrapping_sub(4), 63 } 64 } 65 Self::IndirectGbr { displacement } => { 66 cpu.registers().gbr.wrapping_add(displacement.resolve(size, cpu)) 67 } 68 Self::PcRelative { mut pc, displacement } => { 69 pc = pc.wrapping_add(4); 70 if size == MemoryAccessSize::Longword { 71 pc &= !3; 72 } 73 pc.wrapping_add(displacement.resolve(size, cpu)) 74 } 75 } 76 } 77} 78 79pub struct DisassembledInstruction { 80 pub pc: u32, 81 pub text: String, 82 pub opcode: u16, 83 pub memory_read: Option<(MemoryAccess, MemoryAccessSize)>, 84 pub memory_read_type: ReadType, 85 pub memory_write: Option<(MemoryAccess, MemoryAccessSize)>, 86} 87 88impl Default for DisassembledInstruction { 89 fn default() -> Self { 90 Self::new() 91 } 92} 93 94impl DisassembledInstruction { 95 #[must_use] 96 pub fn new() -> Self { 97 Self { 98 pc: 0, 99 text: String::new(), 100 opcode: 0, 101 memory_read: None, 102 memory_read_type: ReadType::Load, 103 memory_write: None, 104 } 105 } 106 107 pub fn clear(&mut self) { 108 self.text.clear(); 109 self.memory_read = None; 110 self.memory_read_type = ReadType::Load; 111 self.memory_write = None; 112 } 113} 114 115pub fn disassemble_into(pc: u32, opcode: u16, out: &mut DisassembledInstruction) { 116 out.clear(); 117 118 out.text = match opcode { 119 0b0000_0000_0001_1001 => "div0u".into(), 120 0b0000_0000_0000_1011 => "rts".into(), 121 0b0000_0000_0000_1000 => "clrt".into(), 122 0b0000_0000_0010_1000 => "clrmac".into(), 123 0b0000_0000_0000_1001 => "nop".into(), 124 0b0000_0000_0010_1011 => "rte".into(), 125 0b0000_0000_0001_1000 => "sett".into(), 126 0b0000_0000_0001_1011 => "sleep".into(), 127 _ => decode_xnnx(pc, opcode, out), 128 }; 129} 130 131#[inline] 132fn decode_xnnx(pc: u32, opcode: u16, out: &mut DisassembledInstruction) -> String { 133 match opcode & 0b1111_0000_0000_1111 { 134 0b0110_0000_0000_0011 => { 135 format!("mov r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 136 } 137 0b0010_0000_0000_0000 => { 138 let dest = parse_register_high(opcode); 139 out.memory_write = Some(( 140 MemoryAccess::IndirectR { register: dest, displacement: Displacement::none() }, 141 MemoryAccessSize::Byte, 142 )); 143 format!("mov.b r{}, @r{}", parse_register_low(opcode), dest) 144 } 145 0b0010_0000_0000_0001 => { 146 let dest = parse_register_high(opcode); 147 out.memory_write = Some(( 148 MemoryAccess::IndirectR { register: dest, displacement: Displacement::none() }, 149 MemoryAccessSize::Word, 150 )); 151 format!("mov.w r{}, @r{}", parse_register_low(opcode), dest) 152 } 153 0b0010_0000_0000_0010 => { 154 let dest = parse_register_high(opcode); 155 out.memory_write = Some(( 156 MemoryAccess::IndirectR { register: dest, displacement: Displacement::none() }, 157 MemoryAccessSize::Longword, 158 )); 159 format!("mov.l r{}, @r{}", parse_register_low(opcode), dest) 160 } 161 0b0110_0000_0000_0000 => { 162 let source = parse_register_low(opcode); 163 out.memory_read = Some(( 164 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 165 MemoryAccessSize::Byte, 166 )); 167 format!("mov.b @r{}, r{}", source, parse_register_high(opcode)) 168 } 169 0b0110_0000_0000_0001 => { 170 let source = parse_register_low(opcode); 171 out.memory_read = Some(( 172 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 173 MemoryAccessSize::Word, 174 )); 175 format!("mov.w @r{}, r{}", source, parse_register_high(opcode)) 176 } 177 0b0110_0000_0000_0010 => { 178 let source = parse_register_low(opcode); 179 out.memory_read = Some(( 180 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 181 MemoryAccessSize::Longword, 182 )); 183 format!("mov.l @r{}, r{}", source, parse_register_high(opcode)) 184 } 185 0b0010_0000_0000_0100 => { 186 let dest = parse_register_high(opcode); 187 out.memory_write = Some(( 188 MemoryAccess::IndirectRPredecrement { register: dest }, 189 MemoryAccessSize::Byte, 190 )); 191 format!("mov.b r{}, @-r{}", parse_register_low(opcode), dest) 192 } 193 0b0010_0000_0000_0101 => { 194 let dest = parse_register_high(opcode); 195 out.memory_write = Some(( 196 MemoryAccess::IndirectRPredecrement { register: dest }, 197 MemoryAccessSize::Word, 198 )); 199 format!("mov.w r{}, @-r{}", parse_register_low(opcode), dest) 200 } 201 0b0010_0000_0000_0110 => { 202 let dest = parse_register_high(opcode); 203 out.memory_write = Some(( 204 MemoryAccess::IndirectRPredecrement { register: dest }, 205 MemoryAccessSize::Longword, 206 )); 207 format!("mov.l r{}, @-r{}", parse_register_low(opcode), dest) 208 } 209 0b0110_0000_0000_0100 => { 210 let source = parse_register_low(opcode); 211 out.memory_read = Some(( 212 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 213 MemoryAccessSize::Byte, 214 )); 215 format!("mov.b @r{}+, r{}", source, parse_register_high(opcode)) 216 } 217 0b0110_0000_0000_0101 => { 218 let source = parse_register_low(opcode); 219 out.memory_read = Some(( 220 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 221 MemoryAccessSize::Word, 222 )); 223 format!("mov.w @r{}+, r{}", source, parse_register_high(opcode)) 224 } 225 0b0110_0000_0000_0110 => { 226 let source = parse_register_low(opcode); 227 out.memory_read = Some(( 228 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 229 MemoryAccessSize::Longword, 230 )); 231 format!("mov.l @r{}+, r{}", source, parse_register_high(opcode)) 232 } 233 0b0000_0000_0000_0100 => { 234 let dest = parse_register_high(opcode); 235 out.memory_write = Some(( 236 MemoryAccess::IndirectR { register: dest, displacement: Displacement::Register(0) }, 237 MemoryAccessSize::Byte, 238 )); 239 format!("mov.b r{}, @(r0,r{})", parse_register_low(opcode), dest) 240 } 241 0b0000_0000_0000_0101 => { 242 let dest = parse_register_high(opcode); 243 out.memory_write = Some(( 244 MemoryAccess::IndirectR { register: dest, displacement: Displacement::Register(0) }, 245 MemoryAccessSize::Word, 246 )); 247 format!("mov.w r{}, @(r0,r{})", parse_register_low(opcode), dest) 248 } 249 0b0000_0000_0000_0110 => { 250 let dest = parse_register_high(opcode); 251 out.memory_write = Some(( 252 MemoryAccess::IndirectR { register: dest, displacement: Displacement::Register(0) }, 253 MemoryAccessSize::Longword, 254 )); 255 format!("mov.l r{}, @(r0,r{})", parse_register_low(opcode), dest) 256 } 257 0b0000_0000_0000_1100 => { 258 let source = parse_register_low(opcode); 259 out.memory_read = Some(( 260 MemoryAccess::IndirectR { 261 register: source, 262 displacement: Displacement::Register(0), 263 }, 264 MemoryAccessSize::Byte, 265 )); 266 format!("mov.b @(r0,r{}), r{}", source, parse_register_high(opcode)) 267 } 268 0b0000_0000_0000_1101 => { 269 let source = parse_register_low(opcode); 270 out.memory_read = Some(( 271 MemoryAccess::IndirectR { 272 register: source, 273 displacement: Displacement::Register(0), 274 }, 275 MemoryAccessSize::Word, 276 )); 277 format!("mov.w @(r0,r{}), r{}", source, parse_register_high(opcode)) 278 } 279 0b0000_0000_0000_1110 => { 280 let source = parse_register_low(opcode); 281 out.memory_read = Some(( 282 MemoryAccess::IndirectR { 283 register: source, 284 displacement: Displacement::Register(0), 285 }, 286 MemoryAccessSize::Longword, 287 )); 288 format!("mov.l @(r0,r{}), r{}", source, parse_register_high(opcode)) 289 } 290 0b0110_0000_0000_1000 => { 291 format!("swap.b r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 292 } 293 0b0110_0000_0000_1001 => { 294 format!("swap.w r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 295 } 296 0b0010_0000_0000_1101 => { 297 format!("xtrct r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 298 } 299 0b0011_0000_0000_1100 => { 300 format!("add r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 301 } 302 0b0011_0000_0000_1110 => { 303 format!("addc r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 304 } 305 0b0011_0000_0000_1111 => { 306 format!("addv r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 307 } 308 0b0011_0000_0000_0000 => { 309 format!("cmp/eq r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 310 } 311 0b0011_0000_0000_0010 => { 312 format!("cmp/hs r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 313 } 314 0b0011_0000_0000_0011 => { 315 format!("cmp/ge r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 316 } 317 0b0011_0000_0000_0110 => { 318 format!("cmp/hi r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 319 } 320 0b0011_0000_0000_0111 => { 321 format!("cmp/gt r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 322 } 323 0b0010_0000_0000_1100 => { 324 format!("cmp/str r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 325 } 326 0b0011_0000_0000_0100 => { 327 format!("div1 r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 328 } 329 0b0010_0000_0000_0111 => { 330 format!("div0s r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 331 } 332 0b0011_0000_0000_1101 => { 333 format!("dmuls.l r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 334 } 335 0b0011_0000_0000_0101 => { 336 format!("dmulu.l r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 337 } 338 0b0110_0000_0000_1110 => { 339 format!("exts.b r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 340 } 341 0b0110_0000_0000_1111 => { 342 format!("exts.w r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 343 } 344 0b0110_0000_0000_1100 => { 345 format!("extu.b r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 346 } 347 0b0110_0000_0000_1101 => { 348 format!("extu.w r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 349 } 350 0b0000_0000_0000_1111 => { 351 let source = parse_register_low(opcode); 352 let dest = parse_register_high(opcode); 353 out.memory_read = Some(( 354 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 355 MemoryAccessSize::Longword, 356 )); 357 out.memory_write = Some(( 358 MemoryAccess::IndirectR { register: dest, displacement: Displacement::none() }, 359 MemoryAccessSize::Longword, 360 )); 361 format!("mac.l @r{source}+, @r{dest}+") 362 } 363 0b0100_0000_0000_1111 => { 364 let source = parse_register_low(opcode); 365 let dest = parse_register_high(opcode); 366 out.memory_read = Some(( 367 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 368 MemoryAccessSize::Word, 369 )); 370 out.memory_write = Some(( 371 MemoryAccess::IndirectR { register: dest, displacement: Displacement::none() }, 372 MemoryAccessSize::Word, 373 )); 374 format!("mac.w @r{source}+, @r{dest}+") 375 } 376 0b0000_0000_0000_0111 => { 377 format!("mul.l r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 378 } 379 0b0010_0000_0000_1111 => { 380 format!("muls.w r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 381 } 382 0b0010_0000_0000_1110 => { 383 format!("mulu.w r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 384 } 385 0b0110_0000_0000_1011 => { 386 format!("neg r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 387 } 388 0b0110_0000_0000_1010 => { 389 format!("negc r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 390 } 391 0b0011_0000_0000_1000 => { 392 format!("sub r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 393 } 394 0b0011_0000_0000_1010 => { 395 format!("subc r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 396 } 397 0b0011_0000_0000_1011 => { 398 format!("subv r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 399 } 400 0b0010_0000_0000_1001 => { 401 format!("and r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 402 } 403 0b0110_0000_0000_0111 => { 404 format!("not r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 405 } 406 0b0010_0000_0000_1011 => { 407 format!("or r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 408 } 409 0b0010_0000_0000_1000 => { 410 format!("tst r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 411 } 412 0b0010_0000_0000_1010 => { 413 format!("xor r{}, r{}", parse_register_low(opcode), parse_register_high(opcode)) 414 } 415 _ => decode_xxnn(pc, opcode, out), 416 } 417} 418 419#[inline] 420fn decode_xxnn(pc: u32, opcode: u16, out: &mut DisassembledInstruction) -> String { 421 match opcode & 0b1111_1111_0000_0000 { 422 0b1000_0000_0000_0000 => { 423 let displacement: u32 = parse_4bit_displacement(opcode).into(); 424 let dest = parse_register_low(opcode); 425 out.memory_write = Some(( 426 MemoryAccess::IndirectR { 427 register: dest, 428 displacement: Displacement::Immediate(displacement), 429 }, 430 MemoryAccessSize::Byte, 431 )); 432 format!("mov.b r0, @({displacement},r{dest})") 433 } 434 0b1000_0001_0000_0000 => { 435 let displacement: u32 = parse_4bit_displacement(opcode).into(); 436 let dest = parse_register_low(opcode); 437 out.memory_write = Some(( 438 MemoryAccess::IndirectR { 439 register: dest, 440 displacement: Displacement::Immediate(displacement), 441 }, 442 MemoryAccessSize::Word, 443 )); 444 format!("mov.w r0, @({displacement},r{dest})") 445 } 446 0b1000_0100_0000_0000 => { 447 let displacement: u32 = parse_4bit_displacement(opcode).into(); 448 let source = parse_register_low(opcode); 449 out.memory_read = Some(( 450 MemoryAccess::IndirectR { 451 register: source, 452 displacement: Displacement::Immediate(displacement), 453 }, 454 MemoryAccessSize::Byte, 455 )); 456 format!("mov.b @({displacement},r{source}), r0") 457 } 458 0b1000_0101_0000_0000 => { 459 let displacement: u32 = parse_4bit_displacement(opcode).into(); 460 let source = parse_register_low(opcode); 461 out.memory_read = Some(( 462 MemoryAccess::IndirectR { 463 register: source, 464 displacement: Displacement::Immediate(displacement), 465 }, 466 MemoryAccessSize::Word, 467 )); 468 format!("mov.w @({displacement},r{source}), r0") 469 } 470 0b1100_0000_0000_0000 => { 471 let displacement: u32 = parse_8bit_displacement(opcode).into(); 472 out.memory_write = Some(( 473 MemoryAccess::IndirectGbr { displacement: Displacement::Immediate(displacement) }, 474 MemoryAccessSize::Byte, 475 )); 476 format!("mov.b r0, @({displacement},gbr)") 477 } 478 0b1100_0001_0000_0000 => { 479 let displacement: u32 = parse_8bit_displacement(opcode).into(); 480 out.memory_write = Some(( 481 MemoryAccess::IndirectGbr { displacement: Displacement::Immediate(displacement) }, 482 MemoryAccessSize::Word, 483 )); 484 format!("mov.w r0, @({displacement},gbr)") 485 } 486 0b1100_0010_0000_0000 => { 487 let displacement: u32 = parse_8bit_displacement(opcode).into(); 488 out.memory_write = Some(( 489 MemoryAccess::IndirectGbr { displacement: Displacement::Immediate(displacement) }, 490 MemoryAccessSize::Longword, 491 )); 492 format!("mov.l r0, @({displacement},gbr)") 493 } 494 0b1100_0100_0000_0000 => { 495 let displacement: u32 = parse_8bit_displacement(opcode).into(); 496 out.memory_read = Some(( 497 MemoryAccess::IndirectGbr { displacement: Displacement::Immediate(displacement) }, 498 MemoryAccessSize::Byte, 499 )); 500 format!("mov.b @({displacement},gbr), r0") 501 } 502 0b1100_0101_0000_0000 => { 503 let displacement: u32 = parse_8bit_displacement(opcode).into(); 504 out.memory_read = Some(( 505 MemoryAccess::IndirectGbr { displacement: Displacement::Immediate(displacement) }, 506 MemoryAccessSize::Word, 507 )); 508 format!("mov.w @({displacement},gbr), r0") 509 } 510 0b1100_0110_0000_0000 => { 511 let displacement: u32 = parse_8bit_displacement(opcode).into(); 512 out.memory_read = Some(( 513 MemoryAccess::IndirectGbr { displacement: Displacement::Immediate(displacement) }, 514 MemoryAccessSize::Longword, 515 )); 516 format!("mov.l @({displacement},gbr), r0") 517 } 518 0b1100_0111_0000_0000 => { 519 let displacement: u32 = parse_8bit_displacement(opcode).into(); 520 out.memory_read = Some(( 521 MemoryAccess::PcRelative { 522 pc, 523 displacement: Displacement::Immediate(displacement), 524 }, 525 MemoryAccessSize::Longword, 526 )); 527 out.memory_read_type = ReadType::EffectiveAddress; 528 format!("mova @({displacement},pc), r0") 529 } 530 0b1000_1000_0000_0000 => format!("cmp/eq #{}, r0", parse_signed_immediate(opcode)), 531 0b1100_1001_0000_0000 => format!("and #{}, r0", parse_unsigned_immediate(opcode)), 532 0b1100_1101_0000_0000 => { 533 out.memory_read = Some(( 534 MemoryAccess::IndirectGbr { displacement: Displacement::Register(0) }, 535 MemoryAccessSize::Byte, 536 )); 537 out.memory_write = out.memory_read; 538 format!("and.b #{}, @(r0,gbr)", parse_unsigned_immediate(opcode)) 539 } 540 0b1100_1011_0000_0000 => format!("or #{}, r0", parse_unsigned_immediate(opcode)), 541 0b1100_1111_0000_0000 => { 542 out.memory_read = Some(( 543 MemoryAccess::IndirectGbr { displacement: Displacement::Register(0) }, 544 MemoryAccessSize::Byte, 545 )); 546 out.memory_write = out.memory_read; 547 format!("or.b #{}, @(r0,gbr)", parse_unsigned_immediate(opcode)) 548 } 549 0b1100_1000_0000_0000 => format!("tst #{}, r0", parse_unsigned_immediate(opcode)), 550 0b1100_1100_0000_0000 => { 551 out.memory_read = Some(( 552 MemoryAccess::IndirectGbr { displacement: Displacement::Register(0) }, 553 MemoryAccessSize::Byte, 554 )); 555 out.memory_write = out.memory_read; 556 format!("tst.b #{}, @(r0,gbr)", parse_unsigned_immediate(opcode)) 557 } 558 0b1100_1010_0000_0000 => format!("xor #{}, r0", parse_unsigned_immediate(opcode)), 559 0b1100_1110_0000_0000 => { 560 out.memory_read = Some(( 561 MemoryAccess::IndirectGbr { displacement: Displacement::Register(0) }, 562 MemoryAccessSize::Byte, 563 )); 564 out.memory_write = out.memory_read; 565 format!("xor.b #{}, @(r0,gbr)", parse_unsigned_immediate(opcode)) 566 } 567 0b1000_1011_0000_0000 => { 568 format!("bf {}", branch_destination(pc, parse_signed_immediate(opcode) as u32,)) 569 } 570 0b1000_1111_0000_0000 => { 571 format!("bf/s {}", branch_destination(pc, parse_signed_immediate(opcode) as u32,)) 572 } 573 0b1000_1001_0000_0000 => { 574 format!("bt {}", branch_destination(pc, parse_signed_immediate(opcode) as u32,)) 575 } 576 0b1000_1101_0000_0000 => { 577 format!("bt/s {}", branch_destination(pc, parse_signed_immediate(opcode) as u32,)) 578 } 579 0b1100_0011_0000_0000 => format!("trapa #{}", opcode & 0xFF), 580 _ => decode_xnxx(pc, opcode, out), 581 } 582} 583 584#[inline] 585fn decode_xnxx(pc: u32, opcode: u16, out: &mut DisassembledInstruction) -> String { 586 match opcode & 0b1111_0000_1111_1111 { 587 0b0000_0000_0010_1001 => format!("movt r{}", parse_register_high(opcode)), 588 0b0100_0000_0001_0001 => format!("cmp/pz r{}", parse_register_high(opcode)), 589 0b0100_0000_0001_0101 => format!("cmp/pl r{}", parse_register_high(opcode)), 590 0b0100_0000_0001_0000 => format!("dt r{}", parse_register_high(opcode)), 591 0b0100_0000_0001_1011 => { 592 let register = parse_register_high(opcode); 593 out.memory_read = Some(( 594 MemoryAccess::IndirectR { register, displacement: Displacement::none() }, 595 MemoryAccessSize::Byte, 596 )); 597 out.memory_write = out.memory_read; 598 format!("tas.b @r{register}") 599 } 600 0b0100_0000_0000_0100 => format!("rotl r{}", parse_register_high(opcode)), 601 0b0100_0000_0000_0101 => format!("rotr r{}", parse_register_high(opcode)), 602 0b0100_0000_0010_0100 => format!("rotcl r{}", parse_register_high(opcode)), 603 0b0100_0000_0010_0101 => format!("rotcr r{}", parse_register_high(opcode)), 604 0b0100_0000_0010_0000 => format!("shal r{}", parse_register_high(opcode)), 605 0b0100_0000_0010_0001 => format!("shar r{}", parse_register_high(opcode)), 606 0b0100_0000_0000_0000 => format!("shll r{}", parse_register_high(opcode)), 607 0b0100_0000_0000_0001 => format!("shlr r{}", parse_register_high(opcode)), 608 0b0100_0000_0000_1000 => format!("shll2 r{}", parse_register_high(opcode)), 609 0b0100_0000_0000_1001 => format!("shlr2 r{}", parse_register_high(opcode)), 610 0b0100_0000_0001_1000 => format!("shll8 r{}", parse_register_high(opcode)), 611 0b0100_0000_0001_1001 => format!("shlr8 r{}", parse_register_high(opcode)), 612 0b0100_0000_0010_1000 => format!("shll16 r{}", parse_register_high(opcode)), 613 0b0100_0000_0010_1001 => format!("shlr16 r{}", parse_register_high(opcode)), 614 0b0000_0000_0010_0011 => { 615 let register = parse_register_high(opcode); 616 out.memory_read = Some(( 617 MemoryAccess::PcRelative { pc, displacement: Displacement::Register(register) }, 618 MemoryAccessSize::Word, 619 )); 620 out.memory_read_type = ReadType::EffectiveAddress; 621 format!("braf r{register}") 622 } 623 0b0000_0000_0000_0011 => { 624 let register = parse_register_high(opcode); 625 out.memory_read = Some(( 626 MemoryAccess::PcRelative { pc, displacement: Displacement::Register(register) }, 627 MemoryAccessSize::Word, 628 )); 629 out.memory_read_type = ReadType::EffectiveAddress; 630 format!("bsrf r{register}") 631 } 632 0b0100_0000_0010_1011 => { 633 let register = parse_register_high(opcode); 634 out.memory_read = Some(( 635 MemoryAccess::IndirectR { register, displacement: Displacement::none() }, 636 MemoryAccessSize::Longword, 637 )); 638 out.memory_read_type = ReadType::EffectiveAddress; 639 format!("jmp @r{register}") 640 } 641 0b0100_0000_0000_1011 => { 642 let register = parse_register_high(opcode); 643 out.memory_read = Some(( 644 MemoryAccess::IndirectR { register, displacement: Displacement::none() }, 645 MemoryAccessSize::Longword, 646 )); 647 out.memory_read_type = ReadType::EffectiveAddress; 648 format!("jsr @r{register}") 649 } 650 0b0100_0000_0000_1110 => format!("ldc r{}, sr", parse_register_high(opcode)), 651 0b0100_0000_0001_1110 => format!("ldc r{}, gbr", parse_register_high(opcode)), 652 0b0100_0000_0010_1110 => format!("ldc r{}, vbr", parse_register_high(opcode)), 653 0b0100_0000_0000_0111 => { 654 let source = parse_register_high(opcode); 655 out.memory_read = Some(( 656 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 657 MemoryAccessSize::Longword, 658 )); 659 format!("ldc.l @r{source}+, sr") 660 } 661 0b0100_0000_0001_0111 => { 662 let source = parse_register_high(opcode); 663 out.memory_read = Some(( 664 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 665 MemoryAccessSize::Longword, 666 )); 667 format!("ldc.l @r{source}+, gbr") 668 } 669 0b0100_0000_0010_0111 => { 670 let source = parse_register_high(opcode); 671 out.memory_read = Some(( 672 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 673 MemoryAccessSize::Longword, 674 )); 675 format!("ldc.l @r{source}+, vbr") 676 } 677 0b0100_0000_0000_1010 => format!("lds r{}, mach", parse_register_high(opcode)), 678 0b0100_0000_0001_1010 => format!("lds r{}, macl", parse_register_high(opcode)), 679 0b0100_0000_0010_1010 => format!("lds r{}, pr", parse_register_high(opcode)), 680 0b0100_0000_0000_0110 => { 681 let source = parse_register_high(opcode); 682 out.memory_read = Some(( 683 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 684 MemoryAccessSize::Longword, 685 )); 686 format!("lds.l @r{source}+, mach") 687 } 688 0b0100_0000_0001_0110 => { 689 let source = parse_register_high(opcode); 690 out.memory_read = Some(( 691 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 692 MemoryAccessSize::Longword, 693 )); 694 format!("lds.l @r{source}+, macl") 695 } 696 0b0100_0000_0010_0110 => { 697 let source = parse_register_high(opcode); 698 out.memory_read = Some(( 699 MemoryAccess::IndirectR { register: source, displacement: Displacement::none() }, 700 MemoryAccessSize::Longword, 701 )); 702 format!("lds.l @r{source}+, pr") 703 } 704 0b0000_0000_0000_0010 => format!("stc sr, r{}", parse_register_high(opcode)), 705 0b0000_0000_0001_0010 => format!("stc gbr, r{}", parse_register_high(opcode)), 706 0b0000_0000_0010_0010 => format!("stc vbr, r{}", parse_register_high(opcode)), 707 0b0100_0000_0000_0011 => { 708 let dest = parse_register_high(opcode); 709 out.memory_write = Some(( 710 MemoryAccess::IndirectRPredecrement { register: dest }, 711 MemoryAccessSize::Longword, 712 )); 713 format!("stc.l sr, @-r{dest}") 714 } 715 0b0100_0000_0001_0011 => { 716 let dest = parse_register_high(opcode); 717 out.memory_write = Some(( 718 MemoryAccess::IndirectRPredecrement { register: dest }, 719 MemoryAccessSize::Longword, 720 )); 721 format!("stc.l gbr, @-r{dest}") 722 } 723 0b0100_0000_0010_0011 => { 724 let dest = parse_register_high(opcode); 725 out.memory_write = Some(( 726 MemoryAccess::IndirectRPredecrement { register: dest }, 727 MemoryAccessSize::Longword, 728 )); 729 format!("stc.l vbr, @-r{dest}") 730 } 731 0b0000_0000_0000_1010 => format!("sts mach, r{}", parse_register_high(opcode)), 732 0b0000_0000_0001_1010 => format!("sts macl, r{}", parse_register_high(opcode)), 733 0b0000_0000_0010_1010 => format!("sts pr, r{}", parse_register_high(opcode)), 734 0b0100_0000_0000_0010 => { 735 let dest = parse_register_high(opcode); 736 out.memory_write = Some(( 737 MemoryAccess::IndirectRPredecrement { register: dest }, 738 MemoryAccessSize::Longword, 739 )); 740 format!("sts.l mach, @-r{dest}") 741 } 742 0b0100_0000_0001_0010 => { 743 let dest = parse_register_high(opcode); 744 out.memory_write = Some(( 745 MemoryAccess::IndirectRPredecrement { register: dest }, 746 MemoryAccessSize::Longword, 747 )); 748 format!("sts.l macl, @-r{dest}") 749 } 750 0b0100_0000_0010_0010 => { 751 let dest = parse_register_high(opcode); 752 out.memory_write = Some(( 753 MemoryAccess::IndirectRPredecrement { register: dest }, 754 MemoryAccessSize::Longword, 755 )); 756 format!("sts.l pr, @-r{dest}") 757 } 758 _ => decode_xnnn(pc, opcode, out), 759 } 760} 761 762#[inline] 763fn decode_xnnn(pc: u32, opcode: u16, out: &mut DisassembledInstruction) -> String { 764 match opcode & 0b1111_0000_0000_0000 { 765 0b1110_0000_0000_0000 => { 766 format!("mov.b #{}, r{}", parse_signed_immediate(opcode), parse_register_high(opcode)) 767 } 768 0b1001_0000_0000_0000 => { 769 let displacement: u32 = parse_8bit_displacement(opcode).into(); 770 out.memory_read = Some(( 771 MemoryAccess::PcRelative { 772 pc, 773 displacement: Displacement::Immediate(displacement), 774 }, 775 MemoryAccessSize::Word, 776 )); 777 format!("mov.w @({},pc), r{}", displacement, parse_register_high(opcode)) 778 } 779 0b1101_0000_0000_0000 => { 780 let displacement: u32 = parse_8bit_displacement(opcode).into(); 781 out.memory_read = Some(( 782 MemoryAccess::PcRelative { 783 pc, 784 displacement: Displacement::Immediate(displacement), 785 }, 786 MemoryAccessSize::Longword, 787 )); 788 format!( 789 "mov.l @({},pc), r{}", 790 parse_8bit_displacement(opcode), 791 parse_register_high(opcode) 792 ) 793 } 794 0b0001_0000_0000_0000 => { 795 let displacement: u32 = parse_4bit_displacement(opcode).into(); 796 let dest = parse_register_high(opcode); 797 out.memory_write = Some(( 798 MemoryAccess::IndirectR { 799 register: dest, 800 displacement: Displacement::Immediate(displacement), 801 }, 802 MemoryAccessSize::Longword, 803 )); 804 format!("mov.l r{}, @({},r{})", parse_register_low(opcode), displacement, dest) 805 } 806 0b0101_0000_0000_0000 => { 807 let displacement: u32 = parse_4bit_displacement(opcode).into(); 808 let source = parse_register_high(opcode); 809 out.memory_read = Some(( 810 MemoryAccess::IndirectR { 811 register: source, 812 displacement: Displacement::Immediate(displacement), 813 }, 814 MemoryAccessSize::Longword, 815 )); 816 format!("mov.l @({},r{}), r{}", displacement, source, parse_register_high(opcode)) 817 } 818 0b0111_0000_0000_0000 => { 819 format!("add #{}, r{}", parse_signed_immediate(opcode), parse_register_high(opcode)) 820 } 821 0b1010_0000_0000_0000 => { 822 format!("bra {}", branch_destination(pc, parse_12bit_displacement(opcode) as u32)) 823 } 824 0b1011_0000_0000_0000 => { 825 format!("bsr {}", branch_destination(pc, parse_12bit_displacement(opcode) as u32)) 826 } 827 _ => "illegal".into(), 828 } 829} 830 831#[inline] 832fn parse_4bit_displacement(opcode: u16) -> u16 { 833 opcode & 0xF 834} 835 836#[inline] 837fn parse_8bit_displacement(opcode: u16) -> u16 { 838 opcode & 0xFF 839} 840 841#[inline] 842fn parse_12bit_displacement(opcode: u16) -> i32 { 843 (((opcode as i16) << 4) >> 4).into() 844} 845 846#[inline] 847fn parse_signed_immediate(opcode: u16) -> i8 { 848 opcode as i8 849} 850 851#[inline] 852fn parse_unsigned_immediate(opcode: u16) -> u8 { 853 opcode as u8 854} 855 856#[inline] 857fn parse_register_low(opcode: u16) -> u16 { 858 (opcode >> 4) & 0xF 859} 860 861#[inline] 862fn parse_register_high(opcode: u16) -> u16 { 863 (opcode >> 8) & 0xF 864} 865 866#[inline] 867fn branch_destination(pc: u32, displacement: u32) -> String { 868 let address = pc.wrapping_add(4).wrapping_add(displacement << 1); 869 format!("${address:08X}") 870}