Description languages

From Emulator

Jump to: navigation, search


Hardware and software systems are increasingly complex, and reasoning about such systems, as well as creation and simulation of such systems is increasingly reliant on some degree of automation. Such automation relies on information about the systems being available in a machine-readable form, as some kind of a formal system description in a known language.

There are a number of languages designed for the purpose of describing aspects of hardware and software systems. This article provides a fairly broad overview of such description languages, focusing on languages that are potentially useful in the development of execution environments or associated toolkits. The execution environments in question could be hardware-based computation devices or virtual execution environments (emulators, simulators, or virtual machines), and the toolkits might contain compilers, assemblers, debuggers, etc.

Contents


Language classifications

As there are a large number of different description languages for a variety of different purposes, people have come up with terminology for categorizing languages into groups of languages with certain commonalities. These categories are often overlapping, and a lot of the terms lack a single, clear, established definition. It is nonetheless useful to have some idea of the terminology, as it is heavily used in related literature.

Some of the major language classifications seen in literature are:

hardware description language (HDL) 
The term may be used of any formal language capable of describing a hardware system in such a way that the description is a usable basis for designing and simulating the system. A HDL must be able to express the structure of a system (at some level of abstraction) to support architectural modeling. It must also be able to express as much information regarding the behavior of the system as is required for simulation. A HDL may be able to describe the system structure in such detail that the hardware can be automatically synthesized based on a HDL description.
machine description language (MDL) 
The term is used of domain-specific languages intended for expressing information about machine specifics, in particular as relates to the syntax and semantics of machine instructions. These languages are intended to help generate parts of software tools that manipulate machine instructions. [Ramsey]
architecture description language (ADL) 
The term is sometimes used of languages for representing and analyzing software architectures, but here it is taken to mean languages used to specify programmable architectures, i.e., systems consisting of programmable components including a processor core, coprocessors and memory subsystem. An ADL may be used to describe both the structure (hardware components and their connectivity) and the behaviour (instruction set) of such architectures. An ADL may be expressive enough to make it possible to generate both hardware prototypes and related software toolkits (including the compiler, assembler, simulator and debugger) from a single specification expressed in the ADL. [MishraE]

Reasons for language proliferation

As mentioned, there are a large number of domain-specific languages (DSLs) designed for the purpose of expressing machine descriptions. There are also a number of factors that have led to this kind of language proliferation.

Failed and superseded languages

It is not easy to design a language, and to get it right on the first try. There are a number of older languages whose maintenance has been discontinued (e.g., Confluence, HDCaml), sometimes in favor of another language.

Issues of taste

People have differing tastes. The desire for "better" syntax, for instance, may be quite enough reason to design yet-another language for a particular purpose, even when an otherwise fit-for-purpose language is already available.

Design tradeoffs

Some design goals for a language may be conflicting, leading to the language necessarily having to be suboptimal in some respect. This leaves the market open for languages that make different design compromises. For instance, more verbose (and explicit) language is likely to mean more work writing code and less work in comprehending it, while the opposite is likely to be true for a concise language in which many details are left implicit.

Domain specificity

Already by definition, a DSL is specific to a domain. Increasing specificity enables increasing convenience of expression, but also adds limitations to what can be expressed, resulting in a need for more languages. In [Ramsey], Ramsey et al suggest using a number of descriptions to describe a machine, not necessarily written in a common language or supported by a single tool. The idea of using multiple DSLs for describing different parts of a single system is sometimes referred to as language-oriented programming.

Despite the benefits of domain specificity, there is a market for languages that combine multiple sub-domains into a single language. If there is some degree of overlap between the descriptions of two different aspects of a system (e.g., structure and behavior), and both kinds of descriptions are required, it may be beneficial to use a single language that can describe both aspects, to avoid duplication and inconsistencies between descriptions. In [Mishra], Mishra and Dutt classify ADLs into three categories, namely structural, behavioral, and mixed, where mixed ADLs capture both structural and behavioral aspects.

Lack of universality

Even when a description language been designed for describing certain things only, it may not be universal enough to support the description of all such things. It is hard to achieve the required level of generality in designing a language. For example, making an MDL general enough to support describing the Pentium's context-dependent addressing modes and SPARC's register windows has proved to be a challenge. [Ramsey]

Lack of reusability

It may be that a language can indeed describe all machines of a certain kind, but still cannot be used as a basis of hardware synthesis or code generation. Possible reasons for this include:

