charm 0.0.1

ARM assembler & disassembler generated from the ARM exploration tools.
Documentation
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
//! # LDRSB (literal)
//!
//! Load Register Signed Byte (literal) calculates an address from the PC value and an immediate offset, loads a byte from memory, sign-extends it to form a 32-bit word, and writes it to a register. For information about memory accesses see *Memory accesses* .

#![allow(non_snake_case)]
#![allow(unused)]
use crate::error::Result;
use crate::utils::*;
use super::super::formatter::*;
use super::super::instruction::*;
use super::super::operand::*;
use super::super::consts::*;
use super::super::config::*;
use super::super::decoder::*;

// ---------------------------------------------------------------------------
// Iclass IclassLdrsbLT1
// ---------------------------------------------------------------------------

/// Type that represents the IclassLdrsbLT1 instruction class.
pub(crate) struct IclassLdrsbLT1;

impl IclassLdrsbLT1 {
    /// Tries to decode the instruction in `data`.
    pub(crate) fn decode(data: u32, decoder: &mut Decoder) -> Result<Instruction> {
        let U = (data >> 23) & 1;
        let U_post = U;
        let field_19 = (data >> 16) & 15;
        let field_19_post = field_19;
        let Rt = (data >> 12) & 15;
        let Rt_post = Rt;
        let imm12 = (data >> 0) & 4095;
        let imm12_post = imm12;
        let size = (data >> 21) & 3;
        let size_post = size;
        let field_20 = (data >> 20) & 1;
        let field_20_post = field_20;
        let field_28 = (data >> 25) & 15;
        let field_28_post = field_28;
        let field_31 = (data >> 29) & 7;
        let field_31_post = field_31;
        let field_24 = (data >> 24) & 1;
        let field_24_post = field_24;


        return LdrsbLT1::decode(data as u32, decoder);

        unreachable!()
    }
}

/// LDRSB T1 encoding.
///
/// # Encoding
///
/// <table style="font-family: courier, monospace">
///     <tr>
///         <td style="border: none">31</td>
///         <td style="border: none">30</td>
///         <td style="border: none">29</td>
///         <td style="border: none">28</td>
///         <td style="border: none">27</td>
///         <td style="border: none">26</td>
///         <td style="border: none">25</td>
///         <td style="border: none">24</td>
///         <td style="border: none">23</td>
///         <td style="border: none">22</td>
///         <td style="border: none">21</td>
///         <td style="border: none">20</td>
///         <td style="border: none">19</td>
///         <td style="border: none">18</td>
///         <td style="border: none">17</td>
///         <td style="border: none">16</td>
///         <td style="border: none">15</td>
///         <td style="border: none">14</td>
///         <td style="border: none">13</td>
///         <td style="border: none">12</td>
///         <td style="border: none">11</td>
///         <td style="border: none">10</td>
///         <td style="border: none">9</td>
///         <td style="border: none">8</td>
///         <td style="border: none">7</td>
///         <td style="border: none">6</td>
///         <td style="border: none">5</td>
///         <td style="border: none">4</td>
///         <td style="border: none">3</td>
///         <td style="border: none">2</td>
///         <td style="border: none">1</td>
///         <td style="border: none">0</td>
///     </tr>
///     <tr>
///          <td style="text-align: center; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none" colspan="1">1</td>
///          <td style="text-align: center; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none; border-right: none" colspan="1">0</td>
///          <td style="text-align: center; border-left: none" colspan="1">0</td>
///          <td style="text-align: center; border-right: none" colspan="1">1</td>
/// <td style="text-align: center" colspan="1">U</td>
///          <td style="text-align: center; border-right: none" colspan="1">0</td>
///          <td style="text-align: center; border-left: none" colspan="1">0</td>
///          <td style="text-align: center; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none; border-right: none" colspan="1">1</td>
///          <td style="text-align: center; border-left: none" colspan="1">1</td>
///          <td style="text-align: center; border-right: none" colspan="4">!= 1111</td>
/// <td style="text-align: center" colspan="12">imm12</td>
///     </tr>
///     <tr>
/// <td style="text-align: center; border: none" colspan="3"></td>
/// <td style="text-align: center; border: none" colspan="4"></td>
/// <td style="text-align: center; border: none" colspan="1"></td>
/// <td style="text-align: center; border: none" colspan="1"></td>
/// <td style="text-align: center; border: none" colspan="2">size</td>
/// <td style="text-align: center; border: none" colspan="1"></td>
/// <td style="text-align: center; border: none" colspan="4"></td>
/// <td style="text-align: center; border: none" colspan="4">Rt</td>
/// <td style="text-align: center; border: none" colspan="12"></td>
///     </tr>
/// </table>
pub struct LdrsbLT1;

