966 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			966 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!doctype html>
 | 
						|
<html>
 | 
						|
 | 
						|
<head>
 | 
						|
    <meta charset="utf-8">
 | 
						|
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
 | 
						|
 | 
						|
    <title>Renode: Easy CI for your Weird Hardware</title>
 | 
						|
 | 
						|
    <link rel="stylesheet" href="dist/reset.css">
 | 
						|
    <link rel="stylesheet" href="dist/reveal.css">
 | 
						|
    <link rel="stylesheet" href="dist/theme/fossasia2022.css">
 | 
						|
 | 
						|
    <!-- Theme used for syntax highlighted code -->
 | 
						|
    <link rel="stylesheet" href="plugin/highlight/zenburn.css">
 | 
						|
</head>
 | 
						|
 | 
						|
<!--
 | 
						|
* Emulators are useful tools
 | 
						|
    - PC emulator (e.g. Docker on Mac, WSL on Linux)
 | 
						|
    - NES emulator -- fun and games, realtime output
 | 
						|
        - Also have debugging emulators
 | 
						|
    - Renode
 | 
						|
 | 
						|
* Renode Stack
 | 
						|
    - CPU cores written in C
 | 
						|
        - arm, i386, ppc, riscv, sparc, xtensa
 | 
						|
    - Windows, Mac, Linux
 | 
						|
    - Peripherals and UI written in C#
 | 
						|
    - Extensible via Python and C#
 | 
						|
        - Write once. Run anywhere. Using C# to define new peripherals
 | 
						|
 | 
						|
* Three major users
 | 
						|
    - Designers of new boards
 | 
						|
    - Reverse engineering exsisting hardware
 | 
						|
    - Silicon designers
 | 
						|
 | 
						|
* Designers of new boards
 | 
						|
    - One or more chips
 | 
						|
    - How are they connected?
 | 
						|
    - What weird hardware exists?
 | 
						|
 | 
						|
    * Concurrent emulation of multiple devices
 | 
						|
        - Can connect multiple devices, e.g. via UART, GPIO, SPI, Ethernet, CAN...
 | 
						|
        - All devices are emulated using the same time source
 | 
						|
        - Helps to debug timing differences with different processors on a board
 | 
						|
    
 | 
						|
    * Board definition format
 | 
						|
        - Easily define memory layout
 | 
						|
        - Easily move blocks around
 | 
						|
        - Only define what's necessary
 | 
						|
        - You don't need to be perfect, just good enough!
 | 
						|
    
 | 
						|
    * Can read SVD files
 | 
						|
 | 
						|
    * Hardware has Similarities
 | 
						|
        - Picture of existing register sets
 | 
						|
        - There are only so many combinations
 | 
						|
        - Rip. Mix. Burn. Many chips are just copies of one another.
 | 
						|
 | 
						|
    * Tests in CI
 | 
						|
 | 
						|
* Reverse engineering existing hardware
 | 
						|
 | 
						|
    * If it's a supported architecture, it's easy to run code
 | 
						|
    * LoadBinary and set PC
 | 
						|
    * Can skip much of the boot ROM
 | 
						|
    * Attach GDB
 | 
						|
    * Reproducible makes it easy to test theories
 | 
						|
 | 
						|
* Developing new Silicon blocks
 | 
						|
 | 
						|
    * Betrusted hardware
 | 
						|
        - Create a new design in LiteX / Verilog
 | 
						|
        - Document the design
 | 
						|
        - Create a model
 | 
						|
        - Timing isn't as critical
 | 
						|
 | 
						|
-->
 | 
						|
 | 
						|