An "escape hatch" in the language.
The language supports—via an "escape hatch" [Ramsey]—the inclusion of snippets of code written in a particular general-purpose programming language (GPL). Suppose that the snippets must be given in C, for instance, but a Java component is to be generated.
The language has a preferred direction.
A language might allow one to state concrete-to-abstract syntax mappings for machine instructions, allowing for the generation of instruction decoders. To generate an instruction encoder, one needs a mapping to the opposite direction. It is quite common for an MDL to have a bias towards a particular direction of such mappings, and this might mean that a description given in that language can only support certain kinds of applications. In [Ramsey], Ramsey et al suggest expressing relationships rather than (one-way) mappings.
The language is technology dependent.
It is quite common for the description formalism of an MDL to be tied to a particular technology. For example, an MDL might describe instruction semantics in terms of a particular intermediate representation (IR), making it of limited use with technologies that do not use that IR.

Applicability to virtual execution environments

People typically associate most of the languages discussed here primarily with hardware development, for good reason. When talking about these languages in the context of the development of software-based execution environments, one has to consider what difference it makes whether such a language is being used to describe a hardware machine or a virtual execution environment.

Emulators and simulators

HDL implementations often support the synthesis of both hardware and a simulator from the same description. Indeed, there are languages (such as SystemC) that are implemented on top of a GPL in such a way that hardware descriptions can be directly compiled to produce a simulator, using a compiler for the GPL.

Whether a generated simulator is usable as an emulator entirely depends on the kind of a simulator that is produced. If the end result behaves the same as the simulated hardware, and runs with adequate speed, it may well be useful for interactively trying out software targeted for the simulated platform. This is assuming that a complete enough platform can be assembled, which for a complex system would likely involve assembling the system from multiple hardware component emulators generated from separate descriptions.

It may be difficult to generate efficient code for an emulator if the only available hardware description is structural and low-level. From such a description it is likely to be hard to deduce higher-level functional semantics easier to map to efficient software, which might lead to one being forced to closely emulate the hardware behavior at the level of individual circuits. One is in a better situation if one has a SystemC-based description, for instance, as it probably already includes a suitably high-level functional description in the form of straightforward C++ code implementing the functionality. Even better would be to have such target and host descriptions that the generated emulator would support binary translation, but such support is rare for the average HDL. (See Overview of Emulation Methods for more discussion on the efficiency of various emulation methods in general.)

Developer toolkits

In cases where an emulator is functionally equivalent to the described hardware machine, the same developer tools (compiler, assembler, etc.) should for the most part be usable regardless of whether targeting the emulator or the hardware. Hence the benefits of any support for toolkit generation based on a machine description should extend to emulators as well.

Virtual machines

Virtual machines (VMs)—as in applications-level emulators emulating imaginary, non-native systems—may behave quite different to a typical hardware machine. Considering then that for instance the Spawn description language is only suitable for describing the instruction sets of RISC processors, but not CISC processors [Ramsey], it is unlikely that the average hardware focused MDL would be able to describe the instruction set of a Java VM (JVM), for instance. It is, however, possible to design an MDL capable of describing the instruction sets of at least some typical virtual machines, as demonstrated by Vmgen.

Motivation for description language development

In short, description languages are developed to enable hardware and software synthesis. Synthesized systems and components commonly include:

  • digital circuits
  • hardware simulators
  • machine language interpreters and binary translators for emulators and virtual machines
  • parts of tools working with machine-code—examples of such tools are compilers, debuggers, binary translators, instruction level profilers, link-time optimizers, executable editors, etc.

What is described with description languages

When writing a system description, the description author focuses on certain aspects of the system at a time, at a chosen abstraction level. While some languages (e.g., SystemC) scale to encompass more than one abstraction level, it is also common to use different languages for different design tasks, and indeed, some aspects of a system design may only be documented informally. The kinds of descriptions for which machine-readable description languages are typically used are:

architectural description
A description supporting design work; not directly used to synthesize hardware or software. Helps to see an overall picture of a system, and may be used to help create and verify lower-level descriptions.
behavioral description
Looks at a system mostly as a "black box", typically just describing its input/output behavior. Must capture the effects of input on system state, where the state affects output. Useful for creating simulators for testing and verification.
structural description
Describes hardware components and their interconnections. Required for hardware synthesis.

