Design Languages for Embedded Systems
Total Page:16
File Type:pdf, Size:1020Kb
Design Languages for Embedded Systems Stephen A. Edwards Columbia University, New York [email protected] May, 2003 Abstract ward hardware simulation. VHDL’s primitive are assign- ments such as a = b + c or procedural code. Verilog adds Embedded systems are application-specific computers that transistor and logic gate primitives, and allows new ones to interact with the physical world. Each has a diverse set be defined with truth tables. of tasks to perform, and although a very flexible language might be able to handle all of them, instead a variety of Both languages allow concurrent processes to be de- problem-domain-specific languages have evolved that are scribed procedurally. Such processes sleep until awak- easier to write, analyze, and compile. ened by an event that causes them to run, read and write variables, and suspend. Processes may wait for a pe- This paper surveys some of the more important lan- riod of time (e.g., #10 in Verilog, wait for 10ns in guages, introducing their central ideas quickly without go- VHDL), a value change (@(a or b), wait on a,b), ing into detail. A small example of each is included. or an event (@(posedge clk), wait on clk un- 1 Introduction til clk='1'). An embedded system is a computer masquerading as a non- VHDL communication is more disciplined and flexible. computer that must perform a small set of tasks cheaply and Verilog communicates through wires or regs: shared mem- efficiently. A typical system might have communication, ory locations that can cause race conditions. VHDL’s sig- signal processing, and user interface tasks to perform. nals behave like wires but the resolution function may be Because the tasks must solve diverse problems, a lan- user-defined. VHDL’s variables are local to a single pro- guage general-purpose enough to solve them all would be cess unless declared shared. difficult to write, analyze, and compile. Instead, a variety Verilog’s type system models hardware with four-valued of languages have evolved, each best suited to a particu- bit vectors and arrays for modeling memory. VHDL does lar problem domain. For example, a language for signal- not include four-valued vectors, but its type system allows processing is often more convenient for a particular prob- them to be added. Furthermore, composite types such as C lem than, say, assembly, but might be poor for control- structs can be defined. dominated behavior. Overall, Verilog is the leaner language more directly This paper describes popular hardware, software, geared toward simulating digital integrated circuits. VHDL dataflow, and hybrid languages, each of which excels a cer- is a much larger, more verbose language capable of handing tain problems. Dataflow languages are good for signal pro- a wider class of simulation and modeling tasks. cessing, and hybrid languages combine ideas from the other 3 Software Languages three classes. Due to space, this paper only describes the main features Software languages describe sequences of instructions for a of each language. The author’s book on the subject [9] pro- processor to execute. As such, most consist of sequences of vides many more details on all of these languages. imperative instructions that communicate through memory: an array of numbers that hold their values until changed. 2 Hardware Languages Each machine instruction typically does little more than, Verilog [14, 25] and VHDL [13, 23, 8, 2] are the most pop- say, add two numbers, so high-level languages aim to ular languages for hardware description and modeling (Fig- specify many instructions concisely and intuitively. Arith- ure 1, 2). Both model systems with discrete-event seman- metic expressions are typical: coding an expression such tics that ignore idle portions of the design for efficient sim- as ax2 + bx + c in machine code is straightforward, tedious, ulation. Both describe systems with structural hierarchy: a and best done by a compiler. The C language provides such system consists of blocks that contain instances of primi- expressions, control-flow constructs such as loops and con- tives, other blocks, or concurrent processes. Connections ditionals, and recursive functions. The C++ language adds are listed explicitly. classes as a way to build new data types, templates for poly- Verilog provides more primitives geared specifically to- morphic code, exceptions for error handling, and a standard 1 module fulladd(ai, bi, ci, o, co); jmp L2 # go to L2 input ai, bi, ci; L1: # label output o, co; movl %ebx, %eax # n -> m wire s1; movl %ecx, %ebx # r -> n L2: xor x1(s1, ai, bi), x2(o, s1, ci); xorl %edx, %edx # clear %edx divl %ebx # m / n assign co = (ai + bi + ci) >= 2; movl %edx, %ecx # rem -> r endmodule testl %ecx, %ecx # if r = 0, jne L1 # go to L1 module testadd; reg [2:0] y; wire o, co; reg clk; Figure 3: Euclid’s algorithm in i386 assembly language. Symbols like %ebx represent registers. movl means “move fulladd a1(y[0], y[1], y[2], o, co); long value.” divl %ebx divides %eax by %ebx and puts initial begin the remainder in %edx. y = 0; clk = 0; $monitor($time,,"%d%d%d %d%d", #include <stdio.h> y[2], y[1], y[0], co, o); end int main(int argc, char *argv[]) { always #10 clk = ˜clk; char *c; always @(posedge clk) y <= y + 1; while (++argv, --argc > 0) { endmodule c = argv[0] + strlen(argv[0]); while (--c >= argv[0]) Figure 1: A Verilog model for a full adder. This uses prim- putchar(*c); putchar(’\n’); itive gates, continuous assignment, and procedural code. } return 0; entity XOR2 is } port (o: out Bit; a, b: in Bit); end XOR2; architecture arch1 of XOR2 is Figure 4: A C program that prints its arguments backwards. begin The outermost while loop iterates through the arguments A1: o <= (a xor b); end arch1; (count in argc, array of strings in argv), while the inner loop starts a pointer at the end of the current argument and walks entity fulladd is port (ai, bi, ci: in Bit; it backwards, printing each character along the way. o, co: out Bit); end fulladd; architecture arch1 of fulladd is library of common data structures. Java is a still higher- signal s1 : Bit; level language that provides automatic garbage collection, component XOR2 port(o: out Bit; a, b: in Bit); threads, and monitors to synchronize them. end component; for X1, X2: XOR2 use entity Work.XOR2; 3.1 Assembly Languages begin X1: XOR2 port map (s1, ai, bi); X2: XOR2 port map (o, s1, ci); An assembly language program (Figure 3) is a list of pro- A1: co <= (ai and bi) or (ai and ci) cessor instructions written in a symbolic, human-readable or (bi and ci); end arch1; form. Each instruction consists of an operation such as ad- dition along with some operands. E.g., add r5,r2,r4 Figure 2: A VHDL model for a full adder that does not might add the contents of registers r2 and r4 and write include a test bench; compare with Figure 1. the result to r5. Such arithmetic instructions are executed in order, but branch instructions can perform conditionals C C++ Java and loops by changing the processor’s program counter— Expressions ● ● ● the address of the instruction being executed. Control-flow ● ● ● A processor’s assembly language is defined by its op- ● ● ● Recursive functions codes, addressing modes, registers, and memories. The op- ❍ ● ● Exceptions code distinguishes, say, addition from conditional branch, Classes & Inheritance ● ● and an addressing mode defines how and where data is gath- Templates ● Namespaces ● ● ered and stored (e.g., from a register or from a particular Multiple inheritance ● ❍ memory location). Registers can be thought of as small, Threads & Locks ● ● fast, easy-to-access pieces of memory. ❍ ● Garbage collection 3.2 The C Language ● full support ❍ partial support A C program (Figure 4) contains functions built from arith- metic expressions structured with loops and conditionals. Table 1: Software language features compared Instructions in a C program run sequentially, but control- 2 class Cplx { import java.io.*; double re, im; class Counter { public: int value = 0; Cplx(double v) : re(v), im(0) {} boolean present = false; Cplx(double r, double i) public synchronized void count() { : re(r), im(i) {} try { while (present) wait(); } double abs() const { catch (InterruptedException e) {} return sqrt(re*re + im*im); value++; present = true; notifyAll(); } } void operator+= (const Cplx& a) { public synchronized int read() { re += a.re; im += a.im; try { while (!present) wait(); } } catch (InterruptedException e) {} }; present = false; notifyAll(); return value; int main() { } Cplx a(5), b(3,4); } b += a; class Count extends Thread { cout << b.abs() << ’\n’; Counter cnt; return 0; public Count(Counter c) { cnt = c; start(); } } public void run() { for (;;) cnt.count(); } } class Mod5 { Figure 5: A C++ fragment illustrating a partial complex public static void main(String args[]) { number type (the C++ library has a complete version). Counter c = new Counter(); Count count = new Count(c); int v; for (;;) if ( (v = c.read()) % 5 == 0 ) flow constructs such as loops of conditionals can affect the System.out.println(v); } order in which instructions execute. When control reaches a } function call in an expression, control is passed to the called function, which runs until it produces a result, and control Figure 6: A contrived Java program that spawns a counting returns to continue evaluating the expression that called the thread to print all numbers divisible by 5. function. C derives its types from those a processor manipulates different use of the template. For example, the same min directly: signed and unsigned integers ranging from bytes template could be used for both integers and floating-point to words, floating point numbers, and pointers.