impl LdrsbLT1 {
    /// Returns the instruction mnemonic.
    pub fn mnemonic(instr: &Instruction) -> Mnemonic {
        match instr.encoding {
            Encoding::Alt1 => Mnemonic::LDRSB,
            Encoding::Alt2 => Mnemonic::LDRSB,
            _ => todo!()
        }
    }

    /// Returns the instruction condition information.
    pub fn condition(instr: &Instruction) -> ConditionalInstruction {
        match instr.encoding {
            Encoding::Alt1 => {
                ConditionalInstruction::Condition(0, false, false)
            }
            Encoding::Alt2 => {
                ConditionalInstruction::Condition(0, false, false)
            }
            _ => todo!()
        }
    }

    /// Returns the instruction size.
    pub fn size(instr: &Instruction) -> usize {
        match instr.encoding {
            Encoding::Alt1 =>  4,
            Encoding::Alt2 =>  4,
            _ => todo!()
        }
    }

    /// Decodes the instruction in `data`.
    pub fn decode(data: u32, decoder: &mut Decoder) -> Result<Instruction> {
        let U = (data >> 23) & 1;
        let U_post = U;
        let Rt = (data >> 12) & 15;
        let Rt_post = Rt;
        let imm12 = (data >> 0) & 4095;
        let imm12_post = imm12;
        let imm12_post = (((imm12) as i32) << 20) >> 20;
        let Rt_post = Rt;
        let U_post = U;
        let imm12_post = imm12;

        // Checks if preferred encodings have been configured.
        if let Some(encoding) = decoder.config.instructions.ldrsb_l_t1.encodings {
            match encoding {
                LdrsbLT1Encodings::Alt1 => {
                    // Operand values are computed from the base fields.
                    let op_0 = MnemonicCondition::Al;
                    let Rt_post = Rt;
                    let op_1 = Register::decode(Rt_post)?;
                    let imm12_post = (((imm12) as i32) << 20) >> 20;
                    let op_2 = Label::decode(imm12_post.into());

                    // The instruction is then created from the operands.
                    let mut instr = Instruction::builder_multi(Code::LDRSB_l_T1, Encoding::Alt1)
                        .operand(0, op_0)?
                        .operand(1, op_1)?
                        .operand(2, op_2)?
                        .build();
                    
                    // For encodings using labels, we check if we are decoding instruction blocks,
                    // which requires labels to be tracked.
                    if decoder.block_decoding {
                        // TODO: handle addition
                        // The label target is computed from the value stored in the corresponding operand.
                        let size = 4;
                        let pc = size + match instr.op2().as_label()? {
                            Label::Label(imm) => ((decoder.pc as u64) as i64 + *imm as i64) as u32,
                            _ => unreachable!(),
                        };
                        // The label target is added to the decoder hashset and will be used
                        // to see if labels should be added in the resulting decoded instructions block.
                        decoder.labels.insert(pc);
                        // The operand is also replaced by a named label that references the label
                        // that was added to the hashset.
                        instr.set_op(2, Label::LabelName(pc as u64))?;
                    }
                    
                    return Ok(instr);
                }
                LdrsbLT1Encodings::Alt2 => {
                    // Operand values are computed from the base fields.
                    let op_0 = MnemonicCondition::Al;
                    let Rt_post = Rt;
                    let op_1 = Register::decode(Rt_post)?;
                    let op_2 = Register::PC;
                    let U_post = U;
                    let op_3 = PlusMinus::decode(U_post);
                    let imm12_post = imm12;
                    let op_4 = imm12_post as u32;

                    // The instruction is then created from the operands.
                    let mut instr = Instruction::builder_multi(Code::LDRSB_l_T1, Encoding::Alt2)
                        .operand(0, op_0)?
                        .operand(1, op_1)?
                        .operand(2, op_2)?
                        .operand(3, op_3)?
                        .operand(4, op_4)?
                        .build();
                    
                    return Ok(instr);
                }
            }
        }
        
        // Operand values are computed from the base fields.
        let op_0 = MnemonicCondition::Al;
        let Rt_post = Rt;
        let op_1 = Register::decode(Rt_post)?;
        let imm12_post = (((imm12) as i32) << 20) >> 20;
        let op_2 = Label::decode(imm12_post.into());
        // The instruction is then created from the operands.
        let mut instr = Instruction::builder_multi(Code::LDRSB_l_T1, Encoding::Alt1)
            .operand(0, op_0)?
            .operand(1, op_1)?
            .operand(2, op_2)?
            .build();
        
        // For encodings using labels, we check if we are decoding instruction blocks,
        // which requires labels to be tracked.
        if decoder.block_decoding {
            // TODO: handle addition
            // The label target is computed from the value stored in the corresponding operand.
            let size = 4;
            let pc = size + match instr.op2().as_label()? {
                Label::Label(imm) => ((decoder.pc as u64) as i64 + *imm as i64) as u32,
                _ => unreachable!(),
            };
            // The label target is added to the decoder hashset and will be used
            // to see if labels should be added in the resulting decoded instructions block.
            decoder.labels.insert(pc);
            // The operand is also replaced by a named label that references the label
            // that was added to the hashset.
            instr.set_op(2, Label::LabelName(pc as u64))?;
        }
        
        return Ok(instr);
        
        // Operand values are computed from the base fields.
        let op_0 = MnemonicCondition::Al;
        let Rt_post = Rt;
        let op_1 = Register::decode(Rt_post)?;
        let op_2 = Register::PC;
        let U_post = U;
        let op_3 = PlusMinus::decode(U_post);
        let imm12_post = imm12;
        let op_4 = imm12_post as u32;
        // The instruction is then created from the operands.
        let mut instr = Instruction::builder_multi(Code::LDRSB_l_T1, Encoding::Alt2)
            .operand(0, op_0)?
            .operand(1, op_1)?
            .operand(2, op_2)?
            .operand(3, op_3)?
            .operand(4, op_4)?
            .build();
        
        return Ok(instr);
        
        unreachable!()
    }

