Hardware-Software Co-Design
Hardware-software co-design moves away from the traditional sequential approach, in which hardware is designed first and software follows. Instead, co-design methodologies treat hardware and software as equal partners in system development, enabling engineers to make informed trade-offs between implementation options throughout the design process.
This integrated approach becomes increasingly critical as embedded systems grow more complex and performance requirements more demanding. By considering hardware and software alternatives simultaneously, designers can achieve better partitioning of functionality, meet stringent timing constraints, reduce development time, and create systems that would be difficult to realize through sequential design methods alone.
The discipline emerged in the early 1990s, when research systems such as COSYMA and Vulcan demonstrated that partitioning could be automated. COSYMA began with the entire application running in software on a processor and migrated computationally heavy loop nests into custom hardware until performance targets were met. Vulcan took the opposite path, starting with an all-hardware implementation and moving functions back to the processor to reduce cost. Later frameworks, including POLIS and the Ptolemy project, extended these ideas with formal models of computation. Modern commercial flows inherit the same core insight: the boundary between hardware and software is a design variable, not a given.
This category approaches co-design from the embedded-systems side, following the flow from executable specification through partitioning, interface definition, and co-simulation to a working prototype. A companion treatment under digital electronics, hardware-software co-design, covers the same discipline from the digital design perspective and develops system partitioning, interface design, embedded software, and co-verification as separate articles.
Core Concepts
At its foundation, hardware-software co-design addresses the question of how to partition system functionality between hardware and software implementations. A dedicated hardware implementation typically offers superior throughput, lower latency, and better energy efficiency for a specific operation, because it can exploit parallelism and avoid instruction-fetch and decode overhead. Software running on a general-purpose processor provides flexibility, easier modification, faster debugging, and lower non-recurring engineering cost. The challenge lies in finding the partition that meets every system requirement at acceptable cost.
Co-design methodologies employ unified system representations that abstract away implementation details, allowing designers to explore the solution space before committing to a specific hardware or software realization. This abstraction enables automatic or semi-automatic partitioning tools to suggest divisions of functionality based on constraints such as performance, silicon area, power consumption, and time-to-market. Because a single algorithm can often be mapped to a processor core, a custom datapath, a custom instruction added to the processor pipeline, or a programmable accelerator, the same functional specification can yield many valid implementations, each with a different cost-performance profile.
Three properties distinguish co-design from conventional design. First, the specification is implementation-neutral: it describes what the system does, not whether a gate array or a C function does it. Second, estimation replaces measurement early in the flow, so partitioning decisions rest on models of area, latency, and power rather than on finished implementations. Third, the flow is explicitly iterative, because early estimates prove optimistic often enough that designers must revisit the partition as real numbers arrive.
Articles in This Category
The articles below cover the core disciplines of hardware-software co-design, from system modeling through verification and prototyping. Each addresses a distinct stage of the co-design flow.
The Co-Design Flow
A co-design flow proceeds through several distinct stages. The stages are conceptually sequential, but the flow returns to earlier stages whenever new information invalidates an assumption.
Specification and Executable Modeling
The flow begins with system specification, in which functional and non-functional requirements are captured in a technology-independent manner. The specification is then translated into an executable model that can be simulated and analyzed. Executability matters: a model that runs can be profiled, and profiling data drives every partitioning decision that follows. Several established formalisms support this stage, including the Ptolemy project's actor-oriented models, synchronous dataflow for signal-processing pipelines, and Kahn process networks for streaming systems. Each formalism trades expressiveness for analyzability; synchronous dataflow, for example, restricts token production and consumption rates to constants, which in return permits static scheduling and provable bounds on buffer sizes.
Partitioning and Design Space Exploration
The executable model serves as the foundation for design space exploration, in which different partitioning options are evaluated against system constraints. The Y-chart approach, introduced by Daniel Gajski and Robert Kuhn in 1983 and later adapted specifically for system-level exploration, separates the application description from the architecture description and evaluates their mapping as a distinct step. Keeping these three concerns separate lets a designer test one application against several candidate architectures, or several applications against one architecture, without rewriting either description.
Exploration rarely yields a single winner. It yields a Pareto front: a set of designs for which no alternative improves one objective without degrading another. Choosing among Pareto-optimal points is an engineering and business decision that weighs unit cost, schedule risk, and expected product lifetime alongside the technical metrics.
Refinement, Co-Simulation, and Implementation
Once a promising partition is identified, hardware and software components are refined and implemented in parallel. Co-simulation environments allow the evolving hardware and software to be tested together continuously, confirming interface compatibility and functional correctness. A common arrangement couples an instruction-set simulator for the processor with an event-driven simulator for the register-transfer-level hardware, synchronizing the two at transaction boundaries rather than at every clock edge to keep simulation speed tolerable.
The process is inherently iterative. Designers backtrack and adjust partitioning decisions as more detailed implementation information, such as accurate area, timing, and power estimates, becomes available. Discovering after synthesis that an accelerator misses its timing target by twenty percent may force a function back into software, or force a redesign of the datapath, and the earlier that discovery arrives the cheaper it is.
Partitioning Criteria and Metrics
Sound partitioning rests on quantitative criteria rather than intuition. Profiling identifies the functions that dominate execution time, and those functions become accelerator candidates. Amdahl's law bounds the payoff: if a function consumes 60 percent of total run time, accelerating it infinitely still limits overall speedup to 2.5 times. This bound is the single most common reason an accelerator disappoints in practice, and it argues for accelerating a broad hot region rather than one narrow inner loop.
Communication cost frequently decides the outcome. Moving a function to hardware only helps when the data it consumes and produces can reach it cheaply. A function with a high computation-to-communication ratio, such as a block cipher round or an FIR filter operating on streamed samples, suits hardware well. A function that touches scattered pointers in main memory often runs faster on the processor, where the cache hierarchy already serves it. Designers therefore evaluate partitions on the granularity of the interface as much as on the compute kernel itself.
Cost structure matters as much as performance. Custom silicon carries substantial non-recurring engineering cost in design, verification, and mask sets, amortized over volume; software carries almost none but consumes processor cycles and memory on every unit shipped. An FPGA sits between the two, trading unit cost and clock frequency for the ability to change the hardware after deployment. Field upgradability, certification burden, and expected product lifetime all pull the partition in one direction or another. In safety-critical domains the split even changes which standards apply: in avionics, functions implemented in software fall under DO-178C, while complex airborne electronic hardware falls under DO-254, and the two carry different evidence obligations.
Typical objective functions therefore combine execution time or throughput, silicon area or FPGA resource utilization, average and peak power, memory footprint, interface bandwidth, and development effort. Because these objectives conflict, most exploration tools treat partitioning as a multi-objective optimization problem rather than searching for a single optimum.
The Hardware-Software Interface
Every partitioning decision creates an interface, and interfaces are where co-designed systems most often fail. The hardware side exposes a register map: control and status registers, configuration fields, and data ports, each with defined access rules and reset values. The software side supplies a driver that programs those registers in the correct order and interprets the results. Specifying this contract precisely, and generating both sides from one machine-readable description, eliminates a large class of integration defects.
Data movement follows one of a few patterns. Programmed input and output, in which the processor copies each word to or from the accelerator, is simple but consumes processor cycles proportional to the data volume. Direct memory access lets the accelerator read and write memory independently, freeing the processor but introducing coherence questions: if the processor caches a buffer that an accelerator later overwrites, software must invalidate or flush the affected cache lines, or the interconnect must maintain coherence in hardware. Streaming interfaces avoid shared memory entirely by passing data through first-in, first-out channels.
Synchronization presents a parallel set of choices. Polling a status register is straightforward and predictable but wastes cycles and energy. Interrupts free the processor between events at the cost of latency and context-switch overhead, and they complicate worst-case timing analysis in real-time systems. Many designs combine the two, using interrupts for infrequent completion events and polling for short, tightly bounded waits.
Standards and Tools
The hardware-software co-design ecosystem rests on a set of open standards that make models and components portable between tools.
Modeling and Packaging Standards
SystemC, standardized as IEEE 1666 and most recently revised as IEEE 1666-2023 with a corrigendum issued in 2025, provides a unified C++ class library for system-level modeling. Its TLM-2.0 transaction-level modeling interfaces enable fast, interoperable simulation of complex systems on chip by replacing pin-level signaling with function calls that carry a generic payload. TLM-2.0 defines a loosely timed coding style, which favors simulation speed and suits software development, and an approximately timed style, which models transaction phases in more detail and suits architectural analysis.
IP-XACT, standardized as IEEE 1685 and most recently revised as IEEE 1685-2022, defines an XML schema for packaging intellectual-property metadata so that IP blocks can be exchanged and integrated across vendor tool flows. The standard is developed by the Accellera Systems Initiative and handed to the IEEE for balloting. Because an IP-XACT description captures the register map alongside the interface definition, it serves directly as the single source from which register-transfer-level decode logic, driver headers, and documentation are generated.
On-Chip Interconnect
Interconnect standards provide the communication fabric that links accelerators to processors. The Arm AMBA family dominates commercial system-on-chip design: APB serves low-bandwidth peripheral registers, AHB serves moderate-bandwidth traffic, AXI provides high-throughput burst transfers with independent read and write channels, and CHI addresses coherent multi-core interconnect. In the open-source and academic world, the Wishbone bus remains widely used, and TileLink has become common in the RISC-V ecosystem. The choice of fabric constrains achievable bandwidth and latency, so it belongs in the exploration stage rather than after partitioning is settled.
Synthesis and Virtual Platforms
High-level synthesis tools compile C, C++, or SystemC descriptions into register-transfer-level hardware, which shortens the loop between a software function and its hardware equivalent. Widely used commercial tools include Siemens Catapult, Cadence Stratus, and AMD Vitis HLS. Because the same source can be compiled for the processor or synthesized to hardware, high-level synthesis makes moving the partition boundary considerably cheaper than a manual rewrite in a hardware description language.
Virtual platforms model an entire system in software so that firmware development begins long before silicon or even FPGA prototypes exist. QEMU and Arm Fast Models are common examples, and open-source register-transfer-level simulators such as Verilator allow cycle-accurate models to be embedded in the same environment. Teams typically run a fast, loosely timed virtual platform for software bring-up and switch to a slower, more accurate model only when timing questions demand it.
Applications and Impact
Hardware-software co-design has transformed the development of complex embedded systems across many domains. Mobile devices rely on co-design to balance performance against battery life, mapping computationally intensive tasks such as video encoding, image signal processing, and neural inference onto dedicated hardware blocks while keeping application logic and policy in software. The resulting application processors are deeply heterogeneous, combining general-purpose cores, digital signal processors, graphics processors, and fixed-function blocks under one software stack.
Automotive systems use co-design to meet hard real-time and functional-safety requirements under ISO 26262, whose automotive safety integrity levels range from ASIL A to the most stringent ASIL D. Placing a safety function in hardware or in software changes the verification evidence required, so the partition is a safety decision as well as a performance decision. In telecommunications, co-design underpins software-defined radios that combine flexible signal-processing software with high-throughput hardware accelerators for filtering, modulation, and forward error correction.
Machine learning at the edge depends heavily on co-design to fit neural-network inference within tight power and memory budgets. Here the co-design loop extends into the algorithm itself: quantizing a network to eight-bit or lower precision, pruning it, or restructuring its layers changes what the accelerator must support, and accelerator constraints in turn shape the network architecture. As systems continue to grow in complexity and heterogeneity, the principles and practices of hardware-software co-design remain central to successful embedded development.
Summary
Hardware-software co-design treats the boundary between hardware and software as a design variable to be optimized rather than a decision to be made in advance. Its practice rests on executable specifications, quantitative partitioning criteria, careful interface definition, and continuous co-simulation, all supported by standards such as SystemC and IP-XACT and by high-level synthesis and virtual-platform tools. The topics in this category examine each stage in detail. Whether you are partitioning a system for the first time or optimizing an existing one, a firm grasp of co-design methodologies will strengthen your ability to create efficient, high-performance embedded systems.
Related Topics
Co-design draws on material covered elsewhere in this guide. The following articles provide useful background and adjacent detail.