RISC-V Assembly Language Programming using ESP32-C3 and QEMU (Extract)

Page 1

RISC-V

Language

books
Warren Gay
Assembly
Programming Using the ESP32-C3 and QEMU

RISC-V Assembly Language Programming

Using ESP32-C3 and QEMU ●

● This is an Elektor Publication. Elektor is the media brand of Elektor International Media B.V.

PO Box 11, NL-6114-ZG Susteren, The Netherlands

Phone: +31 46 4389444

● All rights reserved. No part of this book may be reproduced in any material form, including photocopying, or storing in any medium by electronic means and whether or not transiently or incidentally to some other use of this publication, without the written permission of the copyright holder except in accordance with the provisions of the Copyright Designs and Patents Act 1988 or under the terms of a licence issued by the Copyright Licencing Agency Ltd., 90 Tottenham Court Road, London, England W1P 9HE. Applications for the copyright holder's permission to reproduce any part of the publication should be addressed to the publishers.

● Declaration

The Author and Publisher have used their best efforts in ensuring the correctness of the information contained in this book. They do not assume, and hereby disclaim, any liability to any party for any loss or damage caused by errors or omissions in this book, whether such errors or omissions result from negligence, accident, or any other cause.

All the programs given in the book are Copyright of the Author and Elektor International Media. These programs may only be used for educational purposes. Written permission from the Author or Elektor must be obtained before any of these programs can be used for commercial purposes.

● British Library Cataloguing in Publication Data

A catalogue record for this book is available from the British Library

● ISBN 978-3-89576-525-4 Print ISBN 978-3-89576-526-1 eBook

● © Copyright 2022: Elektor International Media B.V.

Editor: Alina Neacsu

Prepress Production: D-Vision, Julian van den Berg

Elektor is part of EIM, the world's leading source of essential technical information and electronics products for pro engineers, electronics designers, and the companies seeking to engage them. Each day, our international team develops and delivers high-quality content - via a variety of media channels (including magazines, video, digital media, and social media) in several languages - relating to electronics design and DIY electronics. www.elektormagazine.com