    /// Encodes the instruction into `buf`.
    pub fn encode(instr: &Instruction, buf: &mut Vec<u8>) -> Result<usize> {
        match instr.encoding {
            Encoding::Alt1 => {
                // Retrieve all operand values.
                let Rt_pre = instr.op1().as_register()?.encode();
                let imm12_pre = instr.op2().as_label()?.encode()?;

                // Compute all instruction fields from the operand values.
                let Rt = (Rt_pre & 15);
                let imm12_pre = imm12_pre;
                let imm12 = (imm12_pre & 4095);

                // Add all field values to the base instruction encoding.
                let mut instr: u32 = 0b11111001000111110000000000000000;
                instr |= (Rt & 15) << 12;
                instr |= (imm12 & 4095) << 0;

                let instr_1 = (instr & 0xffff) as u16;
                let instr_2 = ((instr >> 16) & 0xffff) as u16;
                buf.extend(instr_2.to_le_bytes());
                buf.extend(instr_1.to_le_bytes());
                return Ok(4);
            }
            Encoding::Alt2 => {
                // Retrieve all operand values.
                let Rt_pre = instr.op1().as_register()?.encode();
                let U_pre = instr.op3().as_plus_minus()?.encode();
                let imm12_pre = instr.op4().as_unsigned_immediate()? as u32;

                // Compute all instruction fields from the operand values.
                let Rt = (Rt_pre & 15);
                let U = (U_pre & 1);
                let imm12_pre = imm12_pre;
                let imm12 = (imm12_pre & 4095);

                // Add all field values to the base instruction encoding.
                let mut instr: u32 = 0b11111001000111110000000000000000;
                instr |= (Rt & 15) << 12;
                instr |= (U & 1) << 23;
                instr |= (imm12 & 4095) << 0;

                let instr_1 = (instr & 0xffff) as u16;
                let instr_2 = ((instr >> 16) & 0xffff) as u16;
                buf.extend(instr_2.to_le_bytes());
                buf.extend(instr_1.to_le_bytes());
                return Ok(4);
            }
            _ => todo!()
        }
        unreachable!()
    }

