541 lines
15 KiB
HTML
541 lines
15 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
|
|
<title>Emulating the Badge Under Renode</title>
|
|
|
|
<link rel="stylesheet" href="dist/reset.css">
|
|
<link rel="stylesheet" href="dist/reveal.css">
|
|
<link rel="stylesheet" href="dist/theme/fossasia2023.css">
|
|
|
|
<!-- Theme used for syntax highlighted code -->
|
|
<link rel="stylesheet" href="plugin/highlight/zenburn.css">
|
|
</head>
|
|
|
|
<body>
|
|
<div class="reveal">
|
|
<div class="footer">
|
|
<a class="url" href="https://p.xobs.io/c23/">p.xobs.io/c23</a>
|
|
</div>
|
|
<div class="slides">
|
|
<section>
|
|
<h2>Emulating the Badge Under Renode</h2>
|
|
<h3>(Eventually)</h3>
|
|
<br />
|
|
<h3>Sean "xobs" Cross</h3>
|
|
</section>
|
|
<section>
|
|
<h2>About Me</h2>
|
|
<img data-src="img/xobs-projects.jpg">
|
|
</section>
|
|
<section>
|
|
<h2>Talk Outline</h2>
|
|
<ol>
|
|
<li>What is Renode?</li>
|
|
<li>How is it extensible?</li>
|
|
<li>What is the state of the badge?</li>
|
|
</ol>
|
|
</section>
|
|
<section>
|
|
<section>
|
|
<h2>What is Renode?</h2>
|
|
<img data-src="img/renode-base.png">
|
|
</section>
|
|
<section>
|
|
<h2>Renode is an Emulator</h2>
|
|
<ul>
|
|
<li>Windows</li>
|
|
<li>Mac</li>
|
|
<li>Linux</li>
|
|
<ul>
|
|
<li>CI</li>
|
|
<li>Github Actions</li>
|
|
</ul>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Generic Whole-system Emulator</h2>
|
|
<ul>
|
|
<li>CPU cores</li>
|
|
<li>Peripherals</li>
|
|
<li>Interconnections</li>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Whole-system Emulator</h2>
|
|
<img data-src="img/computer-layout.png">
|
|
</section>
|
|
<section>
|
|
<h2>CPU Cores</h2>
|
|
<ul>
|
|
<li>x86</li>
|
|
<li>arm</li>
|
|
<li>arm64</li>
|
|
<li>ppc</li>
|
|
<li>riscv</li>
|
|
<li>sparc</li>
|
|
<li>xtensa</li>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Peripherals</h2>
|
|
<img data-src="img/esp32s3-peripheral-list.png">
|
|
</section>
|
|
<section>
|
|
<h2>Memory is Just a Peripheral</h2>
|
|
<ul>
|
|
<li>When you write to memory, it remembers the data</li>
|
|
<li>When you read from memory, you get the value</li>
|
|
<li>Your program is just initialised memory</li>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Peripherals Are Just Special Memory</h2>
|
|
<ul>
|
|
<li>Writing to a memory address does a thing</li>
|
|
<li>Reading from an address gets a result</li>
|
|
<li>Interrupts are just GPIOs</li>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Peripherals Are Just Special Memory</h2>
|
|
<img data-src="img/memory-write.png">
|
|
</section>
|
|
<section>
|
|
<h2>10% Functionality Solves 90% of Usecases</h2>
|
|
<img data-src="img/vt100-MA-4352.png">
|
|
<!-- <ul>
|
|
<li>E.g. in a serial device, baudrate, timers, and parity/stop can be ignored</li>
|
|
<li>Just "Tx", "Rx", and interrupt setup</li>
|
|
<li>Most software works just fine if you return zeroes for invalid addresses</li>
|
|
</ul> -->
|
|
</section>
|
|
<section>
|
|
<h2>Existing Peripherals in Renode</h2>
|
|
<ul>
|
|
<li>Built-in peripherals for a number of devices</li>
|
|
<ul>
|
|
<li>STM32</li>
|
|
<li>NRF52</li>
|
|
<li>IMXRT</li>
|
|
<li>LiteX</li>
|
|
</ul>
|
|
<li>See
|
|
https://github.com/renode/renode-infrastructure/tree/master/src/Emulator/Peripherals/Peripherals
|
|
for more</li>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Creating New Peripherals</h2>
|
|
<ul>
|
|
<li>Renode is written in C#</li>
|
|
<li>Like Java, C# has an <code>eval()</code> function</li>
|
|
<li>Peripherals can be written and loaded at runtime</li>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Networks in Renode</h2>
|
|
<ul>
|
|
<li>Built-in support for CAN, Ethernet, and Wireless</li>
|
|
<li>Also possible to add networks at runtime</li>
|
|
<li>No latency, just packets of data</li>
|
|
<ul>
|
|
<li>Different devices run at different speeds</li>
|
|
</ul>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Other Goodies</h2>
|
|
<ul>
|
|
<li>Video output with touchscreen support</li>
|
|
<li>Python interpreter for quick hacks</li>
|
|
<li>Networked serial port</li>
|
|
<li>GDB server for each core</li>
|
|
<li>Function call logging</li>
|
|
<li>Robot framework scripting</li>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Shortcomings</h2>
|
|
<ul>
|
|
<li>Unable to unload modules</li>
|
|
<ul>
|
|
<li>Need to restart Renode when you change a file</li>
|
|
</ul>
|
|
<li>No real audio support</li>
|
|
<ul>
|
|
<li>Support for verifying I2S, but can't play it</li>
|
|
</ul>
|
|
<li>Only x64 hosts</li>
|
|
<ul>
|
|
<li>Runs under Rosetta on Mac</li>
|
|
</ul>
|
|
<li>Documentation needs work</li>
|
|
<ul>
|
|
<li>Use the source!</li>
|
|
</ul>
|
|
</ul>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<section>
|
|
<h2>Extending Renode</h2>
|
|
</section>
|
|
<section>
|
|
<h2>First, Betrusted</h2>
|
|
<ul>
|
|
<li>FPGA with VexRiscv</li>
|
|
<li>2nd FPGA with smaller VexRiscv</li>
|
|
<li>16-bit COM bus between them</li>
|
|
<li>AES extensions</li>
|
|
<li>x25519 "ENGINE" accelerator</li>
|
|
<li>SHA accelerator</li>
|
|
<li>Battery charger and manager</li>
|
|
<li>Custom lcd, timers, and USB</li>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Betrusted</h2>
|
|
<img data-src="img/renode-multi-system.png">
|
|
</section>
|
|
<section>
|
|
<h2>Emulating it With Renode</h2>
|
|
<ul>
|
|
<li>Can develop the OS!</li>
|
|
<li>Good enough to catch hardware bugs</li>
|
|
</ul>
|
|
</section>
|
|
<section data-transition="slide-in fade-out">
|
|
<h2>Getting Hardware to Users</h2>
|
|
<img src="img/betrusted-wycheproof-patch.png">
|
|
</section>
|
|
<section data-transition="fade-in">
|
|
<h2>Getting Hardware to Users</h2>
|
|
<img src="img/betrusted-wycheproof-patch-fix.png">
|
|
</section>
|
|
<section>
|
|
<section>
|
|
<h1>Demonstration!</h1>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<section>
|
|
<h2>Getting Started with Renode</h2>
|
|
<ol>
|
|
<li>Renode Platform Definition (<code>.repl</code>)</li>
|
|
<li>Renode Script (<code>.resc</code>)</li>
|
|
</ol>
|
|
</section>
|
|
<section>
|
|
<h2>Example project repl: </h2>
|
|
<pre><code>using "platforms/cpus/nrf52840.repl"
|
|
gpio0: // PinName in ArduinoIDE
|
|
24 -> led_red@0 // LED_RED
|
|
16 -> led_green@0 // LED_GREEN
|
|
6 -> led_blue@0 // LED_BLUE
|
|
camera: Sensors.ArduCAMMini2MPPlus @ {
|
|
spi2;
|
|
twi0 0x30
|
|
}
|
|
lsm9ds1_imu: Sensors.LSM9DS1_IMU @ twi0 0x6b
|
|
lsm9ds1_mag: Sensors.LSM9DS1_Magnetic @ twi0 0x1e
|
|
</code></pre>
|
|
</section>
|
|
<section>
|
|
<h2>Example project resc</h2>
|
|
<pre><code>using sysbus
|
|
mach create
|
|
machine LoadPlatformDescription @platforms/cpus/stm32f103.repl
|
|
machine LoadPlatformDescriptionFromString \
|
|
"button: Miscellaneous.Button @ gpioPortC 13 { IRQ -> gpioPortC@13 }"
|
|
showAnalyzer usart2
|
|
macro reset
|
|
"""
|
|
sysbus LoadELF @zephyr-stm32f103-button.elf
|
|
"""
|
|
runMacro $reset</code></pre>
|
|
</section>
|
|
<section>
|
|
<h2>Running it</h2>
|
|
<pre><code>mono64 Renode.exe project.resc</code></pre>
|
|
</section>
|
|
<section>
|
|
<h2>How to Extend Renode</h2>
|
|
<ol>
|
|
<li>Find a peripheral that does what you want</li>
|
|
<ul>
|
|
<li>You might even find a compatible peripheral!</li>
|
|
</ul>
|
|
<li>Copy it to your project</li>
|
|
<li>Change the constructor</li>
|
|
<li>Change the register set</li>
|
|
<li>Import the <code>.cs</code> file into Renode</li>
|
|
<li>Add it to your platform file</li>
|
|
</ol>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<section>
|
|
<h2>Running Badge Software in Renode</h2>
|
|
</section>
|
|
<section>
|
|
<h2>It Doesn't</h2>
|
|
</section>
|
|
<section>
|
|
<h2>Xtensa is an Uncommon Architecture</h2>
|
|
<ul>
|
|
<li>Audio DSPs</li>
|
|
<li>Possibly Intel?</li>
|
|
<li>NXP</li>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Extensive use of Boot ROM</h2>
|
|
<ul>
|
|
<img data-src="img/memory-maps.png">
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Extensive use of Boot ROM</h2>
|
|
<ul>
|
|
<pre><code class="wrap">$ esptool.py dump_mem \
|
|
0x3ff90000 \
|
|
65536 \
|
|
irom.bin</code></pre>
|
|
</ul>
|
|
</section>
|
|
<!-- <section>
|
|
<ul>
|
|
<li>Immediately get output</li>
|
|
<li>Breaks immediately</li>
|
|
</ul>
|
|
</section> -->
|
|
<section>
|
|
<h2>Add a serial port</h2>
|
|
<code><pre>
|
|
namespace Antmicro.Renode.Peripherals.UART {
|
|
public class ESP32_UART : UARTBase, IDoubleWordPeripheral,
|
|
IKnownSize {
|
|
private readonly DoubleWordRegisterCollection registers;
|
|
public ESP32_UART(Machine machine) : base(machine) {
|
|
registers = new DoubleWordRegisterCollection(this,
|
|
new Dictionary<long, DoubleWordRegister> {
|
|
{0x00, new DoubleWordRegister(this).WithValueField(0,8,
|
|
writeCallback: (_, v) => TransmitCharacter((byte)v))}
|
|
});
|
|
}</code></code>
|
|
</section>
|
|
<section>
|
|
<h2>Add a serial port</h2>
|
|
<pre><code>
|
|
{0x00, new DoubleWordRegister(this)
|
|
.WithValueField(0, 8,
|
|
writeCallback: (_, v) => TransmitCharacter((byte)v))}</code></pre>
|
|
</section>
|
|
<section>
|
|
<h2>Add a platform file</h2>
|
|
<pre><code>cpu1: CPU.Xtensa @ sysbus
|
|
cpuId: 1
|
|
cpuType: "esp32s3"
|
|
dram: Memory.MappedMemory @ sysbus 0x3FC88000
|
|
size: 0x78000
|
|
irom: Memory.MappedMemory @ sysbus 0x3FF00000
|
|
size: 0x20000
|
|
drom: Memory.MappedMemory @ sysbus 0x40000000
|
|
size: 0x60000
|
|
iram: Memory.MappedMemory @ sysbus 0x40370000
|
|
size: 0x70000
|
|
uart0: UART.ESP32_UART @ sysbus 0x60000000
|
|
</code></pre>
|
|
</section>
|
|
<section>
|
|
<img data-src="img/esp32s3-uart.png">
|
|
</section>
|
|
<section>
|
|
<h2>SVD Files Are Your Friend</h2>
|
|
<!-- <ul>
|
|
<li>Your chip probably comes with a SVD file</li>
|
|
<li>This gives a map of RAM and peripherals</li>
|
|
<li>Renode can parse this and use it for logging / defaults</li>
|
|
</ul> -->
|
|
<img data-src="img/svd-files.png">
|
|
</section>
|
|
<section>
|
|
<h2>Load SVD file</h2>
|
|
<pre><code>sysbus:
|
|
init:
|
|
ApplySVD @esp32s3.svd</code></pre>
|
|
</section>
|
|
<section>
|
|
<h2>Load SVD file</h2>
|
|
<pre><code style="word-wrap: break-word;">
|
|
sysbus: Read from an unimplemented register SYSTEM:SYSCLK_CONF
|
|
(0x600C0060), returning a value from SVD: 0x1. (3)
|
|
sysbus: Read from an unimplemented register SYSTEM:PERIP_CLK_EN0
|
|
(0x600C0018), returning a value from SVD: 0xF9C1E06F.
|
|
sysbus: Write of value 0xF9C1E06F to an unimplemented register
|
|
SYSTEM:PERIP_CLK_EN0 (0x600C0018) generated from SVD.
|
|
sysbus: Read from an unimplemented register SYSTEM:PERIP_RST_EN0
|
|
(0x600C0020), returning a value from SVD: 0x0.
|
|
sysbus: Write of value 0x0 to an unimplemented register SYSTEM:PERIP_RST_EN0
|
|
0x600C0020) generated from SVD.
|
|
sysbus: Read from an unimplemented register SYSTEM:PERIP_RST_EN0
|
|
(0x600C0020), returning a value from SVD: 0x0.
|
|
sysbus: Write of value 0x4 to an unimplemented register SYSTEM:PERIP_RST_EN0 (0x600C0020) generated from SVD.
|
|
</code></pre>
|
|
</section>
|
|
<section>
|
|
<h2>Add Peripherals</h2>
|
|
</section>
|
|
<section>
|
|
<h2>Slowly Advance</h2>
|
|
<img data-src="img/esp32s3-more-boot.png">
|
|
</section>
|
|
<section>
|
|
<h2>GDB with ELF</h2>
|
|
<img data-src="img/gdb-with-elf.png">
|
|
</section>
|
|
<section>
|
|
<h2>What's Left?</h2>
|
|
<ul>
|
|
<li>SPI Controller</li>
|
|
<li>Interrupt Controller</li>
|
|
<li>I2C Controller</li>
|
|
<li>Touch Controller</li>
|
|
<li>Display</li>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Displays</h2>
|
|
<ul>
|
|
<li>Implement <code>ISpiDevice</code></li>
|
|
<li>Subclass AutoRepaintingVideo</li>
|
|
<li>Implement <code>Repaint()</code></li>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Touch Controller</h2>
|
|
<ul>
|
|
<li>Possibly interact with the Display controller</li>
|
|
<li>Implement <code>II2CPeripheral</code></li>
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h2>Audio is Hard</h2>
|
|
<ul>
|
|
<li>Existing I2S peripherals just pattern-match audio</li>
|
|
</ul>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<h2>Getting involved</h2>
|
|
<ul>
|
|
<li>Try Renode for your projects!</li>
|
|
<li>Add CI tests for your firmware!</li>
|
|
<li>Explore binaries for unknown targets!</li>
|
|
</ul>
|
|
<h2 class="fragment">Thank you</h2>
|
|
<h3 class="fragment">Questions?</h3>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="dist/reveal.js"></script>
|
|
<script src="plugin/notes/notes.js"></script>
|
|
<script src="plugin/zoom/zoom.js"></script>
|
|
<script src="plugin/markdown/markdown.js"></script>
|
|
<script src="plugin/highlight/highlight.js"></script>
|
|
<script>
|
|
/** This used to be a part of Reveal.js, but was removed at some point */
|
|
function getQueryHash() {
|
|
function deserialize(value) {
|
|
if (typeof value === 'string') {
|
|
if (value === 'null') return null;
|
|
else if (value === 'true') return true;
|
|
else if (value === 'false') return false;
|
|
else if (value.match(/^-?[\d\.]+$/)) return parseFloat(value);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
let query = {};
|
|
location.search.replace(/[A-Z0-9]+?=([\w\.%-]*)/gi, a => {
|
|
query[a.split('=').shift()] = a.split('=').pop();
|
|
});
|
|
// Basic deserialization
|
|
for (let i in query) {
|
|
let value = query[i];
|
|
|
|
query[i] = deserialize(unescape(value));
|
|
}
|
|
|
|
// Do not accept new dependencies via query config to avoid
|
|
// the potential of malicious script injection
|
|
if (typeof query['dependencies'] !== 'undefined') delete query['dependencies'];
|
|
|
|
return query;
|
|
}
|
|
var presenter = !!getQueryHash().s;
|
|
var stream = !!getQueryHash().stream;
|
|
|
|
// More info about initialization & config:
|
|
// - https://revealjs.com/initialization/
|
|
// - https://revealjs.com/config/
|
|
reveal_dependencies = [
|
|
{ src: 'https://reveal-multiplex.glitch.me/socket.io/socket.io.js', async: true },
|
|
];
|
|
if (presenter) {
|
|
reveal_dependencies.push({ src: 'https://reveal-multiplex.glitch.me/master.js', async: true },);
|
|
} else {
|
|
reveal_dependencies.push({ src: 'https://reveal-multiplex.glitch.me/client.js', async: true });
|
|
}
|
|
Reveal.initialize({
|
|
hash: true,
|
|
|
|
controls: presenter ? false : (stream ? false : true),
|
|
progress: true,
|
|
history: true,
|
|
center: true,
|
|
controlsTutorial: presenter ? false : (stream ? false : true),
|
|
|
|
slideNumber: presenter ? null : (stream ? null : 'c/t'),
|
|
|
|
// The "normal" size of the presentation, aspect ratio will be preserved
|
|
// when the presentation is scaled to fit different resolutions. Can be
|
|
// specified using percentage units.
|
|
width: 1280,
|
|
height: 840,
|
|
|
|
// Factor of the display size that should remain empty around the content
|
|
margin: 0.1,
|
|
|
|
multiplex: {
|
|
// Example values. To generate your own, see the socket.io server instructions.
|
|
secret: getQueryHash().s || null,
|
|
id: '863f0948d18284f3',
|
|
url: 'https://p.xobs.io/'
|
|
},
|
|
|
|
|
|
// Bounds for smallest/largest possible scale to apply to content
|
|
minScale: 0.02,
|
|
maxScale: 5.5,
|
|
|
|
defaultTiming: 41,
|
|
|
|
transition: 'slide', // none/fade/slide/convex/concave/zoom
|
|
|
|
// Don't forget to add the dependencies
|
|
dependencies: reveal_dependencies,
|
|
|
|
// Learn about plugins: https://revealjs.com/plugins/
|
|
plugins: [RevealMarkdown, RevealHighlight, RevealZoom, RevealNotes]
|
|
});
|
|
</script>
|
|
</body>
|
|
|
|
</html> |