● 4
Contents ● 5 Contents Chapter 1 • Introduction ............................................. 13 1.1. The Joy of the Machine .......................................... 13 1.2. Assembler Language ............................................ 14 1.3. Why RISC-V? ................................................. 14 1.4. Base Instruction Sets Covered ..................................... 15 1.5. Projects in this Book 15 1.6. What do you need? ............................................. 15 1.6.1. ESP32-C3 Hardware 16 1.7. Assumptions About the Reader ..................................... 18 1.8. Summary 18 Chapter 2 • ESP32-C3 Installation ...................................... 19 2.1. ESP32-C3 Device 19 2.2. Manual Installation (Linux and MacOS) ............................... 20 2.3. Windows Install ............................................... 29 2.4. Summary ................................................... 34 Chapter 3 • Installation and Setup of QEMU .............................. 35 3.1. Linux/MacOS Platforms: 35 3.2. Windows .................................................... 36 3.3. Installing QEMU on MacOS 36 3.4. Install QEMU on Devuan Linux ..................................... 36 3.5. QEMU Package Search 37 3.5.1. Building QEMU on Linux ........................................ 37 3.5.2. Basic Build Steps ............................................. 38 3.5.3. Linux/MacOS Setup of Fedora Linux ................................ 41 3.5.4. Linux/MacOS Boot Fedora Linux .................................. 42 3.5.5. Linux/MacOS Boot Test 43 3.6. Installing QEMU on Windows ...................................... 46 3.7. Summary 50 Chapter 4 • Architecture ............................................. 51 4.1. Program Counter Register 51
RISC-V Assembly Language Programming ● 6 4.2. Endianness .................................................. 51 4.3. General Purpose Registers ........................................ 52 4.4. Introducing Subsets ............................................ 52 4.5. Register Specifics 53 4.5.1. No Flag Bits ................................................ 54 4.5.2. Register x0 / Zero 55 4.5.3. Register x1 / ra .............................................. 55 4.5.4. Register x2 / sp 55 4.5.5. Register x3 / gp.............................................. 55 4.5.6. Register x4 / tp 55 4.5.7. Registers x5-x7 / t0-t2 ......................................... 55 4.5.8. Register x8 / s0 / fp ........................................... 55 4.5.9. Register x9 / s1 .............................................. 55 4.5.10. Registers x10-x11 / a0-a1 ...................................... 55 4.5.11. Registers x12-x17 / a2-a7 56 4.5.12. Registers x17-x27 / s2-s11 ..................................... 56 4.5.13. Registers x28-x31 / t3-t6 56 4.5.14. Register Summary ........................................... 56 4.6. Instruction Set Base Subsets/Extensions 56 4.7. ESP32-C3 Hardware: ........................................... 58 4.8. QEMU RISC-V 64 Bit Emulator ..................................... 58 4.9. RISC-V Privilege Levels ......................................... 59 4.10. RISC-V is Huge ............................................... 60 4.11. Summary 60 Chapter 5 • Getting Started ........................................... 61 5.1. Memory Models & Data Types 61 5.1.1. RV32 Model ................................................. 61 5.1.2. RV64 Model 62 5.2. The Impact of XLEN ............................................ 62 5.3. First Exercise 63 5.3.1. The Main Program ............................................ 63 5.3.2. Assembler Routine add3 ........................................ 64
Contents ● 7 5.3.3. Assembly Language Format ..................................... 64 5.3.4. Pseudo Opcode .global ......................................... 65 5.3.5. Pseudo Opcode .text .......................................... 65 5.3.6. The add Opcode 66 5.3.7. Calling add3 ................................................ 66 5.3.8. RV64I Consideration 67 5.3.9. Running the Demonstration ..................................... 67 5.4. First Exercise on ESP32-C3 68 5.5. Assembler Listings ............................................. 72 5.5.1. ESP32-C3 Assembler Listing 72 5.5.2. Influencing Assembly Code ...................................... 73 5.4.3. Objdump .................................................. 75 5.6. Summary ................................................... 75 Chapter 6 • Load and Store Memory .................................... 76 6.1. A Word About Word Sizes 76 6.2. Load Instructions .............................................. 76 6.3. Load Program Example 77 6.4. The .data Section .............................................. 80 6.5. Unsigned Values 83 6.6. Memory Alignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 6.7. Experiment .................................................. 85 6.8. Immediate Values .............................................. 85 6.9. The li Pseudo-Op .............................................. 86 6.10. The addi Opcode 87 6.11. Pseudo-Op mv ............................................... 87 6.12. Loads under RV64I 88 6.1.3 The .section Pseudo-Op ......................................... 89 6.14. Storing Data 90 6.15. Review .................................................... 94 6.16. RISC-V Assembler Modifiers 95 6.17. Summary................................................... 95
RISC-V Assembly Language Programming ● 8 Chapter 7 • Calling Convention ........................................ 96 7.1. Register Usage ................................................ 96 7.2. Call Procedure ................................................ 97 7.2.1. Opcode jal 97 7.2.2. Pseudo Opcode jr............................................. 97 7.2.3. Pseudo Opcode ret 98 7.2.4. General Call Procedure ......................................... 98 7.2.5. Call to 32-bit Absolute Address 98 7.2.6. Revised Call Procedure ......................................... 99 7.2.7. Concrete Call Example 99 7.2.8. Simple Call Experiment ....................................... 100 7.2.9. Running in gdb ............................................. 101 7.3. Argument Passing in Registers .................................... 104 7.4. The Stack .................................................. 105 7.4.1. Prologue 105 7.4.2. Epilogue .................................................. 106 7.4.3. Floating Point Arguments 106 7.4.4. A Big Call Experiment ......................................... 106 7.5. Calling printf() 111 7.6. Summary .................................................. 114 Chapter 8 • Flow Control ............................................ 116 8.1. Branching Instructions ......................................... 116 8.1.1. Unconditional Transfers ....................................... 116 8.1.2. Conditional Branches 117 8.2. Shift Opcodes................................................ 117 8.3. ESP32-C3 Project 118 8.3.1. Function c_ones() ........................................... 119 8.3.2. Main Test Program 119 8.3.3. Assembler Function ones() ..................................... 120 8.4. Compare and Set 123 8.5. Odd Parity Example ........................................... 123
Contents ● 9 8.6. RV64I Odd Parity ............................................. 125 8.7. Position Independent Code ...................................... 128 8.8. Summary .................................................. 129 Chapter 9 • Basic Opcodes ........................................... 130 9.1. Arithmetic Opcodes 130 9.1.1. add, addi and sub ........................................... 130 9.1.2. lui 130 9.1.3. auipc .................................................... 131 9.1.4. RV64 Arithmetic 131 9.2. Logical Opcodes .............................................. 131 9.3. ESP32-C3 Rotate Left .......................................... 132 9.4. RV64 Rotate Left ............................................. 134 9.5. ESP32-C3 Rotate Right ......................................... 136 9.6. Pseudo Opcodes .............................................. 138 9.7. Unsigned Multi-precision Arithmetic ................................ 138 9.8. Signed Multi-precision Arithmetic 140 9.8.1. Signed Overflow ............................................ 140 9.9. Summary 147 Chapter 10 • Multiply / Divide ........................................ 148 10.1. Multiplication Operations 148 10.2. Division Operations ........................................... 149 10.3. Opcode mul/mulu ............................................ 149 10.4. Opcode mulhs/mulhu ......................................... 149 10.5. Optimized Multiply ........................................... 149 10.6. Unsigned Factorial 151 10.7. Opcode div/divu ............................................. 153 10.8. Optimized Divide 153 10.9 Division By Zero ............................................. 154 10.10 Divide Overflow 154 10.11 Safe Division ............................................... 154 10.12. Greatest Common Divisor ..................................... 158 10.13. Combinations .............................................. 160
RISC-V Assembly Language Programming ● 10 10.14. Summary ................................................. 163 Chapter 11 • Addressing, Subscripting and Strings ........................ 164 11.1. Testing for Null Pointers ........................................ 164 11.2. Sizeof Type for Pointers ........................................ 164 11.3. Matrix Memory Layout 164 11.3.1. Subscript Calculation ........................................ 165 11.4. Identity Matrix Example 165 11.5. String Functions ............................................. 169 11.5.1. Function strlen() 169 11.5.2. Function strncpy32() ........................................ 171 11.5.3. String to Integer Conversion ................................... 174 11.5.4. What if there is no Multiply? ................................... 178 11.5.5. Integer to String Conversion ................................... 178 11.6. Indexed Branching ........................................... 181 11.7. Summary.................................................. 184 Chapter 12 • Floating Point .......................................... 185 12.1. Floating Point Registers ........................................ 185 12.2. GNU Calling Convention 186 12.3. Floating-Point Control and Status Register (fcsr)....................... 186 12.3.1. Rounding Modes fcsr.frm 187 12.3.2. Accrued Exception Flags fcsr.fflags ............................... 188 12.4. NaN Generation and Propagation ................................. 188 12.5. Opcodes and Data Formats ..................................... 188 12.6. Load and Store .............................................. 189 12.7. Floating Computation 189 12.8. Conversion Operations ........................................ 190 12.8.1. Floating-Point Zero 190 12.8.2. Conversion Failures ......................................... 191 12.9. Floating-Point Signs 191 12.10. Floating-Point Move .......................................... 192 12.11. Floating-Point Compare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 12.12. Classify Operation ........................................... 192
Contents ● 11 12.13. Fahrenheit to Celsius Revisited .................................. 193 12.14. Summary ................................................. 196 Chapter 13 • Portability ............................................. 197 13.1. C/C++ Pre-Processor ......................................... 197 13.2. Testing for RISC-V Architecture 199 13.3. Testing For Integer Multiplication ................................. 199 13.4. RV32 vs RV64 202 13.5. Assembler Macros ............................................ 204 13.6. Summary 208 Chapter 14 • Determining Support .................................... 209 14.1. Privilege Levels .............................................. 209 14.1.1. Machine Level ............................................. 210 14.1.2. Supervisor Level ........................................... 210 14.1.3. User Level ................................................ 210 14.2. Control and Status Registers .................................... 210 14.2.1. Machine ISA Register 210 14.3. Opcodes .................................................. 212 14.4. ESP32-C3 212 14.5. Reporting MISA ............................................. 212 14.6. RV64 Platform 216 14.7. Counters .................................................. 219 14.7.1 Project rdcycle ............................................. 219 14.7.2. ESP32-C3 rdcycle Support .................................... 222 14.8. Summary.................................................. 225 Chapter 15 • JTAG Debugging ........................................ 226 15.1. Espressif JTAG .............................................. 226 15.2. Device Requirements 226 15.3. Software Components ......................................... 227 15.4. JTAG With No Serial Window 228 15.4.1. Starting OpenOCD .......................................... 229 15.4.2. Problems with OpenOCD ...................................... 230 15.4.3. Terminating OpenOCD ....................................... 230
RISC-V Assembly Language Programming ● 12 15.4.4. Start gdb ................................................ 230 15.5. Operating gdb .............................................. 232 15.5.1. Abbreviations ............................................. 232 15.5.2 GDB Walkthrough ........................................... 233 15.5.3. Quitting gdb 240 15.6. JTAG With a Serial Window ..................................... 241 15.6. Miscellaneous 244 15.7. Summary.................................................. 244 Chapter 16 • Inline Assembly ........................................ 246 16.1. Keyword Asm ............................................... 246 16.2. Basic asm Form ............................................. 246 16.2.1. Keyword volatile ........................................... 248 16.2.2. Multiple Instructions ......................................... 248 16.2.3. Behind the Scenes .......................................... 249 16.3. Extended Asm .............................................. 249 16.3.1. Assembler Template 249 16.3.2. Output Operands ........................................... 250 16.3.2.1. Constraint 250 16.3.3. Input Operands ............................................ 253 16.3.3.1. Clobbers 254 16.4. Bit Multiply................................................. 255 16.5. Example asm goto ........................................... 257 16.6. Register Constraints .......................................... 259 16.7. Summary.................................................. 265 Index ........................................................... 266