    /// Encode an instruction part of an instruction block into `buf`.
    pub fn encode_block(instr: &mut Instruction, buf: &mut Vec<u8>, labels: &std::collections::HashMap<u64, u64>) -> Result<usize> {
        match instr.encoding {
            Encoding::Alt1 => {
                if let Label::LabelName(label_name) = instr.op2().as_label()? {
                    let size =4;
                    if let Some(label_pc) = labels.get(label_name) {
                        // TODO: handle addition
                        let pc = *label_pc as i64 - size - instr.pc as i64;
                        instr.set_op(2, Label::Label(pc))?;
                    } else {
                        // TODO: handle addition
                        let pc = *label_name as i64 - size - instr.pc as i64;
                        instr.set_op(2, Label::Label(pc))?;
                    }
                }
                Self::encode(instr, buf)
            }
            Encoding::Alt2 => {
                Self::encode(instr, buf)
            }
            _ => todo!()
        }
    }
    
    /// Verifies that operand #0 is valid.
    pub fn check_op0(instr: &Instruction, op: &Operand) -> Result<()> {
        match instr.encoding {
            Encoding::Alt1 => {
                if let Operand::MnemonicCondition(r) = op {
                    return Ok(())
                }
                todo!()
            }
            Encoding::Alt2 => {
                if let Operand::MnemonicCondition(r) = op {
                    return Ok(())
                }
                todo!()
            }
            _ => todo!()
        }
        unreachable!()
    }
    
    /// Verifies that operand #1 is valid.
    pub fn check_op1(instr: &Instruction, op: &Operand) -> Result<()> {
        match instr.encoding {
            Encoding::Alt1 => {
                
                if let Operand::Register(r) = op {
                    return Ok(())
                }
                todo!()
            }
            Encoding::Alt2 => {
                
                if let Operand::Register(r) = op {
                    return Ok(())
                }
                todo!()
            }
            _ => todo!()
        }
        unreachable!()
    }
    
    /// Verifies that operand #2 is valid.
    pub fn check_op2(instr: &Instruction, op: &Operand) -> Result<()> {
        match instr.encoding {
            Encoding::Alt1 => {
                if let Operand::Label(Label::LabelName(_)) = op {
                    return Ok(())
                }
                if let Operand::Label(Label::Label(i)) = op {
                    if !(-4095..=4095).contains(i) {
                        todo!()
                    }
                    return Ok(())
                }
                todo!()
            }
            Encoding::Alt2 => {
                if let Operand::Register(Register::PC) = op {
                    return Ok(())
                }
                todo!()
            }
            _ => todo!()
        }
        unreachable!()
    }
    