The kinds of things that one might describe include:

  • hardware architecture, behavior, and layout
  • processor instruction set syntax and semantics
  • procedure calling conventions and stack frame layouts
  • instrumentation points and actions
  • executable file formats
  • device communication (in device drivers)

An overview of the description language scene

The best-known hardware description languages include VHDL and Verilog. Verilog and VHDL are "rival" languages, which can both be used for specifying and simulating digital circuits. The two languages have a different character, but roughly the same set of features [1]; there are tools that support both languages. Both languages have a subset that can be synthesized, but not translated into hardware. VHDL is perhaps a slightly higher-level language in terms of abstraction, but neither language is particularly high-level. Indeed, there are a large number of other HDLs (e.g., Atom, MyHDL) that are implemented by translating them into VHDL or Verilog.

SystemC is also among the best-known HDLs. It provides features similar to those of VHDL and Verilog, while also adding higher-level constructs useful in system level design.

MDLs are useful in creating compilers and other development tools dealing with machine code, but as existing MDLs tend to be fairly tool-specific, they are not by themselves as well known as standardized, tool-independent HDLs. Some of the tools using MDLs are well-known, however, and the popular GCC compiler in particular is worth mentioning as it is open source, allowing its internal machine descriptions to be examined. In compilers, MDLs are commonly used as a basis for defining how to perform instruction selection for each target machine, and this is the case with GCC as well. Instruction syntax descriptions are useful in a variety of tools.

In the context of tools development it is also interesting to consider tools that deal not only with (binary) machine code, but also (textual) source code. If a compiler can be made retargetable via machine descriptions, one might attempt to also make it "resourceable" via source language descriptions of some kind. Source language grammar descriptions are commonly used as a basis for generating parsers, but one might also want to be able to generate scope analyzers, type checkers, etc. There is a lot of literature related to formalisms for describing programming language semantics, but for instance a dissertation by Iversen [Iversen] surveys some existing technologies that use source language descriptions in compiler generation. There is also interest in abstracting away target (programming) language differences when generating tools; for instance one of Ramsey's papers [RamseyRPG] talks about this.

Somewhat related to MDLs are languages for describing procedure calling conventions [Bailey] [CifuentesPAL] [Olinsky]. While calling conventions have more to do with library ABIs than machines, they are still relevant to compiler backend developers at least. More unusual existing description languages include languages for describing: processor execution pipelines [Milner], executable instrumentation [CifuentesWA], and executable file formats [2]. There are also languages for describing device communication [Reveillere], intended to support device driver development.

Description language design and implementation

Advice regarding MDL design can be found from a paper by Ramsey [Ramsey], and DSL design and implementation in general is discussed in a number of texts, an example of which is a technical report by Mernik [Mernik]. A fairly popular approach to implementing description languages appears to be embedding within a GPL, as the parent language often offers useful abstractions and a familiar syntax. HDLs based on a GPL include SystemC, Atom, and Lava.

Hardware versus software description languages

A notable difference between HDLs and traditional (software) programming languages is that while programming in traditional programming languages is inherently sequential, HDLs must be able to express parallelism. However, with multicore processors becoming commonplace, there is increasing need for software programming languages with better support for concurrency [3], so perhaps this difference will one day go away.

There is a desire to describe both software and hardware based computation in the same way. Mentor Graphics, for instance, exploit this demand with their Catapult Synthesis product, which they claim to "synthesize multi-block pipelined and concurrent hierarchical designs from pure sequential ANSI C++".

It might be appropriate to use the same languages for describing both hardware and software, as the advent of field-programmable gate arrays (FPGAs) and the increasing use of emulators in products are blurring the distinction between hardware and software. An article by Vahid [Vahid] goes as far as to suggest that we should stop calling circuits "hardware" and, more generally, broaden our concept of what constitutes "software". [Vahid]

Sample technologies

GCC

GCC (GNU Compiler Collection) is an example of a widely-used technology that makes use of machine descriptions for purposes of retargetability. The MDL used, in turn, is an example of a hard-to-reuse language, since the description formalism itself is tied to a particular compiler [Ramsey], namely GCC. The machine descriptions used in GCC are described fairly well in the GNU Compiler Collection (GCC) Internals document.

An example machine description snippet is shown below, as extracted from an md file from within GCC source [4]. The particular snippet shows an instruction pattern to be matched against an intermediate representation (IR) tree, in this case specifying how to map a particular addition operation "shape" into Thumb assembly code. The match_operand expressions are placeholders for operands, and the operands are mapped to the placeholders shown in the assembly code template based on their numbering. clobber is merely a compiler hint to indicate that the specified register may be affected. add is a Thumb addition instruction, while adc is addition with carry.