Chapter 1 • Introduction

Introducing.... RISC-V!

With the availability of free and open-source C/C++ compilers today, you might wonder why someone would be interested in assembler language. What is so compelling about the RISC-V Instruction Set Architecture (ISA)? How does RISC-V differ from existing architec tures? And most importantly, how do we gain experience with the RISC-V without a major investment? Is there affordable hobbyist hardware available?

The availability of the Espressif ESP32-C3 chip provides a student with one affordable way to get hands-on experience with RISC-V. The open-sourced QEMU emulator adds a 64-bit experience in RISC-V under Linux. These are just two ways for the student and enthusiast alike to explore RISC-V in this book.

1.1. The Joy of the Machine

In the earliest days of computing, there was great enthusiasm in working out the mechani cal steps required to perform some computation or algorithm. The programmer was aware of every machine cycle, status bit and register available to him as resources to be exploited. In those early times debugging was often performed on a console decorated with lamps, buttons and switches. There was always great satisfaction in getting it right and making it run even faster than before.

I fear that today, we've lost some of that passion for exploiting the machine. Our CPU tower might possess only a power-on button and LED. But if we're lucky, it might provide a disk activity LED as well. Embedded systems are better, sporting multiple LEDs that can be utilized. Whether desktop or embedded device, we still program in high-level languages like C/C++. While there is still joy in that, the thrill of the hunt may be lacking for those thirsting for more. Getting that algorithm to execute even faster or more efficiently is not just a badge of honor, but a matter of pride.

● 13

One deterrent to assembly language has been the extremely cluttered instruction sets of today's architectures. The Intel and AMD instructions sets, for example, have been horri bly extended in the name of compatibility. RISC-V allows the enthusiast to sweep all that clutter aside and start over with a clean slate. This makes things so much easier because there is less to be learned.

Getting back to assembler language will bring back that thrill of the hunt that you may be pining for. At the assembly level, the programmer directs every step of the machine. You decide how the registers are allocated and apply every binary trick in your toolbox to make that process slick. While we don't have hardware debug consoles anymore, we do have powerful debugging tools like the GNU gdb debugger. There's never been a better time to do assembly language than today.

1.2. Assembler Language

It might seem counterproductive to program in assembly language. While C/C++ languag es will continue to be used for productive development, there frequently remain opportu nities for optimizing code at the machine level. In these areas, you will be empowered to exploit the machine in otherwise difficult ways.

One attractive area is writing custom floating-point algorithms in assembly language. For each calculation, you can carefully evaluate which rounding method to use and check for special exception cases at strategic places in the code. In C/C++, the tendency is to simply code the formula.

