1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// This file is part of simavr-section, a Rust port of the *simavr*
// header `avr_mcu_section.h`.
//
// Copyright 2021 Andrew Dona-Couch
//
// simavr-section is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// simavr-section is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//! Add simavr-compatible metadata to your binary.
//!
//! The [`simavr`] library specifies a format for including AVR-related
//! metadata in a firmware ELF file. This crate ports that format to Rust,
//! to allow AVR binaries authored entirely in Rust to specify `simavr`-compliant
//! metadata.
//!
//! The metadata is used to pass various "parameters" to a simulator, such as
//! what microcontroller the code was built for, the expected clock frequency, fuses,
//! and so forth. The same metadata could be read by a programmer to verify the
//! chip being programmed and update fuses as appropriate.
//!
//! # Example
//!
//! Start by adding the `avr_mcu` macro to your `main.rs`. This metadata specifies
//! the core and frequency and is always required.
//!
//! ```
//! use simavr_section::avr_mcu;
//! avr_mcu!(8000000, b"atmega88");
//! ```
//!
//! You can then add additional metadata, such as configuring a VCD trace file
//! that the simulator should export:
//!
//! ```
//! use simavr_section::{avr_mcu_vcd_file, avr_mcu_vcd_port_pin};
//! avr_mcu_vcd_file!(b"gtkwave_trace.vcd", 1 /* param ignored due to a bug in simavr */);
//! avr_mcu_vcd_port_pin!(b'B', 5, b"PORTB5");
//! ```
//!
//! # Build Flags
//!
//! To ensure the metadata passes through to the final ELF, you need to add some link
//! args to the `rustc` call. The easiest way to do this is to add or update your
//! `config.toml` file with these lines:
//!
//! ```toml
//! [target.'cfg(target_arch = "avr")']
//! rustflags = ["-C", "link-arg=-Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000"]
//! ```
//!
//! [`simavr`]: https://github.com/buserror/simavr
pub use simavr_section_sys as bindings;
pub use ;
/// Specify the AVR device and frequency to use.
///
/// Name the device starting with `at`, such as `attiny10` or `atmega328p`.
/// The frequency needs to be a `const`-valued `u32`.
///
/// This tag must always be included.
///
/// # Example
///
/// ```
/// # use simavr_section::avr_mcu;
/// avr_mcu!(8000000, b"atmega88");
/// ```
/// Specify the AVR device voltages.
///
/// This tag allows you to specify the voltages used by your board
/// It is optional in most cases, but you will need it if you use
/// ADC module's IRQs. Not specifying it in this case might lead
/// to a divide-by-zero crash.
/// The units are Volts*1000 (millivolts)
///
/// All three voltages must be literal values.
///
/// # Example
///
/// ```
/// # use simavr_section::avr_mcu_voltages;
/// // Vcc & AVcc are 5V, Aref is 2.5V
/// avr_mcu_voltages!(5000, 5000, 2500);
/// ```
/// Write to the VCD tracefile at the given period.
///
/// Specifies the name and wanted period (in usec) for a VCD file.
/// Both must be literal values.
///
/// Note that due to a [bug in `simavr`], the period is ignored.
///
/// [bug in `simavr`]: https://github.com/buserror/simavr/issues/325
///
/// # Example
///
/// ```
/// # use simavr_section::avr_mcu_vcd_file;
/// avr_mcu_vcd_file!(b"gtkwave_trace.vcd", 1 /* param ignored due to a bug in simavr */);
/// ```
/// Add this port/pin to the VCD file.
///
/// The syntax uses the name of the port as a character,
/// and not a pointer to a register.
///
/// The port character and pin number must be constant-valued expressions.
/// The trace name must be a literal byte string.
///
/// # Example
///
/// ```
/// # use simavr_section::avr_mcu_vcd_port_pin;
/// avr_mcu_vcd_port_pin!(b'B', 5, b"PORTB5");
/// ```
/// Add an IRQ vector to the VCD file.
///
/// These allows you to add a trace showing how long an IRQ vector is pending,
/// and also how long it is running. You can specify the IRQ as a vector name
/// straight from the firmware file, and it will be named properly in the trace
///
/// The vector number and what byte must be `const`-valued expressions.
/// The trace name must be a literal byte string.
///
/// # Example
///
/// ```
/// # use simavr_section::avr_mcu_vcd_irq_trace;
/// avr_mcu_vcd_irq_trace!(1, 1, b"INT0");
/// ```
/// Configure pins which have external pullup or pulldown resistors.
///
/// Allows the firmware to hint simavr as to wether there are external
/// pullups/down on PORT pins. It helps if the firmware uses "open drain"
/// pins by toggling the DDR pins to switch between an output state and
/// a "default" state.
///
/// The value passed here will be output on the PORT IRQ when the DDR
/// pin is set to input again
///
/// # Example
///
/// ```
/// # use simavr_section::avr_mcu_external_port_pull;
/// // Expect an external pull-up on PINB5 and an external pull-down
/// // on PINB0.
/// avr_mcu_external_port_pull!(b'B', 0x11, 0x10);
/// ```