    /// Verifies that operand #3 is valid.
    pub fn check_op3(instr: &Instruction, op: &Operand) -> Result<()> {
        match instr.encoding {
            Encoding::Alt1 => {
                todo!()
            }
            Encoding::Alt2 => {
                if let Operand::PlusMinus(_) = op {
                    return Ok(())
                }
                todo!()
            }
            _ => todo!()
        }
        unreachable!()
    }
    
    /// Verifies that operand #4 is valid.
    pub fn check_op4(instr: &Instruction, op: &Operand) -> Result<()> {
        match instr.encoding {
            Encoding::Alt1 => {
                todo!()
            }
            Encoding::Alt2 => {
                if let Operand::SignedImmediate(i) = op {
                    if *i < 0 || *i > 4095 {
                        todo!()
                    }
                    return Ok(())
                }
                if let Operand::UnsignedImmediate(i) = op {
                    if !(0..=4095).contains(i) {
                        todo!()
                    }
                    return Ok(())
                }
                todo!()
            }
            _ => todo!()
        }
        unreachable!()
    }
    
    /// Verifies that operand #5 is valid.
    pub fn check_op5(instr: &Instruction, op: &Operand) -> Result<()> {
        match instr.encoding {
            Encoding::Alt1 => {
                todo!()
            }
            Encoding::Alt2 => {
                todo!()
            }
            _ => todo!()
        }
        unreachable!()
    }
    
    /// Verifies that operand #6 is valid.
    pub fn check_op6(instr: &Instruction, op: &Operand) -> Result<()> {
        match instr.encoding {
            Encoding::Alt1 => {
                todo!()
            }
            Encoding::Alt2 => {
                todo!()
            }
            _ => todo!()
        }
        unreachable!()
    }

    /// Formats the instruction.
    pub fn format(instr: &Instruction, fmt: &mut impl Formatter, output: &mut impl FormatterOutput, config: &Config) -> Result<()> {
        match instr.encoding {
            Encoding::Alt1 => {
                fmt.format_mnemonic(output, &config.global, &config.instructions.ldrsb_l_t1, &instr)?;
                fmt.format_operand(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, 0)?;
                fmt.format_qualifier(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, FormatterQualifier::Wide, true, false)?;
                fmt.format_punctuation(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, FormatterTextKind::Space)?;
                fmt.format_operand(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, 1)?;
                fmt.format_punctuation(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, FormatterTextKind::Comma)?;
                fmt.format_operand(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, 2)?;
                return Ok(());
            }
            Encoding::Alt2 => {
                fmt.format_mnemonic(output, &config.global, &config.instructions.ldrsb_l_t1, &instr)?;
                fmt.format_operand(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, 0)?;
                fmt.format_qualifier(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, FormatterQualifier::Wide, true, false)?;
                fmt.format_punctuation(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, FormatterTextKind::Space)?;
                fmt.format_operand(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, 1)?;
                fmt.format_punctuation(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, FormatterTextKind::Comma)?;
                fmt.format_punctuation(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, FormatterTextKind::BracketLeft)?;
        fmt.format_operand(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, 2)?;
        fmt.format_punctuation(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, FormatterTextKind::Comma)?;
        fmt.format_punctuation(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, FormatterTextKind::NumSign)?;
        if *instr.op3().as_plus_minus()? == PlusMinus::Minus {
            fmt.format_operand(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, 3)?;
        };
        fmt.format_operand(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, 4)?;
        fmt.format_punctuation(output, &config.global, &config.instructions.ldrsb_l_t1, &instr, FormatterTextKind::BracketRight)?;;
                return Ok(());
            }
            _ => todo!()
        }
        unreachable!()
    }
}

/// Type that represents alias identifiers for [`LdrsbLT1`].
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub enum LdrsbLT1Aliases {
    None,
}

/// Type that represents encoding identifiers for [`LdrsbLT1`].
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub enum LdrsbLT1Encodings {
    Alt1,
    Alt2,
}