Even if you decide that you have no need to write assembly language code, being able to read it can be extremely helpful when debugging. Compilers, often at higher optimization levels, can generate incorrect code (this happens more often than you think). Being able to verify that the generated code is correct can save you from a great deal of guessing when debugging. With a working knowledge, you can step through the code one instruction at a time in a debugger and pinpoint the problem. Once the problem is revealed, you can then decide on a work-around for the compiler or replace the errant code directly with some assembler language code.

In microcomputer solutions, performance is often paramount. Assembler language pro gramming provides more options for meeting those performance goals. Finally, it is possi ble that one day RISC-V may become one of the few standard instruction sets in general use.

1.3. Why RISC-V?

Probably its most attractive feature is that it is designed to be free and open so that it is not hindered by restrictive licensing. This permits any manufacturer to create a RISC-V product without purchasing an expensive or restrictive license.

The RISC-V instruction set is also designed to be clean, unlike many existing architectures. Today's Intel ISA is a bewildering mess of adapted and extended instructions. To be fair, this was done to maintain code compatibility, but what a bewildering mess it has become.

RISC-V Assembly Language Programming ● 14

Now that security is more important than ever, there is a pressing need for a simpler de sign.

Reduced Instruction Set Computer (RISC) architecture had its beginnings in research pro jects conducted by John L. Hennessy at Stanford University between 1981 and 1984. MIPS (Microprocessor without Interlocked Pipeline Stages) was developed with the IBM 801 and the Berkeley RISC projects. The Berkeley RISC project was led by David Patterson who coined the term RISC. The thrust of these efforts was to develop a design that was simpler and potentially faster than the CISC (Complex Instruction Set Computers) of that time.

Today, simplicity benefits the chip manufacturer in lowering the cost of chip development and verification. Simplicity means fewer transistors, which leads to lower power require ments. A simple instruction set also reduces the complexity that the software developers must face. Finally, the RISC-V ISA has provision to include vendor extensions, without requiring any special approval. This can lead to surprising innovations.

1.4. Base Instruction Sets Covered

RISC-V is now a large body of work. In chapter 4, Architecture, I'll discuss base instruc tion sets and extensions to RISC-V. The focus of this book, however, will be on the RV32 and RV64 subsets of RISC-V. This permits an ample study of the ESP32-C3 device (RV32) as well as Fedora Linux under QEMU (RV64). These two environments should provide the reader with a well-rounded tutorial.

1.5. Projects in this Book

In many books applying MCU (Microprocessor Computing Units) concepts, the project builds are the focus. In them, the emphasis is placed on using GPIO (General Purpose Input/Output), I2C, SPI and other built-in peripherals to build something fun.

This book has a different focus, but it is still fun! The projects in this book are boiled down to the barest essentials to keep the assembly language concepts clear and simple. In this manner, you will have "aha!" moments rather than puzzling about something difficult. The focus of this book is on learning how to write RISC-V assembly language code without get ting bogged down. As you work your way through this tutorial, you'll build up small demon stration programs to be run and tested. Often the result is some simple printed messages to prove a concept. Once you've mastered these basic concepts, you will be well equipped to apply assembly language in larger projects.

1.6. What do you need?

This book uses the Espressif ESP32-C3 dev kit device for hardware. You will also emulate RISC-V in 64-bit mode using the QEMU emulator on your desktop computer. The emulator requires that you have at least 20 GB of free disk space available. For both of the ESP-IDF (ESP Integrated Development Framework) and QEMU instances, an internet connection for downloading is assumed.

Chapter 1 • Introduction ● 15

A suitably modern desktop computer is required to program the ESP32-C3 and to run the QEMU emulator, running Fedora Linux. If you lack 20 GB of free disk space, then that can be remedied by plugging in a USB hard drive to add some disk space.

1.6.1. ESP32-C3 Hardware

When purchasing hardware for use with this book, be sure to acquire the correct device type. The original ESP32 devices used the Xtensa processor and are not RISC-V devices. At the time of writing there are several types of ESP32:

• ESP32 (Xtensa dual-core and single-core 32-bit LX6 microprocessor)

• ESP32-S2 (Single-core Xtensa LX7 CPU)

• ESP32-S3 (Dual-core Xtensa LX7 CPU)

• ESP32-C3 Single-core 32-bit RISC-V (WiFi 2.4 Ghz IEEE 802.11b/g/n)

• ESP32-C6 Single-core 32-bit RISC-V

This book was developed specifically with the Espressif ESP32-C3 device (emphasis on the "C3").

When purchasing, don't make the mistake of just buying just a chip. Be sure to purchase a "devkit" that consists of a PCB with the GPIO breakouts, USB interface and the ESP32-C3 chip soldered onto it. You might also find it listed as "ESP-C3", but be careful. Make sure this refers to the ESP32-C3, and not some other ESP32 variants (using the Xtensa CPU). You'll also need an appropriate USB cable to flash and communicate with the devkit. The projects in this book can run off of the power from the USB cable.

Figure 1.1 illustrates an early ESP32-C3 dev board purchased from AliExpress. This ver sion 1 dev board cannot support JTAG. Notice that these use a USB to serial interface chip (CH340C), which can be seen in the photo. If you aren't concerned about JTAG support, then these are otherwise suitable to use.

RISC-V Assembly Language Programming ● 16

Figure 1.1: An early version 1 dev board. Note the USB to serial chip just right of the micro USB connector.

