dev_csr_macro/
lib.rs

1use parse::{BitRange, Periph, Var, Reg};
2use proc_macro::TokenStream;
3use syn::{parse_macro_input, spanned::Spanned, Attribute, Ident};
4use heck::*;
5use proc_macro2::{Literal, Span, TokenStream as TokenStream2};
6use quote::quote;
7
8mod parse;
9
10macro_rules! ident {
11    ($format:expr, $ident:expr) => {
12        Ident::new(&(format!($format, $ident)), $ident.span())
13    };
14}
15
16struct IdentGen {
17    counter: usize
18}
19
20impl IdentGen {
21    pub fn new() -> IdentGen {
22        IdentGen {
23            counter: 0
24        }
25    }
26
27    fn next(&mut self) -> Ident {
28        let ident = Ident::new(&format!("_{}", self.counter), Span::call_site());
29        self.counter += 1;
30        ident
31    }
32}
33
34fn reg_ident(reg: &Ident) -> Ident {
35    Ident::new(&("Reg".to_string() + &reg.to_string().to_upper_camel_case()), reg.span())
36}
37
38#[proc_macro]
39pub fn dev_csr(input: TokenStream) -> TokenStream {
40    let Periph {
41        addr_ty,
42        word_ty,
43        name,
44        regs,
45        vars,
46        keywords,
47        ..
48    } = parse_macro_input!(input as Periph);
49
50    let addr_trait = ident!("As{}Addr", name);
51    let read_trait = ident!("Read{}", name);
52    let write_trait = ident!("Write{}", name);
53
54    let mut out = TokenStream2::new();
55
56    let mut read_out = TokenStream2::new();
57    let mut write_out = TokenStream2::new();
58
59    // coloring on keywords
60    for kw in keywords {
61        let fake_kw = Ident::new("const", kw.span());
62        out.extend(quote! {
63            #fake_kw _: u8 = 0;
64        });
65    }
66
67    for reg in regs {
68        let reg_struct = reg_ident(&reg.reg);
69        let Reg { addr, access, .. } = reg;
70        let readable = access.readable;
71        let writable = access.writable;
72
73        out.extend(quote!{
74            pub struct #reg_struct;
75            impl #reg_struct {
76                pub const ADDR: #addr_ty = #addr;
77                pub const READABLE: bool = #readable;
78                pub const WRITABLE: bool = #writable;
79            }
80
81            impl #addr_trait for #reg_struct {
82                fn as_addr(&self) -> #addr_ty {
83                    #addr
84                }
85            }
86        });
87
88        if readable {
89            out.extend(quote! {
90                impl ReadableAddr for #reg_struct {}
91            });
92        }
93
94        if writable {
95            out.extend(quote! {
96                impl WritableAddr for #reg_struct {}
97            });
98        }
99    }
100
101    for (_, var) in &vars {
102        let IoFn { read, write } = gen_io_fn(var);
103
104        let mut name = var.parts[0].var.clone();
105        name.set_span(Span::call_site());
106        let mut set_var = ident!("set_{}", name);
107        set_var.set_span(Span::call_site());
108        let var_ty = &var.ty;
109        let attr: Vec<&Attribute> = (&var.parts).iter().flat_map(|part| &part.attr).collect();
110
111        if var.access.readable {
112            if let Some(read) = read {
113                read_out.extend(quote! {
114                    #(#attr)*
115                    fn #name(&mut self) -> impl core::future::Future<Output = core::result::Result<#var_ty, Self::Error>> {
116                        #read
117                    }
118                })
119            }
120        }
121
122        if var.access.writable {
123            if let Some(write) = write {
124                write_out.extend(quote! {
125                    #(#attr)*
126                    fn #set_var(&mut self, value: #word_ty) -> impl core::future::Future<Output = core::result::Result<(), Self::Error>> {
127                        #write
128                    }
129                })
130            }
131        }
132    }
133
134    out.extend(quote! {
135        pub trait #addr_trait {
136            fn as_addr(&self) -> #addr_ty;
137        }
138        pub trait ReadableAddr: #addr_trait {}
139        pub trait WritableAddr: #addr_trait {}
140
141        pub trait ReadableValue<T> {
142            fn from_value(value: T) -> Self;
143        }
144        pub trait WritableValue<T> {
145            fn into_value(self) -> T;
146        }
147
148        /*
149        pub struct Transmuted<T>;
150        impl <T> ReadableValue for Transmuted<T> {
151            fn from_value<T>(value: T) -> self {
152                unsafe {
153                    core::mem::transmute(value)
154                }
155            }
156        }
157        impl <T> WritableValue for Transmuted<T> {
158
159        }*/
160
161        impl #addr_trait for #addr_ty {
162            fn as_addr(&self) -> #addr_ty {
163                *self
164            }
165        }
166        impl ReadableAddr for #addr_ty {}
167        impl WritableAddr for #addr_ty {}
168
169        pub trait #read_trait {
170            type Error;
171
172            fn read_contiguous_regs(
173                &mut self,
174                addr: impl ReadableAddr,
175                out: &mut [#word_ty]
176            ) -> impl core::future::Future<Output = core::result::Result<(), Self::Error>>;
177
178            fn read_reg(
179                &mut self,
180                addr: impl ReadableAddr
181            ) -> impl core::future::Future<Output = core::result::Result<#word_ty, Self::Error>> {
182                async move {
183                    let mut out = [0];
184                    match self.read_contiguous_regs(addr, &mut out).await {
185                        Ok(_) => Ok(out[0]),
186                        Err(err) => Err(err)
187                    }
188                }
189            }
190
191            #read_out
192        }
193
194        pub trait #write_trait {
195            type Error;
196
197            /// Write consecutive words to the peripheral. Most chips have it so
198            /// that when writing more than just one word, the next word goes into the
199            /// next address.
200            fn write_contiguous_regs(
201                &mut self,
202                addr: impl WritableAddr,
203                values: &[#word_ty],
204            ) -> impl core::future::Future<Output = core::result::Result<(), Self::Error>>;
205
206            /// Write one word to the peripheral. Default calls `write_contiguous_regs` with length `1`.
207            fn write_reg(
208                &mut self,
209                addr: impl WritableAddr,
210                value: #word_ty
211            ) -> impl core::future::Future<Output = core::result::Result<(), Self::Error>> {
212                async move {
213                    let words = [value];
214                    self.write_contiguous_regs(addr, &words).await
215                }
216            }
217
218            #write_out
219        }
220    });
221
222    out.into()
223}
224
225struct IoFn {
226    read: Option<TokenStream2>,
227    write: Option<TokenStream2>
228}
229fn gen_io_fn(var: &Var) -> IoFn {
230    let var_ty = &var.ty;
231    let mut should_write = true;
232
233    if var.parts.len() == 0 {
234        panic!("Var with no parts???");
235    }
236
237    //let name = &var.parts[0].var;
238
239    if var.parts.len() == 1 {
240        let part = &var.parts[0];
241        let reg = reg_ident(&part.reg);
242
243        // Special case: 1-to-1 mapping
244        if part.reg_range == BitRange::Entire && part.var_range == BitRange::Entire {
245            return IoFn {
246                read: Some(quote! {
247                    self.read_reg(#reg)
248                }),
249                write: Some(quote! {
250                    self.write_reg(#reg, value)
251                })
252            }
253        }
254
255        // Special case: boolean
256        if let BitRange::Single(index) = part.reg_range {
257            if part.var_range == BitRange::Entire {
258                let index = Literal::usize_unsuffixed(index);
259
260                return IoFn {
261                    read: Some(quote! {
262                        async move {
263                            let word = self.read_reg(#reg).await?;
264                            let word = (word >> #index) % 1;
265                            unsafe {
266                                Ok(core::mem::transmute(word))
267                            }
268                        }
269                    }),
270                    write: None,
271                }
272            }
273        }
274    }
275
276    let mut gen = IdentGen::new();
277
278    struct Contig {
279        start: Ident,
280        start_addr: usize,
281        /// Ident that corresponds to each word.
282        words: Vec<Ident>
283    }
284
285    let mut read_var_out = TokenStream2::new();
286    let mut write_var_out = TokenStream2::new();
287
288    let mut contigs: Vec<Contig> = vec![];
289
290    let acc = gen.next();
291
292    for part in &var.parts {
293        let addr = part.reg_addr.base10_parse().unwrap();
294        let ident = gen.next();
295        
296        let contig = match contigs.last() {
297            Some(last) if last.start_addr + last.words.len() == addr => {
298                let mut contig = contigs.pop().unwrap();
299                contig.words.push(ident.clone());
300                contig
301            },
302            _ => {
303                Contig {
304                    start: reg_ident(&part.reg),
305                    start_addr: addr,
306                    words: vec![ident.clone()]
307                }
308            }
309        };
310
311        match part.reg_range {
312            BitRange::Entire => {
313                let var_start = Literal::usize_unsuffixed(part.var_range.start().unwrap());
314                let var_end = Literal::usize_unsuffixed(part.var_range.end().unwrap());
315
316                read_var_out.extend(quote! {
317                    #acc += (#ident as #var_ty) << #var_start;
318                });
319
320                write_var_out.extend(quote! {
321                    let #ident = ((#acc % (1 << (#var_end + 1))) >> #var_start);
322                });
323            },
324            _ => {
325                let reg_start = part.reg_range.start().unwrap();
326                let reg_end = part.reg_range.end().unwrap();
327                let var_start = match part.var_range {
328                    BitRange::Entire => 0,
329                    range => range.start().unwrap()
330                };
331
332                let reg_start = Literal::usize_unsuffixed(reg_start);
333                let reg_end = Literal::usize_unsuffixed(reg_end);
334                let var_start = Literal::usize_unsuffixed(var_start);
335                
336                read_var_out.extend(quote! {
337                    #acc += (((#ident % (1 << (#reg_end + 1))) as #var_ty) >> #reg_start) << #var_start;
338                });
339
340                // Don't write -- theres other stuff in the register that we would overwrite
341                should_write = false;
342                /*match part.var_range.end() {
343                    Some(var_end) => {
344                        write_var_out.extend(quote! {
345                            let #ident = ((#acc % (#var_end + 1)) >> #var_start) << #reg_start;
346                        })
347                    },
348                    None => {
349                        write_var_out.extend(quote! {
350                            let #ident = (#acc >> #var_start) << #reg_start;
351                        })
352                    }
353                }       */         
354            }
355        }
356
357        contigs.push(contig);
358    }
359
360    let mut read_begin = TokenStream2::new();
361    let mut write_end = TokenStream2::new();
362
363    for contig in contigs {
364        if contig.words.len() == 1 {
365            let ident = &contig.words[0];
366            let reg = contig.start;
367
368            read_begin.extend(quote! {
369                let #ident = self.read_reg(#reg).await?;
370            });
371
372            write_end.extend(quote! {
373                self.write_reg(#reg, #ident).await?;
374            });
375        } else {
376            let words = &contig.words;
377            let len = contig.words.len();
378            let start = contig.start;
379
380            read_begin.extend(quote! {
381                let mut read = [0u8; #len];
382                self.read_contiguous_regs(#start, &mut read).await?;
383                let [#(#words),*] = read;
384            });
385
386            write_end.extend(quote! {
387                self.write_contiguous_regs::<#len>(#start, &[#(#words),*]).await?;
388            });
389        }
390    }
391
392    return IoFn {
393        read: Some(quote! {
394            async move {
395                #read_begin
396                let mut #acc: #var_ty = 0;
397                #read_var_out
398                Ok(#acc)
399            }
400        }),
401        write: if should_write {
402            Some(quote! {
403                async move {
404                    let mut #acc = value;
405                    #write_var_out
406                    #write_end
407                    Ok(())
408                }
409            })
410        } else {
411            None
412        }
413    }
414}