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