As time went on, Espressif came out with ESP32-C3 devices with JTAG support (version 3 or later). Since these connect directly from the ESP32-C3 chip to the USB port, they don't use a serial to USB converter chip. This makes it easy to identify the boards that support JTAG. With a direct connection to the USB bus, the ESP32-C3 can perform JTAG functions over the USB bus, as well as the usual serial communications. These are the preferred ESP32-C3 devkits to obtain. Figure 1.2 illustrates a JTAG-capable ESP32-C3 dev board sitting on a breadboard.

Figure 1.2: A revision 3 ESP32-C3 dev board supporting JTAG access.

Chapter 1 • Introduction ● 17

1.7. Assumptions About the Reader

The reader is assumed to have a basic understanding of what a CPU is, what registers are and the rudiments of computer memory. Assembler language and debugging require knowledge of number systems, specifically binary and hexadecimal. The reader should also be familiar with endianness. Knowing how big-endian ordering differs from little-endian will be helpful.

The reader is expected to be familiar with basic file system navigation: changing directo ries, creating directories and copying files. In some cases, the editing of a script file may be necessary. The Windows user should also be familiar with the Linux file system in this regard when using QEMU (emulating Fedora Linux).

Knowledge of the C language is assumed. Code examples will consist of a C language main program calling an assembly language function.

The QEMU examples use a RISC-V version of downloadable Fedora Linux. Consequent ly, some familiarity with the Linux command line is an asset even for Windows users. The ESP32-C3 examples will use your native desktop environment for ESP development, whether Linux, MacOS or Windows. In all cases, simple commands are issued to build and run the test programs.

Finally, the reader is expected to do some software downloading and installation. Unfortunately, there is a fair amount of this initially, but the good news is that it is all free and open software. Once installed, the reader can then focus on the RISC-V concepts presented in this book.

1.8. Summary

The next pair of chapters deal with installing your ESP-IDF (ESP Integrated Development Framework) and the QEMU emulation software. This bit of work is necessary to let the good times roll. So gather your disk space and enable your internet access and begin!

RISC-V Assembly Language Programming ● 18
Bibliography [1] The_RISC-V_Reader_An_Open_Architecture_Atlas_by_David_Patterson_Andrew_ Waterman.pdf

Chapter 2 • ESP32-C3 Installation

ESP32-C3 celebrates RISC-V

This chapter illustrates the steps necessary to get you up and running using the ESP32-C3 device. The first part of this chapter focuses on Linux and MacOS software installations. This is what Espressif calls "Manual Installation". Espressif also supports IDE installations for Eclipse or VSCode if you prefer. See their online documentation for that.

Windows users will want to skip to the later part of this chapter starting with the section heading "Windows Install". This will guide you through the use of the downloaded Espressif windows installer.

For either installation, you will need to plan for ample disk space and be connected to your internet. The ESP-IDF on the Mac (for device ESP32-C3 only) requires about 1.5 GB of disk. But the compilers and other tools will also require additional disk space as they are installed. I recommend that you allocate a minimum of 10 GB of free disk space before you proceed. The downloads are rather large and will take some time to complete. Choose a time to install where you are not rushed.

2.1. ESP32-C3 Device

Espressif markets and sells several devices under the ESP32 moniker, so make sure you purchase the correct device in order to enjoy RISC-V adventures. If your part says ESP32 but not C3, it is not the RISC-V version of the CPU. These devices are also sold as bare modules. So be sure to get a "dev kit" form of the product. One product that I am using is a ESP32-C3-DevKitM-1 clone. By the time you read this there may be newer versions of the ESP32-C3-DevKit and those are likely your best option.

Dev kits may include a USB to serial chip (USB-UART bridge) like the CP2102. My devices used the CHG340 chip. Either bridge chip is ok, since we are only interested in the RISC-V CPU in this book. Now you can purchase dev kits with JTAG support. These devices with revision 3 or later use the USB facilities directly. Figure 2.1 illustrates two early examples of revision 1 dev boards. The CH340C USB to serial converter chip is very conspicuous.

Chapter 2 • ESP32-C3 Installation ● 19

Figure 2.1: Two ESP32-C3 devices with revision 1 PCBs (using USB to serial converters).

2.2. Manual Installation (Linux and MacOS)

Locate the Espressif "Get Started" web page. If the website doesn't change too much, you should be able to arrive there directly using the following url: https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/get-started/index.html

Otherwise search for "ESP-IDF Programming Guide" with your browser.

Once you arrive at that page, don't forget to choose the product type ESP32-C3 in the upper left. Espressif supports multiple device types, and we are primarily interested in the ESP32-C3 with RISC-V support. It should look something like Figure 2.2.

Figure 2.2: Set the device selection as ESP32-C3.

Scroll down the page until you see the link "Linux and MacOS". Click on the link to open a new page of instructions.

RISC-V Assembly Language Programming ● 20
Chapter 2 • ESP32-C3 Installation

Linux and MacOS

On this page you will be guided through the following basic steps:

1. Install Prerequisites.

2. Get ESP-IDF.

3. Setup the tools.

4. Set up the environment variables.

5. First Steps for ESP-IDF.

Note:

the instructions differ at all from this text, do follow the instructions found on the website instead. Espressif may have made changes to the installation procedure by the time you read this.

Install Prerequisites

The prerequisites will vary somewhat with the Linux distribution you're using. Check the Espressif website for the latest updates by distro.

Ubuntu and Debian

For these distributions, the following packages should be installed (some may already be installed):

$ sudo apt install git wget flex bison gperf python3 python3-pip \ python3-setuptools cmake ninja-build ccache libffi-dev libssl-dev \ dfu-util libusb-1.0-0

You might wish to split these up into smaller steps, like the following:

$ sudo apt install git wget

$ sudo apt flex bison

$ sudo apt gperf python3

$ sudo apt python3-pip python3-setuptools

