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