Skip to content

Commit 2ca5e75

Browse files
authored
Merge pull request #48 from jjkt/vstmia
VSTM support
2 parents 4e7ca63 + eebf605 commit 2ca5e75

File tree

8 files changed

+276
-4
lines changed

8 files changed

+276
-4
lines changed

zmu_cortex_m/build.rs

+2
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ fn main() -> Result<(), Box<dyn Error>> {
283283
//("111011101.00........101..0.0....": "VDIV"),
284284
//("111011101.10........101....0....": "VFMAS"),
285285
//("111011101.01........101....0....": "VFNMAS"),
286+
("1110110....0........1011.......0", "VSTM_t1"),
287+
("1110110....0........1010........", "VSTM_t2"),
286288
("11101101..01........1011........", "VLDR_t1"),
287289
("11101101..01........1010........", "VLDR_t2"),
288290
("111011010.101101....1011........", "VPUSH_t1"),

zmu_cortex_m/src/core/instruction.rs

+59-2
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,33 @@ pub struct VPushPopParams {
308308
pub imm32: u32,
309309
}
310310

311+
#[allow(missing_docs)]
312+
#[derive(PartialEq, Debug, Copy, Clone)]
313+
pub enum AddressingMode {
314+
IncrementAfter,
315+
DecrementBefore,
316+
}
317+
318+
#[allow(missing_docs)]
319+
#[derive(PartialEq, Debug, Copy, Clone)]
320+
pub struct VStoreMultipleParams32 {
321+
pub mode: AddressingMode,
322+
pub rn: Reg,
323+
pub write_back: bool,
324+
pub list: EnumSet<SingleReg>,
325+
pub imm32: u32,
326+
}
327+
328+
#[allow(missing_docs)]
329+
#[derive(PartialEq, Debug, Copy, Clone)]
330+
pub struct VStoreMultipleParams64 {
331+
pub mode: AddressingMode,
332+
pub rn: Reg,
333+
pub write_back: bool,
334+
pub list: EnumSet<DoubleReg>,
335+
pub imm32: u32,
336+
}
337+
311338
#[allow(missing_docs)]
312339
#[derive(PartialEq, Debug, Copy, Clone)]
313340
pub struct VMovImmParams32 {
@@ -1267,7 +1294,12 @@ pub enum Instruction {
12671294
VPOP {
12681295
params: VPushPopParams,
12691296
},
1270-
// VSTM
1297+
VSTM_T1 {
1298+
params: VStoreMultipleParams64,
1299+
},
1300+
VSTM_T2 {
1301+
params: VStoreMultipleParams32,
1302+
},
12711303

12721304
// --------------------------------------------
12731305
//
@@ -2275,6 +2307,30 @@ impl fmt::Display for Instruction {
22752307
),
22762308
Self::VLDR { params } => write!(f, "vldr {}, {}", params.dd, params.rn),
22772309
Self::VSTR { params } => write!(f, "vstr {}, {}", params.dd, params.rn),
2310+
Self::VSTM_T1 { params } => write!(
2311+
f,
2312+
"vstm{}.64, {}{} {:?}",
2313+
if params.mode == AddressingMode::IncrementAfter {
2314+
"ia"
2315+
} else {
2316+
"db"
2317+
},
2318+
params.rn,
2319+
if params.write_back { "!" } else { "" },
2320+
params.list
2321+
),
2322+
Self::VSTM_T2 { params } => write!(
2323+
f,
2324+
"vstm{}.32, {}{} {:?}",
2325+
if params.mode == AddressingMode::IncrementAfter {
2326+
"ia"
2327+
} else {
2328+
"db"
2329+
},
2330+
params.rn,
2331+
if params.write_back { "!" } else { "" },
2332+
params.list
2333+
),
22782334
Self::VPUSH { params } => write!(
22792335
f,
22802336
"vpush {}",
@@ -2670,7 +2726,8 @@ pub fn instruction_size(instruction: &Instruction) -> usize {
26702726
//VRINTZ, VRINTR
26712727
//VSEL
26722728
//VSQRT
2673-
//VSTM
2729+
Instruction::VSTM_T1 { .. } => 4,
2730+
Instruction::VSTM_T2 { .. } => 4,
26742731
//VSTR
26752732
//VSUB
26762733
Instruction::WFE { thumb32, .. } => isize_t(*thumb32),

zmu_cortex_m/src/decoder/decoder_tests.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::core::instruction::{
2-
BfcParams, BfiParams, CondBranchParams, Imm32Carry, MovtParams, ParamsRegImm32,
2+
AddressingMode, BfcParams, BfiParams, CondBranchParams, Imm32Carry, MovtParams, ParamsRegImm32,
33
Reg2DoubleParams, Reg2FullParams, Reg2ImmCarryParams, Reg2ImmParams, Reg2Params,
44
Reg2RdRmParams, Reg2RnRmParams, Reg2RtRnImm32Params, Reg2ShiftNParams,
55
Reg2ShiftNoSetFlagsParams, Reg2ShiftParams, Reg2UsizeParams, Reg3FullParams, Reg3HighParams,
@@ -3034,3 +3034,22 @@ fn test_decode_vmov_imm() {
30343034
}
30353035
);
30363036
}
3037+
3038+
#[test]
3039+
fn test_decode_vstm_32_ia() {
3040+
//ecee 7a01 vstmia lr!, {s15}
3041+
3042+
match decode_32(0xecee_7a01) {
3043+
Instruction::VSTM_T2 { params } => {
3044+
assert_eq!(params.mode, AddressingMode::IncrementAfter);
3045+
let single_regs: Vec<_> = params.list.iter().collect();
3046+
assert_eq!(vec![SingleReg::S15], single_regs);
3047+
assert_eq!(params.imm32, 4);
3048+
assert_eq!(params.rn, Reg::LR);
3049+
assert!(params.write_back);
3050+
}
3051+
_ => {
3052+
unreachable!();
3053+
}
3054+
}
3055+
}

zmu_cortex_m/src/decoder/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ mod vmov;
120120
mod vpop;
121121
mod vpush;
122122
mod vstr;
123+
mod vstm;
123124

124125
use {
125126
crate::decoder::str::{
@@ -270,6 +271,7 @@ use {
270271
vpush::decode_VPUSH_t1,
271272
vpush::decode_VPUSH_t2,
272273
vstr::{decode_VSTR_t1, decode_VSTR_t2},
274+
vstm::{decode_VSTM_t1, decode_VSTM_t2},
273275
};
274276

275277
///

zmu_cortex_m/src/decoder/vstm.rs

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use crate::core::bits::Bits;
2+
use crate::core::instruction::{
3+
AddressingMode, Instruction, VStoreMultipleParams32, VStoreMultipleParams64,
4+
};
5+
use crate::core::register::{DoubleReg, Reg, SingleReg};
6+
use enum_set::EnumSet;
7+
8+
#[allow(non_snake_case)]
9+
#[inline(always)]
10+
pub fn decode_VSTM_t1(opcode: u32) -> Instruction {
11+
let W = opcode.get_bit(21);
12+
let U = opcode.get_bit(23);
13+
let imm8 = opcode.get_bits(0..8) as u8;
14+
let imm32 = u32::from(imm8 << 2);
15+
let P = opcode.get_bit(24);
16+
17+
// check that we decoded correctly
18+
assert!((!P && U) || (P && !U && W));
19+
20+
let n = opcode.get_bits(16..20) as u8;
21+
let rn = Reg::from(n);
22+
let D = u8::from(opcode.get_bit(22));
23+
let Vd = opcode.get_bits(12..16) as u8;
24+
let d = D << 4 | Vd;
25+
26+
let regs = imm8 / 2;
27+
28+
if (P==U && W) || n == 15 || regs == 0 || regs > 16 || (d + regs) > 32 {
29+
return Instruction::UDF {
30+
imm32: 0,
31+
opcode: opcode.into(),
32+
thumb32: true,
33+
};
34+
}
35+
36+
#[cfg(feature = "VFPSmallRegisterBank")]
37+
{
38+
if (d + regs) > 16 {
39+
return Instruction::UDF {
40+
imm32: 0,
41+
opcode: opcode.into(),
42+
thumb32: true,
43+
};
44+
}
45+
}
46+
47+
let mode = if U {
48+
AddressingMode::IncrementAfter
49+
} else {
50+
AddressingMode::DecrementBefore
51+
};
52+
53+
let mut double_regs = EnumSet::new();
54+
for i in 0..regs {
55+
double_regs.insert(DoubleReg::from(i + d));
56+
}
57+
58+
Instruction::VSTM_T1 {
59+
params: VStoreMultipleParams64 {
60+
rn,
61+
write_back: W,
62+
list: double_regs,
63+
mode,
64+
imm32,
65+
},
66+
}
67+
}
68+
69+
#[allow(non_snake_case)]
70+
#[inline(always)]
71+
pub fn decode_VSTM_t2(opcode: u32) -> Instruction {
72+
let W = opcode.get_bit(21);
73+
let imm8 = opcode.get_bits(0..8) as u8;
74+
let imm32 = u32::from(imm8 << 2);
75+
let U = opcode.get_bit(23);
76+
let P = opcode.get_bit(24);
77+
78+
// check that we decoded correctly
79+
assert!((!P && U) || (P && !U && W));
80+
81+
let n = opcode.get_bits(16..20) as u8;
82+
let rn = Reg::from(n);
83+
84+
let D = u8::from(opcode.get_bit(22));
85+
let Vd = opcode.get_bits(12..16) as u8;
86+
let d = Vd << 1 | D;
87+
88+
let regs = imm8;
89+
90+
if (P==U && W) || n == 15 || regs == 0 || (d + regs) > 32 {
91+
return Instruction::UDF {
92+
imm32: 0,
93+
opcode: opcode.into(),
94+
thumb32: true,
95+
};
96+
}
97+
98+
let mode = if U {
99+
AddressingMode::IncrementAfter
100+
} else {
101+
AddressingMode::DecrementBefore
102+
};
103+
104+
105+
let mut single_regs = EnumSet::new();
106+
for i in 0..regs {
107+
single_regs.insert(SingleReg::from(d + i));
108+
}
109+
110+
Instruction::VSTM_T2 {
111+
params: VStoreMultipleParams32 {
112+
rn,
113+
write_back: W,
114+
list: single_regs,
115+
mode,
116+
imm32,
117+
},
118+
}
119+
}

zmu_cortex_m/src/executor/fp_load_and_store.rs

+71-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use crate::core::instruction::VPushPopParams;
1+
use crate::core::instruction::{
2+
AddressingMode, VPushPopParams, VStoreMultipleParams32, VStoreMultipleParams64,
3+
};
24
use crate::Processor;
35

46
use crate::executor::{ExecuteSuccess, ExecutorHelper};
@@ -18,6 +20,8 @@ pub trait IsaFloatingPointLoadAndStore {
1820
fn exec_vstr(&mut self, params: &VLoadAndStoreParams) -> ExecuteResult;
1921
fn exec_vpush(&mut self, params: &VPushPopParams) -> ExecuteResult;
2022
fn exec_vpop(&mut self, params: &VPushPopParams) -> ExecuteResult;
23+
fn exec_vstm_t1(&mut self, params: &VStoreMultipleParams64) -> ExecuteResult;
24+
fn exec_vstm_t2(&mut self, params: &VStoreMultipleParams32) -> ExecuteResult;
2125
}
2226

2327
impl IsaFloatingPointLoadAndStore for Processor {
@@ -139,4 +143,70 @@ impl IsaFloatingPointLoadAndStore for Processor {
139143
}
140144
Ok(ExecuteSuccess::NotTaken)
141145
}
146+
147+
fn exec_vstm_t1(&mut self, params: &VStoreMultipleParams64) -> ExecuteResult {
148+
if self.condition_passed() {
149+
//self.execute_fp_check();
150+
151+
let mut address = if params.mode == AddressingMode::IncrementAfter {
152+
self.get_r(params.rn)
153+
} else {
154+
self.get_r(params.rn) - params.imm32
155+
};
156+
157+
if params.write_back {
158+
let write_back_value = if params.mode == AddressingMode::IncrementAfter {
159+
self.get_r(params.rn) + params.imm32
160+
} else {
161+
self.get_r(params.rn) - params.imm32
162+
};
163+
self.set_r(params.rn, write_back_value);
164+
}
165+
166+
for reg in &params.list {
167+
let (low_word, high_word) = self.get_dr(reg);
168+
if self.big_endian() {
169+
self.write32(address, high_word)?;
170+
self.write32(address + 4, low_word)?;
171+
} else {
172+
self.write32(address, low_word)?;
173+
self.write32(address + 4, high_word)?;
174+
}
175+
address += 8;
176+
}
177+
178+
return Ok(ExecuteSuccess::Taken { cycles: 1 });
179+
}
180+
Ok(ExecuteSuccess::NotTaken)
181+
}
182+
183+
fn exec_vstm_t2(&mut self, params: &VStoreMultipleParams32) -> ExecuteResult {
184+
if self.condition_passed() {
185+
//self.execute_fp_check();
186+
187+
let mut address = if params.mode == AddressingMode::IncrementAfter {
188+
self.get_r(params.rn)
189+
} else {
190+
self.get_r(params.rn) - params.imm32
191+
};
192+
193+
if params.write_back {
194+
let write_back_value = if params.mode == AddressingMode::IncrementAfter {
195+
self.get_r(params.rn) + params.imm32
196+
} else {
197+
self.get_r(params.rn) - params.imm32
198+
};
199+
self.set_r(params.rn, write_back_value);
200+
}
201+
202+
for reg in &params.list {
203+
let value = self.get_sr(reg);
204+
self.write32(address, value)?;
205+
address += 4;
206+
}
207+
208+
return Ok(ExecuteSuccess::Taken { cycles: 1 });
209+
}
210+
Ok(ExecuteSuccess::NotTaken)
211+
}
142212
}

zmu_cortex_m/src/executor/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,8 @@ impl ExecutorHelper for Processor {
517517
// --------------------------------------------
518518
Instruction::VLDR { params } => self.exec_vldr(params),
519519
Instruction::VSTR { params } => self.exec_vstr(params),
520+
Instruction::VSTM_T1 { params } => self.exec_vstm_t1(params),
521+
Instruction::VSTM_T2 { params } => self.exec_vstm_t2(params),
520522
Instruction::VPUSH { params } => self.exec_vpush(params),
521523
Instruction::VPOP { params } => self.exec_vpop(params),
522524
Instruction::VMOV_imm_32 { params } => self.exec_vmov_imm_32(*params),

zmu_cortex_m/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#![allow(clippy::too_many_lines)]
2424
#![allow(clippy::redundant_else)]
2525
#![allow(clippy::empty_docs)]
26+
#![allow(clippy::nonminimal_bool)]
2627

2728
extern crate byteorder;
2829
extern crate enum_set;

0 commit comments

Comments
 (0)