$ sudo apt cmake ninja-build

$ sudo apt ccache libffi-dev

$ sudo apt libssl-dev dfu-util libusb-1.0-0

CentOS 7 & 8

CentOS uses the yum installer, and the dependencies are listed as follows:

$ sudo yum -y update && sudo yum install git wget flex bison gperf \ python3 python3-pip python3-setuptools cmake ninja-build ccache \ dfu-util libusbx

Chapter 2 • ESP32-C3 Installation ● 21
If

Arch

Espressif has documented the following dependencies for the Arch distro:

$ sudo pacman -S --needed gcc git make flex bison gperf python-pip \ cmake ninja ccache dfu-util libusb

Espressif notes that CMake version 3.5 or newer is required. If you're running an older distribution, you may need to update your system packages. For other Linux distributions not listed here, use the above as a hint to the package names that you may need to add or update.

MacOS

MacOS users usually install HomeBrew (recommended) or the MacPorts open-source pro jects to add functionality to their Mac. If you've not done that yet, you need to do that now. Refer to the following sites for more information about this:

https://brew.sh/ (HomeBrew) https://www.macports.org/install.php (MacPorts)

Whether you use HomeBrew or MacPorts, you must install pip:

$ sudo easy_install pip

Next, CMake and Ninja are installed. For HomeBrew install:

$ brew install cmake ninja dfu-util

For MacPorts users, use:

$ sudo port install cmake ninja dfu-util

Espressif recommends that you also install ccache for faster build times. For HomeBrew, use:

$ brew install ccache

For MacPorts use:

$ sudo port install ccache

Note: Espressif indicates that if during the installation you encounter an error like the following: xcrun: error: invalid active developer path (/Library/Developer/Command LineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun Then you will need to install the Apple XCode command line tools in order to continue. Install these with:

RISC-V Assembly Language Programming ● 22

$ xcode-select --install

MacOS Python 3

Check the version of python you have installed with:

$ python --version

If it is a version older than 3, or is not present, then check the following (notice that the command name is python3 this time):

$ python3 --version

If that fails, then you need to install it. For HomeBrew:

$ brew install python3

For MacPorts: $ sudo port install python38

Get ESP-IDF

At this point, you need to decide where to place your ESP-IDF software (not as root). I'm going to assume in this book, that the directory will be named ~/espc3, where the tilda (~) represents your home directory. You can choose a different directory name, by simply substituting ~/espc3 for the name you prefer.

First, create the subdirectory to house your files in (starting from your home directory):

$ mkdir -p ~/espc3 and then change to it:

$ cd ~/espc3

Now access the files from GitHub by performing:

$ git clone --recursive https://github.com/espressif/esp-idf.git

This git operation downloads several files and will take some time to complete. It is also a good opportunity to take a break for your favourite beverage.

When the git operation completes, you will have the Espressif software downloaded into the subdirectory ~/espc3/esp-idf.

Chapter 2 • ESP32-C3 Installation ● 23

Set up the Tools

Now we need to install some tools used by the ESP-IDF framework, like the compiler and Python packages.

$ cd ~/espc3/esp-idf

$ ./install.sh esp32c3

Performing this step will result in more files being downloaded and installed. This step progresses much faster than the GitHub clone operation but can still require some time. Perhaps your beverage needs a refill?

At the end of this installation, you might encounter a message like:

WARNING: You are using pip version 21.2.1; however, version 22.0.3 is available.

You should consider upgrading via the '~/.espressif/python_env/idf5.0_py3.9_env/bin/python -m pip install --upgrade pip' command.

This is optional, but I chose to do it.

At the end of the installation, your session should have completed with the message: All done! You can now run:

$ . ./export.sh

At this point, you should run this script and watch for any error messages. Some errors you might see may include:

ERROR: tool xtensa-esp32-elf has no installed versions. Please run '/Users/joe/ espc3/esp-idf/install.sh' to install it.

ERROR: tool xtensa-esp32s2-elf has no installed versions. Please run '/Users/joe/ espc3/esp-idf/install.sh' to install it.

ERROR: tool xtensa-esp32s3-elf has no installed versions. Please run '/Users/joe/ espc3/esp-idf/install.sh' to install it.

In other words, these messages complain about missing support for:

xtensa-esp32-elf

xtensa-esp32s2-elf

xtensa-esp32s3-elf

If you're only concerned about our ESP32-C3 device, which was not listed in error, you can ignore these messages. If you also want to support these other devices (regular ESP32,

RISC-V Assembly Language Programming ● 24

ESP32-S2 and ESP32-S3), you can follow the Espressif advice and run the installation scripts suggested.

Set up Environment Variables

To run the Espressif tools to build your projects some environment changes must be applied each time you log in. In a fresh terminal session, you would need to do the following. Make sure that you type a space between the dot and the rest of the pathname:

$ . ~/espc3/esp-idf/export.sh

Assuming that no critical error messages are reported, this sets up your terminal session to build your ESP projects. Some users may wish to create a shorter way to do this. Espressif recommends creating an alias like get_idf as follows:

$ alias get_idf='. $HOME/espc3/esp-idf/export.sh'

Once that alias is defined, you can just type:

$ get_idf

to establish your build environment. Depending upon the shell you use for your terminal session, you might want to set the get_idf alias up in your ~/.profile or ~/.bashrc file, so that it is automatically defined each time you log in.

Once that export.sh script has run, your environment will have the variable IDF_PATH set. In this chapter, it would have the value "~/espc3/esp-idf". This allows you to use the shell value $IDF_PATH in commands and scripts if you like.

First Steps for ESP-IDF

The installation procedure has covered a lot of ground so let's test it. Change to the exam ple subdirectory shown:

