m68000/
assembler.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! Dynamically assemble M68000 instructions.
6//!
7//! The fields are as described in the M68000 Programming Reference Manual, left (high order bits) to right (low order bits).
8//! Refer to it to know which values are valid for the instructions.
9//! If a bad parameter is send to an assembler function, it panics.
10//!
11//! The shift/rotate instructions are regrouped by their destination location and not by their shift/rotate direction.
12//! So [asm] is the arithmetic shift with the data in memory, and [asr] is the arithmetic shift with data in register.
13//! The direction is specified as a parameter in these functions.
14
15#![allow(clippy::unusual_byte_groupings)]
16
17use crate::addressing_modes::AddressingMode;
18use crate::instruction::{Direction, Size};
19
20/// Conditions for the conditional instructions.
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub enum Condition {
23    /// True.
24    T,
25    /// False.
26    F,
27    /// High.
28    HI,
29    /// Lower or Same.
30    LS,
31    /// Carry Clear.
32    CC,
33    /// Carry Set.
34    CS,
35    /// Not Equal.
36    NE,
37    /// Equal.
38    EQ,
39    /// Overflow Clear.
40    VC,
41    /// Overflow Set.
42    VS,
43    /// Plus.
44    PL,
45    /// Minus.
46    MI,
47    /// Greater or Equal.
48    GE,
49    /// Less Than.
50    LT,
51    /// Greater Than.
52    GT,
53    /// Less or Equal.
54    LE,
55}
56
57/// Modes 2, 5, 6 and 7.
58const MODES_2567: [u8; 4] = [2, 5, 6, 7];
59/// Modes 2, 3, 4, 5, 6 and 7.
60const MODES_234567: [u8; 6] = [2, 3, 4, 5, 6, 7];
61/// Modes 0, 2, 3, 4, 5, 6 and 7.
62const MODES_0234567: [u8; 7] = [0, 2, 3, 4, 5, 6, 7];
63/// Modes 0, 1, 2, 3, 4, 5, 6 and 7.
64const MODES_01234567: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
65
66/// ADDI, ANDI, CMPI, EORI, ORI, SUBI
67fn size_effective_address_immediate(bits8_15: u8, size: Size, am: AddressingMode, mut imm: u32) -> Vec<u16> {
68    let mut vec = Vec::new();
69
70    let (eafield, eaext) = am.assemble(size.is_long());
71    let opcode = (bits8_15 as u16) << 8
72               | Into::<u16>::into(size) << 6
73               | eafield;
74    vec.push(opcode);
75
76    if size.is_long() {
77        vec.push((imm >> 16) as u16);
78    } else if size.is_byte() {
79        imm &= 0x0000_00FF;
80    }
81    vec.push(imm as u16);
82    vec.extend(eaext.iter());
83
84    vec
85}
86
87/// static BCHG, BCLR, BSET, BTST
88fn effective_address_count(bits6_15: u16, am: AddressingMode, count: u8) -> Vec<u16> {
89    let mut vec = Vec::new();
90
91    let (eafield, eaext) = am.assemble(false);
92    let opcode = (bits6_15 & 0x3FF) << 6
93               | eafield;
94    vec.push(opcode);
95    vec.push(count as u16);
96    vec.extend(eaext.iter());
97
98    vec
99}
100
101/// JMP, JSR, MOVE (f) SR CCR, NBCD, PEA, TAS
102fn effective_address(bits6_15: u16, am: AddressingMode) -> Vec<u16> {
103    let mut vec = Vec::new();
104
105    let (eafield, eaext) = am.assemble(false);
106    let opcode = (bits6_15 & 0x3FF) << 6
107               | eafield;
108    vec.push(opcode);
109    vec.extend(eaext.iter());
110
111    vec
112}
113
114/// CLR, NEG, NEGX, NOT, TST
115fn size_effective_address(bits8_15: u8, size: Size, am: AddressingMode) -> Vec<u16> {
116    let mut vec = Vec::new();
117
118    let (eafield, eaext) = am.assemble(size.is_long());
119    let opcode = (bits8_15 as u16) << 8
120               | Into::<u16>::into(size) << 6
121               | eafield;
122    vec.push(opcode);
123    vec.extend(eaext.iter());
124
125    vec
126}
127
128/// dynamic BCHG, BCLR, BSET, BTST, CHK, DIVS, DIVU, LEA, MULS, MULU
129fn register_effective_address(bits12_15: u16, reg: u16, bits6_8: u16, am: AddressingMode) -> Vec<u16> {
130    let mut vec = Vec::new();
131
132    let (eafield, eaext) = am.assemble(false);
133    let opcode = (bits12_15 & 0xF) << 12
134               | (reg & 7) << 9
135               | (bits6_8 & 7) << 6
136               | eafield;
137    vec.push(opcode);
138    vec.extend(eaext.iter());
139
140    vec
141}
142
143/// MOVE, MOVEA
144fn size_effective_address_effective_address(size: Size, dst: AddressingMode, src: AddressingMode) -> Vec<u16> {
145    let mut vec = Vec::new();
146
147    let src = src.assemble(size.is_long());
148    let dst = dst.assemble_move_dst();
149    let opcode = size.into_move() << 12 | dst.0 | src.0;
150
151    vec.push(opcode);
152    vec.extend(src.1.iter());
153    vec.extend(dst.1.iter());
154
155    vec
156}
157
158/// SWAP, UNLK
159fn register(bits3_15: u16, reg: u8) -> u16 {
160    bits3_15 << 3 | reg as u16 & 7
161}
162
163/// ADDQ, SUBQ
164fn data_size_effective_address(data: u8, bit8: u16, size: Size, am: AddressingMode) -> Vec<u16> {
165    let mut vec = Vec::new();
166
167    let (eafield, eaext) = am.assemble(size.is_long());
168    let opcode = 0b0101 << 12
169               | (data as u16 & 7) << 9
170               | (bit8 & 1) << 8
171               | Into::<u16>::into(size) << 6
172               | eafield;
173    vec.push(opcode);
174    vec.extend(eaext.iter());
175
176    vec
177}
178
179/// Bcc, BRA, BSR
180///
181/// If the displacement fits in an i8 and is not 0, 1 opcode is used, otherwise 2.
182fn condition_displacement(cond: Condition, disp: i16) -> Vec<u16> {
183    let mut vec = Vec::new();
184
185    let mut opcode = 0b0110 << 12 | (cond as u16) << 8;
186
187    if disp < i8::MIN as i16 || disp > i8::MAX as i16 || disp == 0 {
188        vec.push(opcode);
189        vec.push(disp as u16);
190    } else {
191        opcode |= disp as u8 as u16;
192        vec.push(opcode);
193    }
194
195    vec
196}
197
198/// ADD, AND, CMP, EOR, OR, SUB
199///
200/// [Direction::DstReg] or [Direction::DstEa].
201fn register_direction_size_effective_address(bits12_15: u16, reg: u8, dir: Direction, size: Size, am: AddressingMode) -> Vec<u16> {
202    let mut vec = Vec::new();
203
204    let (eafield, eaext) = am.assemble(size.is_long());
205    let opcode = bits12_15 << 12
206               | (reg as u16) << 9
207               | if dir == Direction::DstEa { 1 } else { 0 } << 8
208               | Into::<u16>::into(size) << 6
209               | eafield;
210    vec.push(opcode);
211    vec.extend(eaext.iter());
212
213    vec
214}
215
216/// ADDA, CMPA, SUBA
217fn register_size_effective_address(bits12_15: u16, reg: u8, size: Size, am: AddressingMode) -> Vec<u16> {
218    let mut vec = Vec::new();
219
220    let (eafield, eaext) = am.assemble(size.is_long());
221    let opcode = bits12_15 << 12
222               | (reg as u16 & 7) << 9
223               | size.into_bit() << 8
224               | 0b11 << 6
225               | eafield;
226    vec.push(opcode);
227    vec.extend(eaext.iter());
228
229    vec
230}
231
232/// ABCD, ADDX, SBCD, SUBX
233///
234/// [Direction::RegisterToRegister] or [Direction::MemoryToMemory].
235fn register_size_mode_register(bits12_15: u16, dst: u8, size: Size, bits4_5: u16, mode: Direction, src: u8) -> u16 {
236    let mut opcode = (bits12_15 & 0xF) << 12
237                   | (dst as u16 & 7) << 9
238                   | 1 << 8
239                   | Into::<u16>::into(size) << 6
240                   | (bits4_5 & 3) << 4
241                   | src as u16 & 7;
242    if mode == Direction::MemoryToMemory {
243        opcode |= 0x0008;
244    }
245
246    opcode
247}
248
249/// ASm, LSm, ROm, ROXm
250fn direction_effective_address(bits9_15: u16, dir: Direction, bits6_7: u16, am: AddressingMode) -> Vec<u16> {
251    let mut vec = Vec::new();
252
253    let (eafield, eaext) = am.assemble(false);
254    let mut opcode = (bits9_15 & 0x7F) << 9
255                   | (bits6_7 & 3) << 6
256                   | eafield;
257    if dir == Direction::Left {
258        opcode |= 0x0100;
259    }
260    vec.push(opcode);
261    vec.extend(eaext.iter());
262
263    vec
264}
265
266/// ASr, LSr, ROr, ROXr
267fn rotation_direction_size_mode_register(bits12_15: u16, count_reg: u16, dir: Direction, size: Size, ir: u16, bits3_4: u16, reg: u16) -> u16 {
268    let mut opcode = (bits12_15 & 0xF) << 12
269                   | (count_reg & 7) << 9
270                   | Into::<u16>::into(size) << 6
271                   | (ir & 1) << 5
272                   | (bits3_4 & 3) << 3
273                   | reg & 7;
274    if dir == Direction::Left {
275        opcode |= 0x0100;
276    }
277
278    opcode
279}
280
281/// `mode` must be [Direction::RegisterToRegister] or [Direction::MemoryToMemory].
282pub fn abcd(dst: u8, mode: Direction, src: u8) -> u16 {
283    assert!(dst <= 7, "Invalid destination register number {}.", dst);
284    assert!(mode == Direction::RegisterToRegister || mode == Direction::MemoryToMemory, "Invalid mode.");
285    assert!(src <= 7, "Invalid source register number {}.", dst);
286    register_size_mode_register(0b1100, dst, Size::Byte, 0, mode, src)
287}
288
289/// `dir` must be [Direction::DstReg] or [Direction::DstEa].
290pub fn add(reg: u8, dir: Direction, size: Size, am: AddressingMode) -> Vec<u16> {
291    assert!(reg <= 7, "Invalid register.");
292    assert!(dir == Direction::DstEa || dir == Direction::DstReg, "Invalid direction.");
293    if dir == Direction::DstEa {
294        assert!(am.verify(&MODES_234567, &[0, 1]), "Invalid addressing mode.");
295    } else {
296        assert!(!(am.is_ard() && size.is_byte()), "Byte size cannot be used with Address Register Direct source operand.");
297        assert!(am.verify(&MODES_01234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode.");
298    }
299    register_direction_size_effective_address(0b1101, reg, dir, size, am)
300}
301
302pub fn adda(reg: u8, size: Size, am: AddressingMode) -> Vec<u16> {
303    assert!(reg <= 7, "Invalid register.");
304    assert!(!size.is_byte(), "ADDA cannot be byte sized.");
305    register_size_effective_address(0b1101, reg, size, am)
306}
307
308pub fn addi(size: Size, am: AddressingMode, imm: u32) -> Vec<u16> {
309    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in ADDI assembler");
310    size_effective_address_immediate(0b0000_0110, size, am, imm)
311}
312
313/// `data` must be 1 to 8.
314pub fn addq(data: u8, size: Size, am: AddressingMode) -> Vec<u16> {
315    assert!(am.verify(&MODES_01234567, &[0, 1]), "Invalid addressing mode.");
316    assert!(!(am.is_ard() && size.is_byte()), "Byte size cannot be used with Address Register Direct destination operand.");
317    assert!(data >= 1 && data <= 8, "Invalid data.");
318    let data = if data == 8 { 0 } else { data };
319    data_size_effective_address(data, 0, size, am)
320}
321
322/// `mode` must be [Direction::RegisterToRegister] or [Direction::MemoryToMemory].
323pub fn addx(dst: u8, size: Size, mode: Direction, src: u8) -> u16 {
324    assert!(dst <= 7, "Invalid destination register number {}.", dst);
325    assert!(mode == Direction::RegisterToRegister || mode == Direction::MemoryToMemory, "Invalid mode.");
326    assert!(src <= 7, "Invalid source register number {}.", dst);
327    register_size_mode_register(0b1101, dst, size, 0, mode, src)
328}
329
330/// `dir` must be [Direction::DstReg] or [Direction::DstEa].
331pub fn and(reg: u8, dir: Direction, size: Size, am: AddressingMode) -> Vec<u16> {
332    assert!(reg <= 7, "Invalid register.");
333    assert!(dir == Direction::DstEa || dir == Direction::DstReg, "Invalid direction.");
334    if dir == Direction::DstEa {
335        assert!(am.verify(&MODES_234567, &[0, 1]), "Invalid addressing mode.");
336    } else {
337        assert!(am.verify(&MODES_0234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode.");
338    }
339    register_direction_size_effective_address(0b1100, reg, dir, size, am)
340}
341
342pub fn andi(size: Size, am: AddressingMode, imm: u32) -> Vec<u16> {
343    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in ANDI assembler");
344    size_effective_address_immediate(0b0000_0010, size, am, imm)
345}
346
347pub fn andiccr(imm: u16) -> [u16; 2] {
348    [0x023C, imm & 0x00FF]
349}
350
351pub fn andisr(imm: u16) -> [u16; 2] {
352    [0x027C, imm]
353}
354
355/// Arithmetic Shift in memory (BYTE size only). `dir` must be [Direction::Left] or [Direction::Right].
356pub fn asm(dir: Direction, am: AddressingMode) -> Vec<u16> {
357    assert!(dir == Direction::Left || dir == Direction::Right, "Invalid direction field in ASm assembler: expected left or right, got {:?}", dir);
358    assert!(am.verify(&MODES_234567, &[0, 1]), "Invalid addressing mode field in ASm assembler");
359    direction_effective_address(0b1110_000, dir, 0b11, am)
360}
361
362/// Arithmetic Shift in register. `dir` must be [Direction::Left] or [Direction::Right].
363pub fn asr(count_reg: u16, dir: Direction, size: Size, reg_shift: bool, reg: u16) -> u16 {
364    assert!(count_reg <= 7, "Invalid count/register field in ASr assembler: expected 0 to 7, got {}", count_reg);
365    assert!(dir == Direction::Left || dir == Direction::Right, "Invalid direction field in ASr assembler: expected left or right, got {:?}", dir);
366    assert!(reg <= 7, "Invalid register field in ASr assembler: expected 0 to 7, got {}", reg);
367    rotation_direction_size_mode_register(0b1110, count_reg, dir, size, reg_shift as u16, 0b00, reg)
368}
369
370/// If the displacement fits in an i8 and is not 0, 1 opcode is used, otherwise 2.
371pub fn bcc(cond: Condition, disp: i16) -> Vec<u16> {
372    assert!(cond != Condition::T && cond != Condition::F, "Invalid condition.");
373    condition_displacement(cond, disp)
374}
375
376pub fn bchg_dynamic(reg: u8, am: AddressingMode) -> Vec<u16> {
377    assert!(reg <= 7, "Invalid register field in BCHG dynamic assembler: expected 0 to 7, got {}", reg);
378    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in BCHG dynamic assembler");
379    register_effective_address(0b0000, reg as u16, 0b101, am)
380}
381
382pub fn bchg_static(am: AddressingMode, count: u8) -> Vec<u16> {
383    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in BCHG static assembler");
384    effective_address_count(0b0000_1000_01, am, count)
385}
386
387pub fn bclr_dynamic(reg: u8, am: AddressingMode) -> Vec<u16> {
388    assert!(reg <= 7, "Invalid register field in BCLR dynamic assembler: expected 0 to 7, got {}", reg);
389    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in BCLR dynamic assembler");
390    register_effective_address(0b0000, reg as u16, 0b110, am)
391}
392
393pub fn bclr_static(am: AddressingMode, count: u8) -> Vec<u16> {
394    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in BCLR static assembler");
395    effective_address_count(0b0000_1000_10, am, count)
396}
397
398/// If the displacement fits in an i8 and is not 0, 1 opcode is used, otherwise 2.
399pub fn bra(disp: i16) -> Vec<u16> {
400    condition_displacement(Condition::T, disp)
401}
402
403pub fn bset_dynamic(reg: u8, am: AddressingMode) -> Vec<u16> {
404    assert!(reg <= 7, "Invalid register field in BSET dynamic assembler: expected 0 to 7, got {}", reg);
405    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in BSET dynamic assembler");
406    register_effective_address(0b0000, reg as u16, 0b111, am)
407}
408
409pub fn bset_static(am: AddressingMode, count: u8) -> Vec<u16> {
410    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in BSET static assembler");
411    effective_address_count(0b0000_1000_11, am, count)
412}
413
414/// If the displacement fits in an i8 and is not 0, 1 opcode is used, otherwise 2.
415pub fn bsr(disp: i16) -> Vec<u16> {
416    condition_displacement(Condition::F, disp)
417}
418
419pub fn btst_dynamic(reg: u8, am: AddressingMode) -> Vec<u16> {
420    assert!(reg <= 7, "Invalid register field in BTST dynamic assembler: expected 0 to 7, got {}", reg);
421    assert!(am.verify(&MODES_0234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode in BTST dynamic assembler");
422    register_effective_address(0b0000, reg as u16, 0b100, am)
423}
424
425pub fn btst_static(am: AddressingMode, count: u8) -> Vec<u16> {
426    assert!(am.verify(&MODES_0234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode in BTST static assembler");
427    effective_address_count(0b0000_1000_00, am, count)
428}
429
430pub fn chk(reg: u8, am: AddressingMode) -> Vec<u16> {
431    assert!(reg <= 7, "Invalid register field in CHK assembler: expected 0 to 7, got {}", reg);
432    assert!(am.verify(&MODES_0234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode in CHK assembler");
433    register_effective_address(0b0100, reg as u16, 0b110, am)
434}
435
436pub fn clr(size: Size, am: AddressingMode) -> Vec<u16> {
437    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in CLR assembler");
438    size_effective_address(0b0100_0010, size, am)
439}
440
441pub fn cmp(reg: u8, size: Size, am: AddressingMode) -> Vec<u16> {
442    assert!(reg <= 7, "Invalid register.");
443    assert!(!(am.is_ard() && size.is_byte()), "Byte size cannot be used with Address Register Direct source operand.");
444    assert!(am.verify(&MODES_01234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode.");
445    register_direction_size_effective_address(0b1011, reg, Direction::DstReg, size, am)
446}
447
448pub fn cmpa(reg: u8, size: Size, am: AddressingMode) -> Vec<u16> {
449    assert!(reg <= 7, "Invalid register.");
450    assert!(!size.is_byte(), "CMPA cannot be byte sized.");
451    register_size_effective_address(0b1011, reg, size, am)
452}
453
454pub fn cmpi(size: Size, am: AddressingMode, imm: u32) -> Vec<u16> {
455    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in CMPI assembler");
456    size_effective_address_immediate(0b0000_1100, size, am, imm)
457}
458
459pub fn cmpm(ax: u8, size: Size, ay: u8) -> u16 {
460    assert!(ax <= 7, "Invalid destination register.");
461    assert!(ay <= 7, "Invalid source register.");
462    0b1011_0001 << 8 | (ax as u16 & 7) << 9 | Into::<u16>::into(size) << 6 | 0b001 << 3 | ay as u16 & 7
463}
464
465pub fn dbcc(cond: Condition, reg: u8, disp: i16) -> [u16; 2] {
466    assert!(reg <= 7, "Invalid register.");
467    [0b0101 << 12 | (cond as u16) << 8 | 0b1100_1 << 3 | reg as u16 & 7, disp as u16]
468}
469
470pub fn divs(reg: u8, am: AddressingMode) -> Vec<u16> {
471    assert!(reg <= 7, "Invalid register field in DIVS assembler: expected 0 to 7, got {}", reg);
472    assert!(am.verify(&MODES_0234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode in DIVS assembler");
473    register_effective_address(0b1000, reg as u16, 0b111, am)
474}
475
476pub fn divu(reg: u8, am: AddressingMode) -> Vec<u16> {
477    assert!(reg <= 7, "Invalid register field in DIVU assembler: expected 0 to 7, got {}", reg);
478    assert!(am.verify(&MODES_0234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode in DIVU assembler");
479    register_effective_address(0b1000, reg as u16, 0b011, am)
480}
481
482pub fn eor(reg: u8, size: Size, am: AddressingMode) -> Vec<u16> {
483    assert!(reg <= 7, "Invalid register.");
484    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode.");
485    register_direction_size_effective_address(0b1011, reg, Direction::DstEa, size, am)
486}
487
488pub fn eori(size: Size, am: AddressingMode, imm: u32) -> Vec<u16> {
489    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in EORI assembler");
490    size_effective_address_immediate(0b0000_1010, size, am, imm)
491}
492
493pub fn eoriccr(imm: u16) -> [u16; 2] {
494    [0x0A3C, imm & 0x00FF]
495}
496
497pub fn eorisr(imm: u16) -> [u16; 2] {
498    [0x0A7C, imm]
499}
500
501/// `dir` must be [Direction::ExchangeData], [Direction::ExchangeAddress] or [Direction::ExchangeDataAddress].
502pub fn exg(rx: u8, dir: Direction, ry: u8) -> u16 {
503    assert!(dir == Direction::ExchangeData || dir == Direction::ExchangeAddress || dir == Direction::ExchangeDataAddress, "Invalid operation");
504    assert!(rx <= 7, "Invalid Rx register.");
505    assert!(ry <= 7, "Invalid Ry register.");
506    let opmode = if dir == Direction::ExchangeData {
507        0b01000
508    } else if dir == Direction::ExchangeAddress {
509        0b01001
510    } else {
511        0b10001
512    };
513    0b1100_0001 << 8 | (rx as u16) << 9 | opmode << 3 | ry as u16 & 7
514}
515
516/// `word_to_long` is true for word to long sign extension, false for byte to word sign extension.
517pub fn ext(word_to_long: bool, reg: u8) -> u16 {
518    assert!(reg <= 7, "Invalid register.");
519    0b0100_1000_1 << 7 | (word_to_long as u16) << 6 | reg as u16 & 7
520}
521
522pub fn illegal() -> u16 {
523    0x4AFC
524}
525
526pub fn jmp(am: AddressingMode) -> Vec<u16> {
527    assert!(am.verify(&MODES_2567, &[0, 1, 2, 3]), "Invalid addressing mode in JMP assembler");
528    effective_address(0b0100_1110_11, am)
529}
530
531pub fn jsr(am: AddressingMode) -> Vec<u16> {
532    assert!(am.verify(&MODES_2567, &[0, 1, 2, 3]), "Invalid addressing mode in JSR assembler");
533    effective_address(0b0100_1110_10, am)
534}
535
536pub fn lea(reg: u8, am: AddressingMode) -> Vec<u16> {
537    assert!(reg <= 7, "Invalid register field in LEA assembler: expected 0 to 7, got {}", reg);
538    assert!(am.verify(&MODES_2567, &[0, 1, 2, 3]), "Invalid addressing mode in LEA assembler");
539    register_effective_address(0b0100, reg as u16, 0b111, am)
540}
541
542pub fn link(reg: u8, disp: i16) -> [u16; 2] {
543    assert!(reg <= 7, "Invalid register.");
544    [0b0100_1110_0101_0 << 3 | reg as u16 & 7, disp as u16]
545}
546
547/// Logical Shift in memory (BYTE size only). `dir` must be [Direction::Left] or [Direction::Right].
548pub fn lsm(dir: Direction, am: AddressingMode) -> Vec<u16> {
549    assert!(dir == Direction::Left || dir == Direction::Right, "Invalid direction field in LSm assembler: expected left or right, got {:?}", dir);
550    assert!(am.verify(&MODES_234567, &[0, 1]), "Invalid addressing mode field in LSm assembler");
551    direction_effective_address(0b1110_001, dir, 0b11, am)
552}
553
554/// Logical Shift in register. `dir` must be [Direction::Left] or [Direction::Right].
555pub fn lsr(count_reg: u16, dir: Direction, size: Size, reg_shift: bool, reg: u16) -> u16 {
556    assert!(count_reg <= 7, "Invalid count/register field in LSr assembler: expected 0 to 7, got {}", count_reg);
557    assert!(dir == Direction::Left || dir == Direction::Right, "Invalid direction field in LSr assembler: expected left or right, got {:?}", dir);
558    assert!(reg <= 7, "Invalid register field in LSr assembler: expected 0 to 7, got {}", reg);
559    rotation_direction_size_mode_register(0b1110, count_reg, dir, size, reg_shift as u16, 0b01, reg)
560}
561
562pub fn r#move(size: Size, dst: AddressingMode, src: AddressingMode) -> Vec<u16> {
563    assert!(dst.verify(&MODES_0234567, &[0, 1]), "Invalid destination addressing mode.");
564    assert!(!(src.is_ard() && size.is_byte()), "Byte size cannot be used with Address Register Direct source operand.");
565    size_effective_address_effective_address(size, dst, src)
566}
567
568pub fn movea(size: Size, dst_reg: u8, src: AddressingMode) -> Vec<u16> {
569    assert!(dst_reg <= 7, "Invalid address register.");
570    assert!(size != Size::Byte, "MOVEA cannot be byte sized.");
571    size_effective_address_effective_address(size, AddressingMode::Ard(dst_reg), src)
572}
573
574pub fn moveccr(am: AddressingMode) -> Vec<u16> {
575    assert!(am.verify(&MODES_0234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode in MOVE to CCR assembler");
576    effective_address(0b0100_0100_11, am)
577}
578
579pub fn movefsr(am: AddressingMode) -> Vec<u16> {
580    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in MOVE from SR assembler");
581    effective_address(0b0100_0000_11, am)
582}
583
584pub fn movesr(am: AddressingMode) -> Vec<u16> {
585    assert!(am.verify(&MODES_0234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode in MOVE to SR assembler");
586    effective_address(0b0100_0110_11, am)
587}
588
589/// `dir` must be [Direction::UspToRegister] or [Direction::RegisterToUsp].
590pub fn moveusp(dir: Direction, reg: u8) -> u16 {
591    assert!(dir == Direction::UspToRegister || dir == Direction::RegisterToUsp, "Invalid direction.");
592    assert!(reg <= 7, "Invalid register");
593    let d = if dir == Direction::UspToRegister { 1 } else { 0 };
594    0b0100_1110_0110 << 4 | d << 3 | reg as u16 & 7
595}
596
597/// `dir` must be [Direction::RegisterToMemory] or [Direction::MemoryToRegister]. `mask` is the raw mask list.
598pub fn movem(dir: Direction, size: Size, am: AddressingMode, mask: u16) -> Vec<u16> {
599    assert!(dir == Direction::RegisterToMemory || dir == Direction::MemoryToRegister, "Invalid direction.");
600    assert!(!size.is_byte(), "Invalid byte size for MOVEM.");
601    let d = if dir == Direction::MemoryToRegister {
602        assert!(am.verify(&[2, 3, 5, 6, 7], &[0, 1, 2, 3]), "Invalid addressing mode.");
603        1
604    } else {
605        assert!(am.verify(&[2, 4, 5, 6, 7], &[0, 1]), "Invalid addressing mode.");
606        0
607    };
608
609    let mut vec = Vec::new();
610
611    let (eafield, eaext) = am.assemble(size.is_long());
612    let opcode = 0b0100_1 << 11
613               | d << 10
614               | 0b001 << 7
615               | size.into_bit() << 6
616               | eafield;
617
618    vec.push(opcode);
619    vec.push(mask);
620    vec.extend(eaext.iter());
621
622    vec
623}
624
625/// `dir` must be [Direction::MemoryToRegister] or [Direction::RegisterToMemory].
626pub fn movep(data_reg: u8, dir: Direction, size: Size, addr_reg: u8, disp: i16) -> [u16; 2] {
627    assert!(data_reg <= 7, "Invalid data register.");
628    assert!(dir == Direction::RegisterToMemory || dir == Direction::MemoryToRegister, "Invalid direction.");
629    assert!(!size.is_byte(), "Invalid byte size for MOVEP.");
630    assert!(addr_reg <= 7, "Invalid address register.");
631
632    let mut opcode = (data_reg as u16 & 7) << 9
633                   | 0b1_0000_1 << 3
634                   | addr_reg as u16 & 7;
635    if dir == Direction::RegisterToMemory {
636        opcode |= 0x0080;
637    }
638    if size.is_long() {
639        opcode |= 0x0040;
640    }
641    [opcode, disp as u16]
642}
643
644pub fn moveq(reg: u8, data: i8) -> u16 {
645    assert!(reg <= 7, "Invalid register.");
646    0b0111 << 12 | (reg as u16) << 9 | data as u8 as u16
647}
648
649pub fn muls(reg: u8, am: AddressingMode) -> Vec<u16> {
650    assert!(reg <= 7, "Invalid register field in MULS assembler: expected 0 to 7, got {}", reg);
651    assert!(am.verify(&MODES_0234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode in MULS assembler");
652    register_effective_address(0b1100, reg as u16, 0b111, am)
653}
654
655pub fn mulu(reg: u8, am: AddressingMode) -> Vec<u16> {
656    assert!(reg <= 7, "Invalid register field in MULU assembler: expected 0 to 7, got {}", reg);
657    assert!(am.verify(&MODES_0234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode in MULU assembler");
658    register_effective_address(0b1100, reg as u16, 0b011, am)
659}
660
661pub fn nbcd(am: AddressingMode) -> Vec<u16> {
662    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in NBCD assembler");
663    effective_address(0b0100_1000_00, am)
664}
665
666pub fn neg(size: Size, am: AddressingMode) -> Vec<u16> {
667    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in NEG assembler");
668    size_effective_address(0b0100_0100, size, am)
669}
670
671pub fn negx(size: Size, am: AddressingMode) -> Vec<u16> {
672    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in NEGX assembler");
673    size_effective_address(0b0100_0000, size, am)
674}
675
676pub fn nop() -> u16 {
677    0x4E71
678}
679
680pub fn not(size: Size, am: AddressingMode) -> Vec<u16> {
681    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in NOT assembler");
682    size_effective_address(0b0100_0110, size, am)
683}
684
685/// `dir` must be [Direction::DstReg] or [Direction::DstEa].
686pub fn or(reg: u8, dir: Direction, size: Size, am: AddressingMode) -> Vec<u16> {
687    assert!(reg <= 7, "Invalid register.");
688    assert!(dir == Direction::DstEa || dir == Direction::DstReg, "Invalid direction.");
689    if dir == Direction::DstEa {
690        assert!(am.verify(&MODES_234567, &[0, 1]), "Invalid addressing mode.");
691    } else {
692        assert!(am.verify(&MODES_0234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode.");
693    }
694    register_direction_size_effective_address(0b1000, reg, dir, size, am)
695}
696
697pub fn ori(size: Size, am: AddressingMode, imm: u32) -> Vec<u16> {
698    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in ORI assembler");
699    size_effective_address_immediate(0b0000_0000, size, am, imm)
700}
701
702pub fn oriccr(imm: u16) -> [u16; 2] {
703    [0x003C, imm & 0x00FF]
704}
705
706pub fn orisr(imm: u16) -> [u16; 2] {
707    [0x007C, imm]
708}
709
710pub fn pea(am: AddressingMode) -> Vec<u16> {
711    assert!(am.verify(&MODES_2567, &[0, 1, 2, 3]), "Invalid addressing mode in PEA assembler");
712    effective_address(0b0100_1000_01, am)
713}
714
715pub fn reset() -> u16 {
716    0x4E70
717}
718
719/// Rotate in memory (BYTE size only). `dir` must be [Direction::Left] or [Direction::Right].
720pub fn rom(dir: Direction, am: AddressingMode) -> Vec<u16> {
721    assert!(dir == Direction::Left || dir == Direction::Right, "Invalid direction field in ROm assembler: expected left or right, got {:?}", dir);
722    assert!(am.verify(&MODES_234567, &[0, 1]), "Invalid addressing mode field in ROm assembler");
723    direction_effective_address(0b1110_011, dir, 0b11, am)
724}
725
726/// Rotate in register. `dir` must be [Direction::Left] or [Direction::Right].
727pub fn ror(count_reg: u16, dir: Direction, size: Size, reg_shift: bool, reg: u16) -> u16 {
728    assert!(count_reg <= 7, "Invalid count/register field in ROr assembler: expected 0 to 7, got {}", count_reg);
729    assert!(dir == Direction::Left || dir == Direction::Right, "Invalid direction field in ROr assembler: expected left or right, got {:?}", dir);
730    assert!(reg <= 7, "Invalid register field in ROr assembler: expected 0 to 7, got {}", reg);
731    rotation_direction_size_mode_register(0b1110, count_reg, dir, size, reg_shift as u16, 0b11, reg)
732}
733
734/// Rotate with Extend in memory (BYTE size only). `dir` must be [Direction::Left] or [Direction::Right].
735pub fn roxm(dir: Direction, am: AddressingMode) -> Vec<u16> {
736    assert!(dir == Direction::Left || dir == Direction::Right, "Invalid direction field in ROXm assembler: expected left or right, got {:?}", dir);
737    assert!(am.verify(&MODES_234567, &[0, 1]), "Invalid addressing mode field in ROXm assembler");
738    direction_effective_address(0b1110_010, dir, 0b11, am)
739}
740
741/// Rotate with Extend in register. `dir` must be [Direction::Left] or [Direction::Right].
742pub fn roxr(count_reg: u16, dir: Direction, size: Size, reg_shift: bool, reg: u16) -> u16 {
743    assert!(count_reg <= 7, "Invalid count/register field in ROXr assembler: expected 0 to 7, got {}", count_reg);
744    assert!(dir == Direction::Left || dir == Direction::Right, "Invalid direction field in ROXr assembler: expected left or right, got {:?}", dir);
745    assert!(reg <= 7, "Invalid register field in ROXr assembler: expected 0 to 7, got {}", reg);
746    rotation_direction_size_mode_register(0b1110, count_reg, dir, size, reg_shift as u16, 0b10, reg)
747}
748
749pub fn rte() -> u16 {
750    0x4E73
751}
752
753pub fn rtr() -> u16 {
754    0x4E77
755}
756
757pub fn rts() -> u16 {
758    0x4E75
759}
760
761/// `mode` must be [Direction::RegisterToRegister] or [Direction::MemoryToMemory].
762pub fn sbcd(dst: u8, mode: Direction, src: u8) -> u16 {
763    assert!(dst <= 7, "Invalid destination register number {}.", dst);
764    assert!(mode == Direction::RegisterToRegister || mode == Direction::MemoryToMemory, "Invalid mode.");
765    assert!(src <= 7, "Invalid source register number {}.", dst);
766    register_size_mode_register(0b1000, dst, Size::Byte, 0, mode, src)
767}
768
769pub fn scc(cond: Condition, am: AddressingMode) -> Vec<u16> {
770    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode");
771    let mut vec = Vec::new();
772
773    let (eafield, eaext) = am.assemble(false);
774    let opcode = 0b0101 << 12
775               | (cond as u16) << 8
776               | 0b11 << 6
777               | eafield;
778    vec.push(opcode);
779    vec.extend(eaext.iter());
780
781    vec
782}
783
784pub fn stop(sr: u16) -> [u16; 2] {
785    [0x4E72, sr]
786}
787
788/// `dir` must be [Direction::DstReg] or [Direction::DstEa].
789pub fn sub(reg: u8, dir: Direction, size: Size, am: AddressingMode) -> Vec<u16> {
790    assert!(reg <= 7, "Invalid register.");
791    assert!(dir == Direction::DstEa || dir == Direction::DstReg, "Invalid direction.");
792    if dir == Direction::DstEa {
793        assert!(am.verify(&MODES_234567, &[0, 1]), "Invalid addressing mode.");
794    } else {
795        assert!(!(am.is_ard() && size.is_byte()), "Byte size cannot be used with Address Register Direct source operand.");
796        assert!(am.verify(&MODES_01234567, &[0, 1, 2, 3, 4]), "Invalid addressing mode.");
797    }
798    register_direction_size_effective_address(0b1001, reg, dir, size, am)
799}
800
801pub fn suba(reg: u8, size: Size, am: AddressingMode) -> Vec<u16> {
802    assert!(reg <= 7, "Invalid register.");
803    assert!(!size.is_byte(), "SUBA cannot be byte sized.");
804    register_size_effective_address(0b1001, reg, size, am)
805}
806
807pub fn subi(size: Size, am: AddressingMode, imm: u32) -> Vec<u16> {
808    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in SUBI assembler");
809    size_effective_address_immediate(0b0000_0100, size, am, imm)
810}
811
812/// `data` must be 1 to 8.
813pub fn subq(data: u8, size: Size, am: AddressingMode) -> Vec<u16> {
814    assert!(am.verify(&MODES_01234567, &[0, 1]), "Invalid addressing mode.");
815    assert!(!(am.is_ard() && size.is_byte()), "Byte size cannot be used with Address Register Direct destination operand.");
816    assert!(data >= 1 && data <= 8, "Invalid data.");
817    let data = if data == 8 { 0 } else { data };
818    data_size_effective_address(data, 1, size, am)
819}
820
821/// `mode` must be [Direction::RegisterToRegister] or [Direction::MemoryToMemory].
822pub fn subx(dst: u8, size: Size, mode: Direction, src: u8) -> u16 {
823    assert!(dst <= 7, "Invalid destination register number {}.", dst);
824    assert!(mode == Direction::RegisterToRegister || mode == Direction::MemoryToMemory, "Invalid mode.");
825    assert!(src <= 7, "Invalid source register number {}.", dst);
826    register_size_mode_register(0b1001, dst, size, 0, mode, src)
827}
828
829pub fn swap(reg: u8) -> u16 {
830    assert!(reg <= 7, "Invalid register.");
831    register(0b0100_1000_0100_0, reg)
832}
833
834pub fn tas(am: AddressingMode) -> Vec<u16> {
835    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in TAS assembler");
836    effective_address(0b0100_1010_11, am)
837}
838
839pub fn trap(vector: u8) -> u16 {
840    assert!(vector <= 15, "Invalid TRAP vector.");
841    0b0100_1110_0100 << 4 | vector as u16
842}
843
844pub fn trapv() -> u16 {
845    0x4E76
846}
847
848pub fn tst(size: Size, am: AddressingMode) -> Vec<u16> {
849    assert!(am.verify(&MODES_0234567, &[0, 1]), "Invalid addressing mode in TST assembler");
850    size_effective_address(0b0100_1010, size, am)
851}
852
853pub fn unlk(reg: u8) -> u16 {
854    assert!(reg <= 7, "Invalid register.");
855    register(0b0100_1110_0101_1, reg)
856}