(define_insn "*thumb_adddi3"
  [(set (match_operand:DI          0 "register_operand" "=l")
	(plus:DI (match_operand:DI 1 "register_operand" "%0")
		 (match_operand:DI 2 "register_operand" "l")))
   (clobber (reg:CC CC_REGNUM))
  ]
  "TARGET_THUMB"
  "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2"
  [(set_attr "length" "4")]
)

SystemC

SystemC is a popular hardware modeling solution supporting design abstractions at the register transfer, behavioral, and system levels. [Panda]

The hardware models are described in a language that consists of standard C++ and an IEEE standardized SystemC API. [5] The SystemC language supports multiple levels of abstraction by including constructs analogous to those provided by traditional HDLs (e.g., VHDL and Verilog), while also adding higher-level constructs useful in system-level design.

There is an open source implementation consisting of the SystemC class library and a simulation kernel. A SystemC model written by the user can be compiled for the development host with a standard C++ compiler, with the resulting host-native executable forming a simulator for the described system. [6]

A typical SystemC-based design flow aiming for hardware synthesis involves the creation of a system-level design, then a behavioral design, then a register-transfer list (RTL) level design, and finally a gate-level netlist. The specification language can remain the same across these abstraction-decreasing transitions, and tools may be used to reduce the amount of manual work required during the design process. [Panda]

SLED

SLED (Specification Language for Encoding and Decoding) [RamseySLED] is a language for describing abstract, binary, and assembly-language representations of machine instructions. SLED is suitable for describing both CISC and RISC machines; it has been used to describe MIPS R3000, SPARC, Alpha, Intel Pentium, Power PC, and Motorola 68000 instructions. [RamseySLED]

Ramsey et al, the authors of SLED, suggest that in building systems software, it may make sense to use what they call a "loose confederation of languages" for describing the system specifics. [Ramsey] Systems have a variety of system-specific aspects that matter when building systems software, and it takes time to design a language, so the focus should be on reuse. For better reuse, language designers might want to avoid making languages tool or system specific, and make use of existing languages when suitable.

To tie together a confederation of languages, Ramsey et al suggest having those languages refer to shared semantic models of essential aspects of machines. Ramsey et al studied a number of existing descriptions used for building systems software, and identified the requirement for languages to refer either to a machine's instruction set, to storage locations of a machine's state, or both. [Ramsey] SLED refers only to instructions, not to state. An instruction set is modelled as a grammar that gives the abstract syntax of instructions and addressing modes. [Dias]

SLED itself uses four elements: fields and tokens describe parts of instructions; patterns describe binary representations of instructions or groups of instructions; and constructors map between the abstract and binary levels. [RamseySLED]

Concise descriptions have been achieved with SLED, ranging in size from 125-250 lines for machines like the MIPS, Alpha, and SPARC, to about 500 lines for the Pentium. [Ramsey] The conciseness is in large part due to the power of SLED's pattern language, which makes it possible to specify constraints on the relationships between instructions and their operands and fields, and even apply such constraints to groups of similar instructions in one go.

Example SLED code is shown below, extracted from an existing SLED specification for MIPS [7]. In the example, the fields declaration names certain bit ranges of 32-instructions. The two patterns declarations specify values for some of these fields for some instructions. For instance, in the binary representation of the bgez (branch) instruction, both the op and cond bit ranges have the value 1.

fields of instruction (32) 
word 0:31 op 26:31 cond 16:20

patterns
 [ special bcond j jal beq bne blez bgtz ]
 is op = {0 to 7}

patterns
 [ bltz bgez bltzal bgezal ] is bcond & cond = [ 0 1 16 17 ]

The New Jersey Machine-Code Toolkit implements SLED, providing support for encoding and decoding machine instructions based on SLED descriptions.

λ-RTL

λ-RTL is another member of Ramsey et al's "federation" of MDLs. The purpose of λ-RTL is to describe the semantics of machine instructions. It does so in the sense of how executing an instruction changes the state of the machine. [Ramsey] This necessarily means that λ-RTL is concerned both with the machine instruction set and machine state.