<body>
 | 
						|
    <div class="reveal">
 | 
						|
        <div class="footer">
 | 
						|
            <a class="url" href="https://p.xobs.io/fa22/">p.xobs.io/fa22</a>
 | 
						|
        </div>
 | 
						|
        <div class="slides">
 | 
						|
            <section>
 | 
						|
                <section>
 | 
						|
                    <h2>Renode: Easy Emulation for your Weird Hardware</h2>
 | 
						|
                    <h3>Sean Cross</h3>
 | 
						|
                    <p>Follow along at <a href="https://p.xobs.io/fa22">https://p.xobs.io/fa22</a></p>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>About Me: I Do Weird Hardware</h2>
 | 
						|
                    <ul>
 | 
						|
                        <!-- <li>Betrusted/Precursor: FPGA Secure Communications</li>
 | 
						|
                            <li>Fomu: World's Smallest FPGA Dev Board</li>
 | 
						|
                            <li>Chibitronics: Loading programs via audio</li> -->
 | 
						|
                        <img src="media/xobs-projects.jpg">
 | 
						|
                    </ul>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Renode</h2>
 | 
						|
                    <p>I find it a useful tool. Maybe you will, too!</p>
 | 
						|
                    <img height="100" src="media/antmicro-logo-white.svg">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>What is "Weird Hardware"?</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>Hardware that there is only one of (because you just made it)</li>
 | 
						|
                        <li>Hardware that you're trying to understand</li>
 | 
						|
                        <li>Hardware that uses ARM, i386, PowerPC, Risc-V, Sparc, or Xtensa</li>
 | 
						|
                    </ul>
 | 
						|
                </section>
 | 
						|
                <!-- <section>
 | 
						|
                    <h2>Hardware is Nothing Without Software</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>Software needs to be written</li>
 | 
						|
                        <li class="fragment">Software needs to be <strong>tested</strong></li>
 | 
						|
                        <li class="fragment">Software needs to be <i>debugged</i></li>
 | 
						|
                    </ul>
 | 
						|
                </section> -->
 | 
						|
                <section>
 | 
						|
                    <h2>About Renode</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>Multi-Node Emulator</li>
 | 
						|
                        <li>Extensible with C# and Python</li>
 | 
						|
                        <li>Windows, Mac, Linux</li>
 | 
						|
                        <li>MIT Licensed</li>
 | 
						|
                    </ul>
 | 
						|
                    <img src="media/renode-console.png">
 | 
						|
                </section>
 | 
						|
                <!-- <section>
 | 
						|
                    <h2>Who Might Find This Talk Interesting?</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>Creators</li>
 | 
						|
                        <li>Integrators</li>
 | 
						|
                        <li>Reverse Engineers</li>
 | 
						|
                    </ul>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Creators: Making New Things!</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>Reusing an existing platform</li>
 | 
						|
                        <li>Reusing an existing microcontroller</li>
 | 
						|
                        <li>New microcontroller from existing family</li>
 | 
						|
                        <li>New microcontroller with a common CPU</li>
 | 
						|
                    </ul>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Integrators: Making Sure Nothing Broke!</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>Hardware testing incompatible with cloud</li>
 | 
						|
                        <ul>
 | 
						|
                            <li>...it sure is effective, though</li>
 | 
						|
                        </ul>
 | 
						|
                        <li>Hardware crunch makes it difficult to get hardware</li>
 | 
						|
                        <li>Downloading software is much cheaper than shipping</li>
 | 
						|
                    </ul>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Reverse Engineers: What Is This Blob Doing?</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>Staring at code flow is enlightening, but time-consuming</li>
 | 
						|
                        <li>What is it doing and how does it get there?</li>
 | 
						|
                    </ul>
 | 
						|
                    <img src="media/bluenrg-ghidra-trace.png" class="fragment">
 | 
						|
                </section> -->
 | 
						|
            </section>
 | 
						|
            <section>
 | 
						|
                <section>
 | 
						|
                    <h2>What Is an Emulator?</h2>
 | 
						|
                </section>
 | 
						|
                <section data-transition="slide-in fade-out">
 | 
						|
                    <h2>Whole-System Emulator</h2>
 | 
						|
                    <img src="media/fceux-smb.png">
 | 
						|
                    <!--
 | 
						|
                    <ul>
 | 
						|
                        <li>Wii Virtual Console</li>
 | 
						|
                        <li>VirtualBox</li>
 | 
						|
                        <li>Parallels</li>
 | 
						|
                    </ul>
 | 
						|
                    -->
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade-in">
 | 
						|
                    <h2>Whole-System Emulator</h2>
 | 
						|
                    <img src="media/fceux-smb-debug.png">
 | 
						|
                    <!--
 | 
						|
                    <ul>
 | 
						|
                        <li>Wii Virtual Console</li>
 | 
						|
                        <li>VirtualBox</li>
 | 
						|
                        <li>Parallels</li>
 | 
						|
                    </ul>
 | 
						|
                    -->
 | 
						|
                </section>
 | 
						|
                <!-- <section>
 | 
						|
                    <h2>Transparent Emulator</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>WSL2/Docker</li>
 | 
						|
                        <li>qemu on Linux</li>
 | 
						|
                        <li>Rosetta on Mac</li>
 | 
						|
                    </ul>
 | 
						|
                </section> -->
 | 
						|
                <section data-transition="slide-in fade-out">
 | 
						|
                    <h2>What is an Emulator?</h2>
 | 
						|
                    <img class="fragment" src="media/bbs-example.png">
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade">
 | 
						|
                    <h2>What is an Emulator?</h2>
 | 
						|
                    <img src="media/DEC_VT100_terminal_cropped.jpg">
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade-in slide-out">
 | 
						|
                    <h2>What is an Emulator?</h2>
 | 
						|
                    <img src="media/vt100-MA-4352.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Emulation Depends on your Goals!</h2>
 | 
						|
                    <p class="fragment">Emulation is a lie</p>
 | 
						|
                </section>
 | 
						|
                <!-- <section>
 | 
						|
                    <h2>Renode Is Many of These</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>Console: Able to present an interactive environment</li>
 | 
						|
                        <li>Transparent: Can run in CI via Robot commands</li>
 | 
						|
                        <li>Debugger: Has a GDB server built in</li>
 | 
						|
                    </ul>
 | 
						|
                </section> -->
 | 
						|
            </section>
 | 
						|
 | 
						|
            <section>
 | 
						|
                <section data-transition="slide-in fade-out">
 | 
						|
                    <h2>What is a Computer?</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>A system of devices</li>
 | 
						|
                        <li>One or more processors</li>
 | 
						|
                        <li>One or more buses</li>
 | 
						|
                        <li>One or more blocks of memory</li>
 | 
						|
                        <li>Some I/O</li>
 | 
						|
                    </ul>
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade-out">
 | 
						|
                    <h2>What is a Computer?</h2>
 | 
						|
                    <img src="media/bluenrg-block-diagram.png">
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade">
 | 
						|
                    <h2>What is a Computer?</h2>
 | 
						|
                    <img src="media/bluenrg-block-diagram-no-extra-bits.png">
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade">
 | 
						|
                    <h2>What is a Computer?</h2>
 | 
						|
                    <img src="media/bluenrg-block-diagram-cpu.png">
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade">
 | 
						|
                    <h2>What is a Computer?</h2>
 | 
						|
                    <img src="media/bluenrg-block-diagram-memories.png">
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade-in">
 | 
						|
                    <h2>What is a Computer?</h2>
 | 
						|
                    <img src="media/bluenrg-block-diagram-peripherals.png">
 | 
						|
                </section>
 | 
						|
                <!-- <section>
 | 
						|
                    <h2>What is a Computer?</h2>
 | 
						|
                    <img src="media/bluenrg-peripherals.png">
 | 
						|
                </section> -->
 | 
						|
                <section>
 | 
						|
                    <h2>What is a Computer?</h2>
 | 
						|
                    <img src="media/bluenrg-memory-map.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>What is a Computer?</h2>
 | 
						|
                    <img src="media/conceptual-diagram.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Defining a Computer in Renode</h2>
 | 
						|
                    <pre><code data-trim data-line-numbers="|1-5|7-10|12-13">
 | 
						|
                        flash: Memory.MappedMemory @ sysbus 0x00000000
 | 
						|
                            size: 0x00008000
 | 
						|
 | 
						|
                        sram: Memory.MappedMemory @ sysbus 0x20000000
 | 
						|
                            size: 0x00001000
 | 
						|
                            
 | 
						|
                        cpu: CPU.CortexM @ sysbus
 | 
						|
                            cpuType: "cortex-m0+"
 | 
						|
                            PerformanceInMips: 24
 | 
						|
                            nvic: nvic
 | 
						|
    
 | 
						|
                        nvic: IRQControllers.NVIC @ sysbus 0xE000E000
 | 
						|
                            IRQ -> cpu@0
 | 
						|
                    </code></pre>
 | 
						|
                    bluenrg-1.repl
 | 
						|
                </section>
 | 
						|
            </section>
 | 
						|
 | 
						|
            <section>
 | 
						|
                <h2>That's Nice, but What About...</h2>
 | 
						|
                <ol>
 | 
						|
                    <li>Loading firmware?</li>
 | 
						|
                    <li>Adding peripherals?</li>
 | 
						|
                </ol>
 | 
						|
            </section>
 | 
						|
 | 
						|
            <section>
 | 
						|
                <section>
 | 
						|
                    <h2>What is "Firmware"?</h2>
 | 
						|
                    <blockquote class="fragment strike">Firmware is a series of instructions executed by the CPU in
 | 
						|
                        order to accomplish a task</blockquote>
 | 
						|
                    <blockquote class="fragment">Firmware is Memory</blockquote>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Loading Firmware in Renode</h2>
 | 
						|
                    <pre><code data-trim>
 | 
						|
                        sysbus LoadELF @firmware.elf
 | 
						|
                    </code></pre>
 | 
						|
                    <pre class="fragment"><code data-trim>
 | 
						|
                        sysbus LoadBinary @rom.bin 0x20000000
 | 
						|
                    </code></pre>
 | 
						|
                    <!-- <pre class="fragment"><code data-trim>
 | 
						|
                        sysbus LoadSymbolsFrom @rom.elf
 | 
						|
                    </code></pre> -->
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>How does Renode Interact With $VENDOR_TOOL?</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>Hopefully your vendor tool produces ELF files</li>
 | 
						|
                        <li class="fragment">HEX? BIN? Just use <code>LoadBinary</code>!
 | 
						|
                        <li class="fragment">Custom firmware format? Need to unpack first.</li>
 | 
						|
                        </li>
 | 
						|
                    </ul>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>What About Boot ROMs?</h2>
 | 
						|
                    <ol>
 | 
						|
                        <li class="fragment strike semi-fade-out" data-fragment-index="1">Initialize peripherals</li>
 | 
						|
                        <li class="fragment strike semi-fade-out" data-fragment-index="1">Check for boot override</li>
 | 
						|
                        <li class="fragment strike semi-fade-out" data-fragment-index="1">Check for low-power state</li>
 | 
						|
                        <li class="fragment strike semi-fade-out" data-fragment-index="1">Load firmware into RAM</li>
 | 
						|
                        <li class="fragment strike semi-fade-out" data-fragment-index="1">Validate firmware</li>
 | 
						|
                        <li>Jump to loaded program</li>
 | 
						|
                    </ol>
 | 
						|
                    <pre class="fragment"><code data-trim>
 | 
						|
                        sysbus LoadBinary @rom.bin 0x20000000
 | 
						|
                        sysbus.cpu VectorTableOffset 0x20000000
 | 
						|
                        sysbus.cpu SP `sysbus ReadDoubleWord 0x20000000`
 | 
						|
                        sysbus.cpu PC `sysbus ReadDoubleWord 0x20000004`
 | 
						|
                        start
 | 
						|
                    </code></pre>
 | 
						|
                </section>
 | 
						|
            </section>
 | 
						|
            <section>
 | 
						|
                <section>
 | 
						|
                    <h2>What about New Peripherals?</h2>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>It's All About Small Victories</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>Serial ports are super rewarding</li>
 | 
						|
                        <li>They're also usually simple!</li>
 | 
						|
                        <li>They are easy to script</li>
 | 
						|
                    </ul>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>What is a Computer?</h2>
 | 
						|
                    <img src="media/bluenrg-memory-map.png">
 | 
						|
                </section>
 | 
						|
                <section data-transition="slide-in fade-out">
 | 
						|
                    <h2>What is a Register?</h2>
 | 
						|
                    <img src="media/pl011-bluenrg.png">
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade">
 | 
						|
                    <h2>What is a Register?</h2>
 | 
						|
                    <img src="media/pl011-bluenrg-field.png">
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade">
 | 
						|
                    <h2>What is a Register?</h2>
 | 
						|
                    <img src="media/pl011-bluenrg.png">
 | 
						|
                    <img class="fragment" src="media/pl011-cc2538-cropped.png">
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade">
 | 
						|
                    <h2>What is a Register?</h2>
 | 
						|
                    <img src="media/pl011-bcm2835-cropped.png">
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade-in">
 | 
						|
                    <h2>What is a Register?</h2>
 | 
						|
                    <img src="media/pl011-arm.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Reuse an Existing Block!</h2>
 | 
						|
                    <pre data-id="code-animation"><code data-trim data-line-numbers="|10-12">
 | 
						|
                        flash: Memory.MappedMemory @ sysbus 0x00000000
 | 
						|
                            size: 0x00008000
 | 
						|
 | 
						|
                        sram: Memory.MappedMemory @ sysbus 0x20000000
 | 
						|
                            size: 0x00001000
 | 
						|
                            
 | 
						|
                        nvic: IRQControllers.NVIC @ sysbus 0xE000E000
 | 
						|
                            IRQ -> cpu@0
 | 
						|
 | 
						|
                        // 👇 Add a UART with IRQ #10 at address 0x40300000
 | 
						|
                        uart: UART.PL011 @ sysbus 0x40300000
 | 
						|
                            -> nvic@10
 | 
						|
                    
 | 
						|
                        cpu: CPU.CortexM @ sysbus
 | 
						|
                            nvic: nvic
 | 
						|
                            cpuType: "cortex-m0+"
 | 
						|
                            PerformanceInMips: 24
 | 
						|
                    </code></pre>
 | 
						|
                    bluenrg-1.repl
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Setting up Renode</h2>
 | 
						|
                    <pre data-id="code-animation"><code data-trim data-line-numbers="|1|2|3-5|6|">
 | 
						|
                        machine LoadPlatformDescription @bluenrg-1.repl
 | 
						|
                        sysbus LoadBinary @BLE_Chat_Server.bin 0x10040000
 | 
						|
                        cpu VectorTableOffset 0x10040000
 | 
						|
                        cpu SP `sysbus ReadDoubleWord 0x10040000`
 | 
						|
                        cpu PC `sysbus ReadDoubleWord 0x10040004`
 | 
						|
                        start
 | 
						|
                    </code></pre>
 | 
						|
                    <p class="fragment">BlueNRG-1.resc</p>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Output Success!</h2>
 | 
						|
                    <img src="media/bluenrg-renode-uart.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Always Check for Block Reuse</h2>
 | 
						|
                    Blocks are frequently reused across designs, and can save you from having to reimplement
 | 
						|
                    everything from scratch!
 | 
						|
                </section>
 | 
						|
                <!-- <section>
 | 
						|
                    <h2>What if we need to write it ourselves?</h2>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Steps to Set Up a Serial Port</h2>
 | 
						|
                    <ol>
 | 
						|
                        <li class="fragment strike semi-fade-out" data-fragment-index="1">Enable peripheral</li>
 | 
						|
                        <li class="fragment strike semi-fade-out" data-fragment-index="1">Set up clock</li>
 | 
						|
                        <li class="fragment strike semi-fade-out" data-fragment-index="1">Mux GPIOs</li>
 | 
						|
                        <li class="fragment strike semi-fade-out" data-fragment-index="1">Calculate baud rate</li>
 | 
						|
                        <li>Write to UART TX register</li>
 | 
						|
                        <li>Read from UART RX register</li>
 | 
						|
                    </ol>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Steps to Set Up a Serial Port</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>Interrupt Support</li>
 | 
						|
                        <ul>
 | 
						|
                            <li>Handled as a GPIO within the peripheral</li>
 | 
						|
                        </ul>
 | 
						|
                        <li>DMA</li>
 | 
						|
                        <ul>
 | 
						|
                            <li>Handled as a different peripheral</li>
 | 
						|
                        </ul>
 | 
						|
                    </ul>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Modify an Existing Block</h2>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Example Serial Port: AxiUartLite</h2>
 | 
						|
                    <pre class="code-animation"><code class="cs" data-trim data-line-numbers="|80-83|55-61|35-45|39-45">
 | 
						|
                        //
 | 
						|
                        // Copyright (c) 2010-2018 Antmicro
 | 
						|
                        //
 | 
						|
                        // This file is licensed under the MIT License.
 | 
						|
                        // Full license text is available in 'licenses/MIT.txt'.
 | 
						|
                        //
 | 
						|
                        using System;
 | 
						|
                        using Antmicro.Renode.Peripherals.Bus;
 | 
						|
                        using System.Collections.Generic;
 | 
						|
                        using Antmicro.Renode.Core;
 | 
						|
                        using Antmicro.Renode.Logging;
 | 
						|
                        using Antmicro.Renode.Peripherals.Miscellaneous;
 | 
						|
                        using Antmicro.Migrant;
 | 
						|
                        
 | 
						|
                        namespace Antmicro.Renode.Peripherals.UART
 | 
						|
                        {
 | 
						|
                            [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)]
 | 
						|
                            public class AxiUartLite : IDoubleWordPeripheral, IUART, IKnownSize
 | 
						|
                            {
 | 
						|
                                public AxiUartLite()
 | 
						|
                                {
 | 
						|
                                    readFifo = new Queue<uint>();
 | 
						|
                                }
 | 
						|
                        
 | 
						|
                                public void WriteChar(byte value)
 | 
						|
                                {
 | 
						|
                                    readFifo.Enqueue(value);
 | 
						|
                                }
 | 
						|
                        
 | 
						|
                                public void Reset()
 | 
						|
                                {
 | 
						|
                                    readFifo.Clear();
 | 
						|
                                }
 | 
						|
                        
 | 
						|
                                public uint ReadDoubleWord(long offset)
 | 
						|
                                {
 | 
						|
                                    switch((Register)offset)
 | 
						|
                                    {
 | 
						|
                                    case Register.RxFIFO:
 | 
						|
                                        if(readFifo.Count == 0)
 | 
						|
                                        {
 | 
						|
                                            this.Log(LogLevel.Warning, "Trying to read from empty fifo.");
 | 
						|
                                            return 0;
 | 
						|
                                        }
 | 
						|
                                        return readFifo.Dequeue();
 | 
						|
                                    case Register.Status:
 | 
						|
                                        // Tx FIFO Empty | Rx FIFO Valid Data
 | 
						|
                                        return (1u << 2) | (readFifo.Count == 0 ? 0 : 1u);
 | 
						|
                                    default:
 | 
						|
                                        this.LogUnhandledRead(offset);
 | 
						|
                                        return 0;
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                        
 | 
						|
                                public void WriteDoubleWord(long offset, uint value)
 | 
						|
                                {
 | 
						|
                                    switch((Register)offset)
 | 
						|
                                    {
 | 
						|
                                    case Register.TxFIFO:
 | 
						|
                                        CharReceived?.Invoke((byte)value);
 | 
						|
                                        break;
 | 
						|
                                    default:
 | 
						|
                                        this.LogUnhandledWrite(offset, value);
 | 
						|
                                        break;
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                        
 | 
						|
                                [field: Transient]
 | 
						|
                                public event Action<byte> CharReceived;
 | 
						|
                        
 | 
						|
                                public long Size { get { return 0x10; } }
 | 
						|
                                public Bits StopBits { get { return Bits.One; } }
 | 
						|
                                public Parity ParityBit { get { return Parity.None; } }
 | 
						|
                                public uint BaudRate { get { return 0; } }
 | 
						|
                        
 | 
						|
                                private readonly Queue<uint> readFifo;
 | 
						|
                        
 | 
						|
                                private enum Register
 | 
						|
                                {
 | 
						|
                                    RxFIFO = 0x0,
 | 
						|
                                    TxFIFO = 0x4,
 | 
						|
                                    Status = 0x8,
 | 
						|
                                    Control = 0xC
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                        }                        
 | 
						|
                    </code></pre>
 | 
						|
                    AxiUartLite.cs
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Steps to Set Up a Serial Port</h2>
 | 
						|
                    <img src="media/renode-xous-kernel-uart.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>What about Missing Definitions?</h2>
 | 
						|
                    <ul>
 | 
						|
                        <li>Most registers are unused</li>
 | 
						|
                        <ul>
 | 
						|
                            <li>Start/Stop bits</li>
 | 
						|
                            <li>One-wire mode</li>
 | 
						|
                            <li>Infrared mode</li>
 | 
						|
                        </ul>
 | 
						|
                        <li class="fragment">Most writes can be ignored</li>
 | 
						|
                    </ul>
 | 
						|
                </section> -->
 | 
						|
                <section>
 | 
						|
                    <h2>Peripheral Rapid Development</h2>
 | 
						|
                    <img src="media/hardware-20191117-cropped.jpg">
 | 
						|
                    Betrusted Prototype
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Peripheral Documentation</h2>
 | 
						|
                    <img class="r-stretch" src="media/betrusted-soc-manual.png">
 | 
						|
                    <a href="https://ci.betrusted.io/betrusted-soc/doc/">ci.betrusted.io/betrusted-soc/doc/</a>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Peripheral Rapid Development</h2>
 | 
						|
                    <video class="r-stretch" data-autoplay src="media/Renode-20191117-trimmed.m4v"></video>
 | 
						|
                    <p>Hackaday Supercon 2019</p>
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade-out">
 | 
						|
                    <h2>Advantages of Emulation</h2>
 | 
						|
                    <img class="r-stretch" src="media/betrusted-soc-uart-mux.png">
 | 
						|
                </section>
 | 
						|
                <section data-transition="fade-in">
 | 
						|
                    <h2>Advantages of Emulation</h2>
 | 
						|
                    <img src="media/renode-xous-double-uart-tiled.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Getting Hardware to Users</h2>
 | 
						|
                    <img src="media/betrusted-engine-block-diagram.png" class="r-stretch">
 | 
						|
                    <p>Betrusted ENGINE</p>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Getting Hardware to Users</h2>
 | 
						|
                    <img src="media/betrusted-wycheproof-patch.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Getting Hardware to Users</h2>
 | 
						|
                    <img src="media/betrusted-wycheproof-patch-fix.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Emulation brings more eyes to the project</h2>
 | 
						|
                </section>
 | 
						|
            </section>
 | 
						|
            <section>
 | 
						|
                <section>
 | 
						|
                    <h2>Robot Framework: Running Tests in CI</h2>
 | 
						|
                    <pre class="code-animation"><code class="robot" data-trim data-line-numbers="|1-6|8-18|20-26|28-40|39-40">
 | 
						|
                            *** Settings ***
 | 
						|
                                Suite Setup                   Setup
 | 
						|
                                Suite Teardown                Teardown
 | 
						|
                                Test Setup                    Reset Emulation
 | 
						|
                                Test Teardown                 Test Teardown
 | 
						|
                                Resource                      ${RENODEKEYWORDS}
 | 
						|
                                
 | 
						|
                            *** Variables ***
 | 
						|
                                ${UART}   sysbus.uart0
 | 
						|
                                ${URI}    @https://dl.antmicro.com/projects/renode
 | 
						|
                                
 | 
						|
                                ${LIS2DS12}=     SEPARATOR=
 | 
						|
                                ...  """                                         ${\n}
 | 
						|
                                ...  using "platforms/cpus/nrf52840.repl"        ${\n}
 | 
						|
                                ...                                              ${\n}
 | 
						|
                                ...  lis2ds12: Sensors.LIS2DS12 @ twi1 0x1c      ${\n}
 | 
						|
                                ...  ${SPACE*4}IRQ -> gpio0@28                   ${\n}
 | 
						|
                                ...  """
 | 
						|
 | 
						|
                            *** Keywords ***
 | 
						|
                            Create Machine
 | 
						|
                                Execute Command  mach create
 | 
						|
                                Execute Command  machine 
 | 
						|
                                ...    LoadPlatformDescriptionFromString ${LIS2DS12}
 | 
						|
                                Execute Command  sysbus LoadELF 
 | 
						|
                                ...    ${URI}/nrf52840--zephyr_lis2dh.elf
 | 
						|
 | 
						|
                            *** Test Cases ***
 | 
						|
                            Should Read Acceleration
 | 
						|
                                Create Machine
 | 
						|
                                Create Terminal Tester    ${UART}
 | 
						|
                            
 | 
						|
                                Execute Command  sysbus.twi1.lis2ds12 AccelerationX 10
 | 
						|
                                Execute Command  sysbus.twi1.lis2ds12 AccelerationY 5
 | 
						|
                                Execute Command  sysbus.twi1.lis2ds12 AccelerationZ -5
 | 
						|
                            
 | 
						|
                                Start Emulation
 | 
						|
                            
 | 
						|
                                Wait For Line On Uart  
 | 
						|
                                ...     x 9.997213 , y 4.997410 , z -4.999803
 | 
						|
                    </code></pre>
 | 
						|
                    <p>LIS2DS12.robot</p>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Github Actions</h2>
 | 
						|
                    <img src="media/renode-ci-test.png">
 | 
						|
                </section>
 | 
						|
            </section>
 | 
						|
            <section>
 | 
						|
                <section>
 | 
						|
                    <h2>Renode for Reverse Engineering</h2>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>SVD: Standard Chip Documentation</h2>
 | 
						|
                    <pre class="code-animation"><code class="xml" data-trim data-line-numbers="|3-9|25-87|27-31|31|39-57|41|43|48-56|46"><script type="text/template">
 | 
						|
                        <?xml version='1.0' encoding='utf-8'?>
 | 
						|
                        <device xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" schemaVersion="1.1" xsi:noNamespaceSchemaLocation="CMSIS-SVD_Schema_1_1_draft.xsd">
 | 
						|
                            <vendor>STMicroelectronics</vendor>
 | 
						|
                            <vendorID>ST</vendorID>
 | 
						|
                            <name>BlueNRG2</name>
 | 
						|
                            <series>BlueNRG1</series>
 | 
						|
                            <version>1.0.0</version>
 | 
						|
                            <description>ARM 32-bit Cortex-M0 Microcontroller based device, CPU clock up to 32MHz</description>
 | 
						|
                            <licenseText>License</licenseText>
 | 
						|
                            <cpu>
 | 
						|
                                <name>CM0</name>
 | 
						|
                                <revision>r0p0</revision>
 | 
						|
                                <endian>little</endian>
 | 
						|
                                <mpuPresent>false</mpuPresent>
 | 
						|
                                <fpuPresent>false</fpuPresent>
 | 
						|
                                <nvicPrioBits>2</nvicPrioBits>
 | 
						|
                                <vendorSystickConfig>false</vendorSystickConfig>
 | 
						|
                            </cpu>
 | 
						|
                            <addressUnitBits>8</addressUnitBits>
 | 
						|
                            <width>32</width>
 | 
						|
                            <size>32</size>
 | 
						|
                            <access>read-write</access>
 | 
						|
                            <resetValue>0x00000000</resetValue>
 | 
						|
                            <resetMask>0xFFFFFFFF</resetMask>
 | 
						|
                            <peripherals>
 | 
						|
                                <peripheral>
 | 
						|
                                    <name>RNG</name>
 | 
						|
                                    <version>1.0</version>
 | 
						|
                                    <description>RNG</description>
 | 
						|
                                    <groupName>RNG</groupName>
 | 
						|
                                    <baseAddress>0xB0000000</baseAddress>
 | 
						|
                                    <size>32</size>
 | 
						|
                                    <access>read-write</access>
 | 
						|
                                    <addressBlock>
 | 
						|
                                        <offset>0</offset>
 | 
						|
                                        <size>0x1000</size>
 | 
						|
                                        <usage>registers</usage>
 | 
						|
                                    </addressBlock>
 | 
						|
                                    <registers>
 | 
						|
                                        <register>
 | 
						|
                                            <name>CR</name>
 | 
						|
                                            <description>RNG configuration register</description>
 | 
						|
                                            <addressOffset>0x00</addressOffset>
 | 
						|
                                            <size>32</size>
 | 
						|
                                            <access>read-write</access>
 | 
						|
                                            <resetValue>0x00000000</resetValue>
 | 
						|
                                            <resetMask>0x0000FFFF</resetMask>
 | 
						|
                                            <fields>
 | 
						|
                                                <field>
 | 
						|
                                                    <name>DIS</name>
 | 
						|
                                                    <description>Set the state of the random number generator.<ul><li>0: RNG is enable.</li><li>1: RNG is disabled. The internal free-running oscillators are put in power-down mode and the RNG clock is stopped at the input of the block.</li></ul></description>
 | 
						|
                                                    <bitOffset>2</bitOffset>
 | 
						|
                                                    <bitWidth>1</bitWidth>
 | 
						|
                                                    <access>read-write</access>
 | 
						|
                                                </field>
 | 
						|
                                            </fields>
 | 
						|
                                        </register>
 | 
						|
                                        <register>
 | 
						|
                                            <name>SR</name>
 | 
						|
                                            <description>RNG status register</description>
 | 
						|
                                            <addressOffset>0x04</addressOffset>
 | 
						|
                                            <size>32</size>
 | 
						|
                                            <access>read-only</access>
 | 
						|
                                            <resetValue>0x00000000</resetValue>
 | 
						|
                                            <resetMask>0x0000FFFF</resetMask>
 | 
						|
                                            <fields>
 | 
						|
                                                <field>
 | 
						|
                                                    <name>RDY</name>
 | 
						|
                                                    <description>New random value ready.<ul><li>0: The RNG_VAL register value is not yet valid. If performing a read access to VAL, the host will be put on hold (by wait-states insertion on the AHB bus) until a random value is available.</li><li>1: The VAL register contains a valid random number.</li></ul>This bit remains at 0 when the RNG is disabled (RNGDIS bit = 1b in CR)</description>
 | 
						|
                                                    <bitOffset>0</bitOffset>
 | 
						|
                                                    <bitWidth>1</bitWidth>
 | 
						|
                                                    <access>read-only</access>
 | 
						|
                                                </field>
 | 
						|
                                            </fields>
 | 
						|
                                        </register>
 | 
						|
                                        <register>
 | 
						|
                                            <name>VAL</name>
 | 
						|
                                            <description>RNG 16 bit random value</description>
 | 
						|
                                            <addressOffset>0x08</addressOffset>
 | 
						|
                                            <size>32</size>
 | 
						|
                                            <access>read-only</access>
 | 
						|
                                            <resetValue>0x00000000</resetValue>
 | 
						|
                                            <resetMask>0x0000FFFF</resetMask>
 | 
						|
                                        </register>
 | 
						|
                                        </registers>
 | 
						|
                                </peripheral>
 | 
						|
                            </peripherals>
 | 
						|
                        </device>
 | 
						|
                    </script></code></pre>
 | 
						|
                    <p>BlueNRG2.svd</p>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>SVD: Using with Renode</h2>
 | 
						|
                    <pre class="code-animation"><code data-trim>
 | 
						|
                        sysbus ApplySVD @BlueNRG2.svd
 | 
						|
                    </code></pre>
 | 
						|
                    <img class="fragment" src="media/bluenrg-renode-svd.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Logging Memory Accesses</h2>
 | 
						|
                    <img src="media/renode-betrusted-log.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Debugging with GDB</h2>
 | 
						|
                    <img src="media/renode-start-gdb.png">
 | 
						|
                    <img class="fragment" src="media/renode-connect-gdb.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Creating ELF Files</h2>
 | 
						|
                    <img src="media/ghidra-decompile.png">
 | 
						|
                </section>
 | 
						|
            </section>
 | 
						|
            <section>
 | 
						|
                <section>
 | 
						|
                    <h2>Multi-System Emulation</h2>
 | 
						|
                    <img src="media/betrusted-ec-com-1.png">
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Multi-System Emulation</h2>
 | 
						|
                    <img src="media/renode-multi-system.png">
 | 
						|
                </section>
 | 
						|
            </section>
 | 
						|
            <section>
 | 
						|
                <section>
 | 
						|
                    <h2>Other Things Renode can Do</h2>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Loading Peripherals at Runtime</h2>
 | 
						|
                    <pre><code data-trim data-line-numbers="|1|2">
 | 
						|
                    path add $ORIGIN
 | 
						|
                    i @peripherals/trng_server.cs
 | 
						|
                </code></pre>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Loading Peripherals at Runtime</h2>
 | 
						|
                    <pre><code class="cs" data-trim data-line-numbers="|1-10|12-28|14-19|20-27">
 | 
						|
                        private enum Registers
 | 
						|
                        {
 | 
						|
                            STATUS = 0x0,
 | 
						|
                            DATA = 0x4,
 | 
						|
                            URANDOM = 0x8,
 | 
						|
                            URANDOM_VALID = 0xc,
 | 
						|
                            EV_STATUS = 0x10,
 | 
						|
                            EV_PENDING = 0x14,
 | 
						|
                            EV_ENABLE = 0x18,
 | 
						|
                        }
 | 
						|
 | 
						|
                        private void DefineRegisters()
 | 
						|
                        {
 | 
						|
                            Registers.STATUS.Define(this) // RDY is set on reset
 | 
						|
                                .WithFlag(0, name: "ready",
 | 
						|
                                    valueProviderCallback: _ => true)
 | 
						|
                                .WithFlag(1, name: "avail",
 | 
						|
                                    valueProviderCallback: _ => true)
 | 
						|
                            ;
 | 
						|
                            Registers.DATA.Define(this)
 | 
						|
                                .WithValueField(0, 32, FieldMode.Read,
 | 
						|
                                    valueProviderCallback: _ =>
 | 
						|
                                    {
 | 
						|
                                        return (uint)rng.Next();
 | 
						|
                                    },
 | 
						|
                                    name: "DATA"
 | 
						|
                            );
 | 
						|
                        }
 | 
						|
                    </code></pre>
 | 
						|
                    From trng_server.cs
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Visual Studio Code Lens</h2>
 | 
						|
                    <img src="media/renode-vscode.png">
 | 
						|
                    <p>Auto-complete and contextual popups</p>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Networking with Tap</h2>
 | 
						|
                    <pre><code data-trim data-line-numbers="|1|2|3-4">
 | 
						|
                        emulation CreateSwitch "switch"
 | 
						|
                        emulation CreateTap "renodetap" "tap"
 | 
						|
                        connector Connect host.tap switch
 | 
						|
                        connector Connect sysbus.wifi.wf200 switch
 | 
						|
                    </code></pre>
 | 
						|
                </section>
 | 
						|
                <section>
 | 
						|
                    <h2>Networking with Tap</h2>
 | 
						|
                    <img src="media/renode-networking.png">
 | 
						|
                    <p>SoC → <em><strong>COM-SOC</strong></em> → COM → <em><strong>COM-EC</strong></em> → EC →
 | 
						|
                        <em><strong>EC-WIFI</strong></em> → WF200 → Tap → Internet
 | 
						|
                    </p>
 | 
						|
                </section>
 | 
						|
            </section>
 | 
						|
            <section>
 | 
						|
                <h2>Renode is Free Software</h2>
 | 
						|
                Give it a try!
 | 
						|
            </section>
 | 
						|
            <section>
 | 
						|
                <h2>Thank you for joining</h2>
 | 
						|
                <h3>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 type="text/javascript" src="js/robot.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: 'ef4a6dfa448e19c1',
 | 
						|
                url: 'https://p.xobs.io/'
 | 
						|
            },
 | 
						|
 | 
						|
 | 
						|
            // Bounds for smallest/largest possible scale to apply to content
 | 
						|
            minScale: 0.02,
 | 
						|
            maxScale: 5.5,
 | 
						|
 | 
						|
            transition: 'slide', // none/fade/slide/convex/concave/zoom
 | 
						|
 | 
						|
            highlight: {
 | 
						|
                beforeHighlight: hljs => hljs.registerLanguage('robot', window.hljsDefineRobot)
 | 
						|
            },
 | 
						|
 | 
						|
            // Don't forget to add the dependencies
 | 
						|
            dependencies: reveal_dependencies,
 | 
						|
 | 
						|
            // Learn about plugins: https://revealjs.com/plugins/
 | 
						|
            plugins: [RevealMarkdown, RevealHighlight, RevealZoom]
 | 
						|
        });
 | 
						|
 | 
						|
 | 
						|
    </script>
 | 
						|
</body>
 | 
						|
 | 
						|
</html> |