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() + ®.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 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);
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 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 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 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 if var.parts.len() == 1 {
240 let part = &var.parts[0];
241 let reg = reg_ident(&part.reg);
242
243 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 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 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 should_write = false;
342 }
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}