$ cd $IDF_PATH/examples/get-started/hello_world (or)

$ cd ~/espc3/esp-idf/examples/get-started/hello_world

Configure the Target Device

In order to build for the ESP32-C3 device, we need to tell the build framework about it:

$ idf.py set-target esp32c3

Build Example hello_world

This step adjusts the environment so that it knows that it is compiling for our RISC-V device (ESP32-C3). Now test the build process:

Chapter 2 • ESP32-C3 Installation ● 25

$ idf.py build

The first time this runs for a given project, it will compile a lot, but don't be concerned. Subsequent builds will not take so long. When it succeeds, the process should end with a message:

Project build complete. To flash, run this command: ....snip.... or run 'idf.py -p (PORT) flash'

Flash the Device

Before we can flash your RISC-V (ESP32-C3), we need to find out what port it appears on when you plug its cable into a USB port. But before you plug in your device's USB cable, list the cu devices under /dev as follows:

$ ls /dev/cu* /dev/cu.Bluetooth-Incoming-Port /dev/cu.usbserial-0001

This will list some that are already present. Don't be concerned if no devices show up. Now plug in your RISC-V device's USB cable and list the files again:

$ ls /dev/cu* /dev/cu.Bluetooth-Incoming-Port /dev/cu.usbserial-0001 /dev/cu.usbserial-1430

In this example, the device /dev/cu.usbserial-1430 was added. This is the device name we need for flashing our device. Define it in the shell variable named PORT, so that you won't have to type it each time:

$ PORT=/dev/cu.usbserial-1430

$ export PORT

To flash the example program to your device, try it now (the example output has been abbreviated somewhat):

$ idf.py flash

Executing action: flash Serial port /dev/cu.usbserial-1430

Connecting....

Detecting chip type... ESP32-C3

Running ninja in directory /Users/joe/espc3/esp-idf/examples/get-started/ hello_world/build

Executing "ninja flash"...

...

Chip is ESP32-C3 (revision 3)

Features: Wi-Fi Crystal is 40MHz

RISC-V Assembly Language Programming ● 26

MAC: 7c:df:a1:b4:44:94

Uploading stub...

Running stub...

Stub running...

Changing baud rate to 460800 Changed.

Configuring flash size...

Flash will be erased from 0x00000000 to 0x00004fff...

Flash will be erased from 0x00010000 to 0x00034fff... Flash will be erased from 0x00008000 to 0x00008fff...

Compressed 19984 bytes to 12116...

Writing at 0x00000000... (100 %)

Wrote 19984 bytes (12116 compressed) at 0x00000000 in 0.7 seconds (effective 221.1 kbit/s)...

Hash of data verified.

Compressed 151072 bytes to 81515...

Writing at 0x00010000... (20 %)

Writing at 0x00019a2e... (40 %)

Writing at 0x00020360... (60 %)

Writing at 0x00027602... (80 %)

Writing at 0x0002dada... (100 %)

Wrote 151072 bytes (81515 compressed) at 0x00010000 in 2.7 seconds (effective 443.9 kbit/s)...

Hash of data verified.

Compressed 3072 bytes to 103...

Writing at 0x00008000... (100 %)

Wrote 3072 bytes (103 compressed) at 0x00008000 in 0.1 seconds (effective 262.5 kbit/s)...

Hash of data verified.

Chapter 2 • ESP32-C3 Installation ● 27
Leaving... Hard resetting via RTS pin... Done If your session appeared similar to this, then congratulations are in order. You have flashed your first RISC-V program to the device. Running hello_world To see the hello_world program run, we monitor it as follows: $ idf.py monitor $ idf.py monitor Executing action: monitor Serial port /dev/cu.usbserial-1430 Connecting.... Detecting chip type... ESP32-C3

Running idf_monitor in directory /Users/joe/espc3/esp-idf/examples/get-started/ hello_world

...

--- idf_monitor on /dev/cu.usbserial-1430 115200 ---

--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---

ESP-ROM:esp32c3-api1-20210207

Build:Feb 7 2021

rst:0x1 (POWERON),boot:0xc (SPI_FAST_FLASH_BOOT)

SPIWP:0xee

mode:DIO, clock div:1

load:0x3fcd6100,len:0x1750

load:0x403ce000,len:0x930

load:0x403d0000,len:0x2d3c entry 0x403ce000

I (30) boot: ESP-IDF v5.0-dev-1730-g229ed08484 2nd stage bootloader

I (30) boot: compile time 19:50:12

I (30) boot: chip revision: 3

I (33) boot.esp32c3: SPI Speed : 80MHz

I (38) boot.esp32c3: SPI Mode : DIO

I (43) boot.esp32c3: SPI Flash Size : 2MB

I (48) boot: Enabling RNG early entropy source...

I (53) boot: Partition Table:

I (57) boot: ## Label Usage Type ST Offset Length

I (64) boot: 0 nvs WiFi data 01 02 00009000 00006000

I (71) boot: 1 phy_init RF data 01 01 0000f000 00001000

I (79) boot: 2 factory factory app 00 00 00010000 00100000

I (86) boot: End of partition table

...

I (145) boot: Loaded app from partition at offset 0x10000

I (148) boot: Disabling RNG early entropy source...

I (165) cpu_start: Pro cpu up.

I (173) cpu_start: Pro cpu start user code

I (173) cpu_start: cpu freq: 160000000 Hz

I (173) cpu_start: Application information:

I (176) cpu_start: Project name: hello_world

I (182) cpu_start: App version: v5.0-dev-1730-g229ed08484

I (188) cpu_start: Compile time: Mar 1 2022 19:50:05