λ-RTL uses the same instruction set model as SLED, while machine state is modelled as a collection of storage spaces, each of which is an array of cells. For example, $r[0] refers to the first cell in the 'r' space. [Dias]

To define state changes, each instance of an instruction is assigned a function from storage spaces to storage spaces. The functions are specified as RTLs. [Ramsey] Whereas bare RTLs are spartan and lead to verbose descriptions, λ-RTL provides additional abstractions to enable more concise description, while still remaining translatable to RTLs.

λ-RTL is inspired by Standard ML, and hence has its foundations on typed lambda calculus; this—together with the use of RTLs—explains the name of the language. Despite the strong static typing, types need not be written explicitly, due to the language supporting type inference. Type checking is helpful in catching mistakes such as accidentally attempting to assign a 16-bit value to a 32-bit register.

An example snippet of λ-RTL code is shown below, extracted from an existing λ-RTL specification for SPARC [8]. The snippet shows how the semantics for a group of arithmetic instructions (i.e., add, addcc, ...) can essentially all be specified at once, without having to separately spell out the RTL for each of them. Instead, parameterized "meta-functions" (such as add_instruction) that evaluate to the appropriate RTL for each instruction are used. Note that not all the relevant declarations are shown here.

fun set_cc(result, overflow, carry) is
  icc.N := bit (result < 0) |
  icc.Z := bit (result = 0) |
  icc.V := overflow |
  icc.C := carry

fun add_instruction (rs1, operand2, carry_in, rd, {set_codes}) is 
  let val {result, carry is carry_out} is add($r[rs1], operand2, carry_in)
  in   $r[rd] := result
     | set_codes -->
         set_cc(result, bit(add_overflows ($r[rs1], operand2, carry_in)), carry_out)
  end

[add addcc addx addxcc] (rs1, reg_or_imm, rd) is 
  add_instruction(rs1, reg_or_imm, [0 carryBit], rd, {set_codes is [false true]})

λ-RTL enables reasonably compact descriptions; it apparently can describe 160 SPARC instructions in about 300 lines of code. [Ramsey]

There is an existing, still immature implementation of λ-RTL available for download. What it does is translate λ-RTL descriptions into canonical-form RTL ones.

UQBT

The University of Queensland Binary Translator (UQBT) framework is a static, retargetable (both input and output machine) system supporting static binary translation across a variety of source and target machines. [9]

To achieve retargetability (and "resourceability") UQBT uses a variety of description languages. These include two MDLs, namely SLED and SSL (Semantic Specification Language) [CifuentesSSL], the latter of which is for describing machine instruction semantics. UQBT also uses languages that are strictly speaking not MDLs, but rather concern operating system and compiler specific issues. These languages include: PAL (Procedural Abstraction Language) [CifuentesPAL] for describing calling conventions, parameter passing conventions, stack frames and local variable locations; and BFF (Binary File Format) for describing binary file formats (such as ELF for Solaris and Linux systems). [10]

Walkabout

Walkabout is a retargetable binary translation framework for experimenting with dynamic translations of machine code. It supports the instantiation of emulators for different machines, as well as the development of dynamic translators that use such emulators to determine what code paths are hot (i.e., frequently executed) and then generate native code on-the-fly for those paths. Walkabout is based on ideas and experience learned during the development of UQBT. [11]

Again, to separate machine-dependent concerns, Walkabout exploits a variety of description languages. As with UQBT, SLED and SSL are used to describe instruction sets. SLED and SSL can together express specifications containing all the information required to generate a machine code interpreter. SSL allows one to specify the mapping between assembly instructions and their equivalent register transfers, to name new registers and declare overlaps, to define superoperators in the form of macros for commonly set condition codes, and to specify the fetch-execute cycle for a machine. [CifuentesWA]

Walkabout authors also designed a new language called INSTR [CifuentesWA] (for instrumentation language), which can be used to specify which instructions to instrument and how. Walkabout relies on instrumentation for determining hot paths.

Vmgen

Vmgen is an interpreter generator with a focus on stack-based VMs. Vmgen takes a VM instruction set description as input and generates C code for processing the instructions in several ways (code generation, execution, disassembly, etc.). The generator has been used to create interpreters for Forth and Java, at least. [Ertl]

Vmgen supports several optimizations, for instance some having to do with stack access and branch prediction. For generated interpreters, the authors claim interpretation speeds usually better than those of competing interpreters, and typically only a factor of 2-10 slower than the code generated by native-code compilers. [12]

