1 // Copyright © 2024 Igalia S.L.
2 // SPDX-License-Identifier: MIT
3
4 use crate::util::EtnaAsmResultExt;
5
6 use etnaviv_isa_proc::IsaParser;
7 use isa_bindings::*;
8 use pest::iterators::Pair;
9 use pest::Parser;
10 use std::fs;
11 use std::str::FromStr;
12
13 #[derive(IsaParser)]
14 #[isa = "etnaviv.xml"]
15 #[static_rules_file = "static_rules.pest"]
16 struct Isa;
17
get_child_rule(item: Pair<Rule>) -> Rule18 fn get_child_rule(item: Pair<Rule>) -> Rule {
19 item.into_inner().next().unwrap().as_rule()
20 }
21
parse_pair<T: FromStr>(item: Pair<Rule>) -> T where T::Err: std::fmt::Debug,22 fn parse_pair<T: FromStr>(item: Pair<Rule>) -> T
23 where
24 T::Err: std::fmt::Debug,
25 {
26 item.as_str().parse::<T>().unwrap()
27 }
28
fill_swizzle(item: Pair<Rule>) -> u3229 fn fill_swizzle(item: Pair<Rule>) -> u32 {
30 assert!(item.as_rule() == Rule::SrcSwizzle);
31
32 item.into_inner()
33 .map(|comp| match comp.as_rule() {
34 Rule::Swiz => match comp.as_str() {
35 "x" => 0,
36 "y" => 1,
37 "z" => 2,
38 "w" => 3,
39 _ => panic!("Unexpected swizzle {:?}", comp.as_str()),
40 },
41 _ => panic!("Unexpected rule {:?}", comp.as_rule()),
42 })
43 .enumerate()
44 .fold(0, |acc, (index, swiz_index)| {
45 acc | swiz_index << (2 * index)
46 })
47 }
48
fill_destination(pair: Pair<Rule>, dest: &mut etna_inst_dst)49 fn fill_destination(pair: Pair<Rule>, dest: &mut etna_inst_dst) {
50 dest.set_use(1);
51
52 for item in pair.into_inner() {
53 match item.as_rule() {
54 Rule::RegAddressingMode => {
55 let rule = get_child_rule(item);
56 dest.set_amode(isa_reg_addressing_mode::from_rule(rule));
57 }
58 Rule::Register => {
59 dest.set_reg(parse_pair(item));
60 }
61 Rule::Wrmask => {
62 let rule = get_child_rule(item);
63 dest.set_write_mask(isa_wrmask::from_rule(rule));
64 }
65 _ => panic!("Unexpected rule {:?}", item.as_rule()),
66 }
67 }
68 }
69
fill_mem_destination(pair: Pair<Rule>, dest: &mut etna_inst_dst)70 fn fill_mem_destination(pair: Pair<Rule>, dest: &mut etna_inst_dst) {
71 dest.set_use(1);
72
73 for item in pair.into_inner() {
74 match item.as_rule() {
75 Rule::Wrmask => {
76 let rule = get_child_rule(item);
77 dest.set_write_mask(isa_wrmask::from_rule(rule));
78 }
79 _ => panic!("Unexpected rule {:?}", item.as_rule()),
80 }
81 }
82 }
83
fill_tex(pair: Pair<Rule>, tex: &mut etna_inst_tex)84 fn fill_tex(pair: Pair<Rule>, tex: &mut etna_inst_tex) {
85 for item in pair.into_inner() {
86 match item.as_rule() {
87 Rule::Register => {
88 let r = parse_pair(item);
89 tex.set_id(r)
90 }
91 Rule::SrcSwizzle => {
92 let bytes = fill_swizzle(item);
93 tex.set_swiz(bytes);
94 }
95 _ => panic!("Unexpected rule {:?}", item.as_rule()),
96 }
97 }
98 }
99
fill_source(pair: Pair<Rule>, src: &mut etna_inst_src, dual_16_mode: bool)100 fn fill_source(pair: Pair<Rule>, src: &mut etna_inst_src, dual_16_mode: bool) {
101 src.set_use(1);
102
103 for item in pair.into_inner() {
104 match item.as_rule() {
105 Rule::Absolute => unsafe {
106 src.__bindgen_anon_1.__bindgen_anon_1.set_abs(1);
107 },
108 Rule::Negate => unsafe {
109 src.__bindgen_anon_1.__bindgen_anon_1.set_neg(1);
110 },
111 Rule::RegGroup => {
112 let rule = get_child_rule(item);
113 src.set_rgroup(isa_reg_group::from_rule(rule));
114 }
115 Rule::RegAddressingMode => {
116 let rule = get_child_rule(item);
117 unsafe {
118 src.__bindgen_anon_1
119 .__bindgen_anon_1
120 .set_amode(isa_reg_addressing_mode::from_rule(rule));
121 }
122 }
123 Rule::Register => {
124 let r = parse_pair(item);
125 unsafe {
126 src.__bindgen_anon_1.__bindgen_anon_1.set_reg(r);
127 }
128 }
129 Rule::Immediate_Minus_Nan => {
130 src.set_rgroup(isa_reg_group::ISA_REG_GROUP_IMMED);
131
132 let imm_struct = unsafe { &mut src.__bindgen_anon_1.__bindgen_anon_2 };
133
134 imm_struct.set_imm_type(0);
135 imm_struct.set_imm_val(0xfffff);
136 }
137 Rule::Immediate_float => {
138 let value: f32 = parse_pair(item);
139 let bits = value.to_bits();
140
141 assert!((bits & 0xfff) == 0); /* 12 lsb cut off */
142 src.set_rgroup(isa_reg_group::ISA_REG_GROUP_IMMED);
143
144 let imm_type = if dual_16_mode { 3 } else { 0 };
145 let imm_struct = unsafe { &mut src.__bindgen_anon_1.__bindgen_anon_2 };
146
147 imm_struct.set_imm_type(imm_type);
148 imm_struct.set_imm_val(bits >> 12);
149 }
150 i_type @ (Rule::Immediate_int | Rule::Immediate_uint) => {
151 let value = if i_type == Rule::Immediate_int {
152 parse_pair::<i32>(item) as u32
153 } else {
154 parse_pair::<u32>(item)
155 };
156
157 src.set_rgroup(isa_reg_group::ISA_REG_GROUP_IMMED);
158
159 let imm_struct = unsafe { &mut src.__bindgen_anon_1.__bindgen_anon_2 };
160 imm_struct.set_imm_type(1);
161 imm_struct.set_imm_val(value);
162 }
163 Rule::SrcSwizzle => {
164 let bytes = fill_swizzle(item);
165 unsafe {
166 src.__bindgen_anon_1.__bindgen_anon_1.set_swiz(bytes);
167 }
168 }
169 _ => panic!("Unexpected rule {:?}", item.as_rule()),
170 }
171 }
172 }
173
process(input: Pair<Rule>, dual_16_mode: bool) -> Option<etna_inst>174 fn process(input: Pair<Rule>, dual_16_mode: bool) -> Option<etna_inst> {
175 // The assembler and disassembler are both using the
176 // 'full' form of the ISA which contains void's and
177 // use the HW ordering of instruction src arguments.
178
179 if input.as_rule() == Rule::EOI {
180 return None;
181 }
182
183 // Create instruction with sane defaults.
184 let mut instr = etna_inst::default();
185 instr.dst.set_write_mask(isa_wrmask::ISA_WRMASK_XYZW);
186
187 instr.opcode = isa_opc::from_rule(input.as_rule());
188 let mut src_index = 0;
189
190 for p in input.into_inner() {
191 match p.as_rule() {
192 Rule::Dst_full => {
193 instr.set_dst_full(1);
194 }
195 Rule::Sat => {
196 instr.set_sat(1);
197 }
198 Rule::Cond => {
199 let rule = get_child_rule(p);
200 instr.set_cond(isa_cond::from_rule(rule));
201 }
202 Rule::Skphp => {
203 instr.set_skphp(1);
204 }
205 Rule::Pmode => {
206 instr.set_pmode(1);
207 }
208 Rule::Denorm => {
209 instr.set_denorm(1);
210 }
211 Rule::Local => {
212 instr.set_local(1);
213 }
214 Rule::Left_shift => {
215 let item = p.into_inner().next().unwrap();
216 let amount = parse_pair(item);
217 instr.set_left_shift(amount);
218 }
219 Rule::Type => {
220 let rule = get_child_rule(p);
221 instr.type_ = isa_type::from_rule(rule);
222 }
223 Rule::Thread => {
224 let rule = get_child_rule(p);
225 instr.set_thread(isa_thread::from_rule(rule));
226 }
227 Rule::Rounding => {
228 let rule = get_child_rule(p);
229 instr.rounding = isa_rounding::from_rule(rule);
230 }
231 Rule::DestVoid => {
232 // Nothing to do
233 }
234 Rule::DstRegister => {
235 fill_destination(p, &mut instr.dst);
236 }
237 Rule::DstMemAddr => {
238 fill_mem_destination(p, &mut instr.dst);
239 }
240 Rule::SrcVoid => {
241 // Nothing to do
242 }
243 Rule::SrcRegister => {
244 fill_source(p, &mut instr.src[src_index], dual_16_mode);
245 src_index += 1;
246 }
247 Rule::TexSrc => {
248 fill_tex(p, &mut instr.tex);
249 }
250 Rule::Target => {
251 let target = parse_pair(p);
252 instr.imm = target;
253 }
254 _ => panic!("Unexpected rule {:?}", p.as_rule()),
255 }
256 }
257
258 Some(instr)
259 }
260
parse(rule: Rule, content: &str, dual_16_mode: bool, asm_result: &mut etna_asm_result)261 fn parse(rule: Rule, content: &str, dual_16_mode: bool, asm_result: &mut etna_asm_result) {
262 let result = Isa::parse(rule, content);
263
264 match result {
265 Ok(program) => {
266 for line in program {
267 if let Some(result) = process(line, dual_16_mode) {
268 asm_result.append_instruction(result);
269 }
270 }
271
272 asm_result.success = true;
273 }
274 Err(e) => {
275 asm_result.set_error(&format!("{}", e));
276 asm_result.success = false;
277 }
278 }
279 }
280
asm_process_str(string: &str, dual_16_mode: bool, asm_result: &mut etna_asm_result)281 pub fn asm_process_str(string: &str, dual_16_mode: bool, asm_result: &mut etna_asm_result) {
282 parse(Rule::instruction, string, dual_16_mode, asm_result)
283 }
284
asm_process_file(file: &str, dual_16_mode: bool, asm_result: &mut etna_asm_result)285 pub fn asm_process_file(file: &str, dual_16_mode: bool, asm_result: &mut etna_asm_result) {
286 let content = fs::read_to_string(file).expect("cannot read file");
287
288 parse(Rule::instructions, &content, dual_16_mode, asm_result)
289 }
290