I (194) cpu_start: ELF file SHA256: d4ad172e8078f033...

I (200) cpu_start: ESP-IDF: v5.0-dev-1730-g229ed08484

I (207) heap_init: Initializing. RAM available for dynamic allocation:

I (214) heap_init: At 3FC8C540 len 00033AC0 (206 KiB): DRAM

I (220) heap_init: At 3FCC0000 len 0001F060 (124 KiB): STACK/DRAM

I (227) heap_init: At 50000020 len 00001FE0 (7 KiB): RTCRAM

I (234) spi_flash: detected chip: generic

I (238) spi_flash: flash io: dio

I (242) sleep: Configure to isolate all GPIO pins in sleep state

RISC-V Assembly Language Programming ● 28

I (249) sleep: Enable automatic switching of GPIO sleep configuration I (256) cpu_start: Starting scheduler.

Hello world!

This is esp32c3 chip with 1 CPU core(s), WiFi/BLE, silicon revision 3, 2MB external flash

Minimum free heap size: 328924 bytes

Restarting in 10 seconds...

Restarting in 9 seconds...

Restarting in 8 seconds... Restarting in 7 seconds...

After the device boots up, you will see the message "Starting scheduler". The next message shown is the "Hello world!" that we were waiting for. Then the program counts down and will reboot again until you terminate it. To stop monitoring, type Control-] (control plus the right square bracket) and you should be returned to your shell. Congratulations, you ran your first RISC-V program!

2.3. Windows Install

While it is possible to install the Windows Subsystem for Linux (WSL and WSL2) on Win dows 10 and later, you may not be able to get the Linux USB access to work with the ESP32-C3 device. For this reason, I'll document the native Windows install procedure as provided by Espressif. Espressif provides the install documentation here:

https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/get-started/ windows-setup.html

Limitations

Espressif lists the following limitations:

• The installation path of ESP-IDF and ESP-IDF Tools must not be longer than 90 characters.

From their web page:

[Installation paths that are too long] might result in a failed build. The installation path of Python or ESP-IDF must not contain white spaces or parentheses. The in stallation path of Python or ESP-IDF should not contain special characters (non-AS CII) unless the operating system is configured with "Unicode UTF-8" support.

System Administrator can enable the support via Control Panel. Change date, time, or number formats - Administrative tab - Change system locale - check the option "Beta: Use Unicode UTF-8 for worldwide language support" - Ok and reboot the computer.

Chapter 2 • ESP32-C3 Installation ● 29

register 53

148

hello_world 25 HomeBrew 43

instructions sets

Binary Interface 53 apt 37

22

shift

C/C++ 81 C compiler 62 CentOS 21 cexpression 253 CHG340 chip 19 CMU extensions 216 COM port 33 CSR 186 cycle snapshot 221

IDLE thread 240 Install Prerequisites 21 Instruction Set Architecture 13

JTAG support 227

License Agreement 30 Linux USB access 29 LP64 Solaris model 62

21

Machine Performance Counter Value 225 MacOS 22 Manual Installation 19 matrix organized 164 MIPS 15 MISA register 59 MPCCR counter 222 MXL field 210

NaN-boxing 192 NULL pointer 164

30

Linux 18, 41

bits

226 OpenOCD session 230 operating privilege mode 209 overflow occurred 147

Pre-Processor 197

212

50

RISC-V Assembly Language Programming ● 266 32-bit register 83 A ABI
Ada
AMD
14 Application
Arch
arithmetic
118 B boot.bat script 48 C
D Debian
E embedded platforms 178 Environment Variables 25 ESP-IDF
ESP-IDF PowerShell 32 F Fedora
FLEN
185 floating-point format 192 FreeRTOS 212 G GCC 197 gdb debugger 87 H
I
J
L
M
N
O OpenOCD
P
pseudo-instructions
PuTTY
Index

QEMU

SRAM 81 SSH Authentication 45 stack layout 109 Stanford University 15 subi 130

T tilda 233

U

UART0 241 Ubuntu 21 Unicode UTF-8 29 USB Serial/JTAG Controller 242 USB-UART bridge 19

V variable bcount 119

W WARL 210 X XLEN 51 XLEN-bit divisor 153 Xtensa 16

Index ● 267 Q
emulator 13 QEMU Install 47 S

booksbooks

RISC-V Assembly Language Programming

Using the ESP32-C3 and QEMU

With the availability of free and open source C/C++ compilers today, you might wonder why someone would be interested in assembler language. What is so compelling about the RISC-V Instruction Set Architecture (ISA)? How does RISC-V di er from existing architectures? And most importantly, how do we gain experience with the RISC-V without a major investment? Is there a ordable hardware available?

The availability of the Espressif ESP32-C3 chip provides a way to get hands-on experience with RISC-V. The open sourced QEMU emulator adds a 64-bit experience in RISC-V under Linux. These are just two ways for the student and enthusiast alike to explore RISC-V in this book.

The projects in this book are boiled down to the barest essentials to keep the assembly language concepts clear and simple. In this manner you will have “aha!” moments rather than puzzling about something di icult. The focus in this book is about learning how to write RISC-V assembly language code without getting bogged down. As you work your way through this tutorial, you’ll build up small demonstration programs to be run and tested. Often the result is some simple printed messages to prove a concept. Once you’ve mastered these basic concepts, you will be well equipped to apply assembly language in larger projects.

Warren Gay is a datablocks.net senior software developer, writing Linux internet servers in C++. He got involved with electronics at an early age, and since then he has built microcomputers and has worked with MC68HC705, AVR, STM32, ESP32 and ARM computers, just to name a few.

Elektor International Media BV www.elektor.com
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.