Vmgen descriptions contain, for each instruction:

  • an instruction specification (what values to pop and push off the stack, their order, types, names, etc.)
  • action code in C (some support macros are provided)

Instruction specification samples extracted from Gforth source code [13] are shown below. Here add, for instance, pops two values off the stack, sums them, and pushes the result onto the stack. lit, in turn, takes a value from the instruction stream, and pushes it onto the stack.

add ( i1 i2 -- i )
i = i1+i2;

not ( i1 -- i2 )
i2 = !i1;

lit ( #i -- i )

drop ( i -- )

print ( i -- )
printf("%ld\n", i);

branch ( #target -- )
SET_IP(target);

See also

External links

References

[Bailey] Mark W. Bailey and Jack W. Davidson. A formal model and specification language for procedure calling conventions. ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL), pages 298–310. January 1995. [14]

[CifuentesPAL] Cristina Cifuentes and Doug Simon. Procedural abstraction recovery from binary code. Technical Report 448. University of Queensland. Brisbane, Australia. September 1999. [15]

[CifuentesSSL] Cristina Cifuentes and Shane Sendall. Specifying the semantics of machine instructions. Technical Report 422. University of Queensland. Brisbane, Australia. December 1997. [16]

[CifuentesWA] Cristina Cifuentes, Brian T. Lewis, and David Ung. Walkabout—A retargetable dynamic binary translation framework. Fourth Workshop on Binary Translation. Charlottesville, Virginia. September, 2002. [17]

[Dias] João Dias and Norman Ramsey. Converting intermediate code to assembly code using declarative machine descriptions. 15th International Conference on Compiler Construction (CC 2006). March 2006. [18]

[Ertl] M. Anton Ertl, David Gregg, Andreas Krall, and Bernd Paysan. vmgen—A generator of efficient virtual machine interpreters. Software: Practice and Experience, vol. 32, no. 3, pages 265–294. 2002. [19]

[Iversen] Jørgen Iversen. Formalisms and tools supporting constructive action semantics. PhD thesis. Department of Computer Science, University of Aarhus, Denmark. May 2005. [20]

[Mernik] Marjan Mernik, Jan Heering, and Anthony M. Sloane. When and how to develop domain-specific languages. Technical report, SEN-E0517, ISSN 1386-369X. CWI. December 2005. [21]

[Milner] Christopher W. Milner. Pipeline descriptions for retargetable compilers: A decoupled approach. Technical report CS-99-11. University of Virginia. June 1998. [22]

[Mishra] Prabhat Mishra and Nikil Dutt. Architecture description languages. Customizable and Configurable Embedded Processors. Paolo Ienne and Rainer Leupers, editors. Morgan Kaufmann Publishers, 2006. [23]

[MishraE] Prabhat Mishra and Nikil Dutt. Architecture description languages for programmable embedded systems. IEE Proceedings on Computers and Digital Techniques (CDT), Special issue on Embedded Microelectronic Systems: Status and Trends, volume 152, no 3, pages 285–297. May 2005. [24]

[Olinsky] Reuben Olinsky, Christian Lindig, and Norman Ramsey. Staged allocation: engineering the specification and implementation of procedure calling conventions. ACM Symposium on Principles of Programming Languages (POPL'06). January 2006. [25]

[Panda] Preeti Ranjan Panda. SystemC—A modeling platform supporting multiple design abstractions. International Symposium on System Synthesis (ISSS). Montreal, October 2001. [26]

[Ramsey] Norman Ramsey, Jack Davidson, and Mary F. Fernández. Design principles for machine-description languages. Unpublished. [27]

[RamseyRPG] Norman Ramsey. Pragmatic aspects of reusable program generators. Journal of Functional Programming, 13(3):601-646, May 2003. [28]

[RamseySLED] Norman Ramsey and Mary Fernández. Specifying representations of machine instructions. ACM Transactions on Programming Languages and Systems, 19(3):492-524. May 1997. [29]

[Reveillere] Laurent Réveillère, Fabrice Mérillon, Charles Consel, Renaud Marlet, and Gilles Muller. A DSL approach to improve productivity and safety in device drivers development. 15th IEEE International Conference on Automated Software Engineering (ASE 2000), Grenoble, France, pages 101–109, September 2000. IEEE Computer Society Press. [30]

[Vahid] Frank Vahid. It's time to stop calling circuits "hardware". IEEE Computer Magazine. September 2007. [31]