Il co-design hardware/software (spesso abbreviato in co-design HW/SW) è una metodologia di progettazione a livello di sistema in cui i componenti hardware e software vengono sviluppati insieme anziché separatamente. Il suo obiettivo è migliorare le metriche a livello di sistema come le prestazioni, il consumo energetico, il costo e la flessibilità, provando diversi modi di suddividere le funzionalità tra hardware e software fin dalle prime fasi della progettazione.

Il co-design hardware/software è ampiamente utilizzato nei sistemi embedded, nei sistemi cyber-fisici, e nelle piattaforme di calcolo eterogeneo, dove l'esecuzione del software e l'accelerazione hardware devono operare in stretta collaborazione.

Panoramica Il co-design hardware/software si basa sul principio che i vincoli hardware e software vengano considerati simultaneamente, in modo che le decisioni su un lato possano essere prese tenendo conto dell’altro. Una stessa funzione può essere implementata sia in software su un processore sia in logica hardware dedicata, con effetti congiunti su prestazioni, consumo energetico, area e costo. Mantenendo entrambi gli aspetti aperti nelle prime fasi della progettazione, il co-design consente di esplorare combinazioni che un approccio unilaterale non sarebbe in grado di individuare.

Nel co-design, il confine tra hardware e software è trattato come una variabile di progetto. Le operazioni computazionalmente intensive e regolari vengono tipicamente implementate in hardware dedicato, mentre la logica di controllo e le parti soggette a variazioni restano nel software. I parametri che definiscono questa suddivisione, come la larghezza dei bit, la dimensione dei buffer e il grado di parallelismo, sono condivisi tra i due domini invece di essere fissati separatamente.

Storia Il co-design hardware/software prese forma alla fine degli anni ’80 e all’inizio degli anni ’90, quando i sistemi embedded stavano diventando sempre più complessi e la pratica tradizionale di progettare hardware e software separatamente iniziò a mostrare i propri limiti. Molti dei primi prodotti embedded, come apparecchiature per le telecomunicazioni, controllori industriali ed elettronica di consumo, presentavano vincoli stringenti di prestazioni e consumo energetico che non potevano essere soddisfatti ottimizzando il solo software.

Le prime ricerche esplorarono la possibilità di progettare congiuntamente hardware digitale e software embedded, in modo che una determinata funzione potesse essere implementata sia su un processore sia in logica hardware dedicata. In questo contesto furono sviluppati metodi formali per la partizione hardware/software, la specifica a livello di sistema e la stima delle prestazioni, mentre gli strumenti di automazione della progettazione elettronica (EDA) iniziarono a supportare flussi di progettazione integrati.

Nel corso degli anni ’90, il co-design si legò sempre più strettamente ai sistemi embedded e alla progettazione dei sistemi su chip (SoC). Con l’integrazione di processori, memorie, periferiche e logica personalizzata su un unico chip, la progettazione congiunta di hardware e software divenne essenziale per soddisfare i vincoli di costo, prestazioni e consumo energetico.

La crescente diffusione delle field-programmable gate array (FPGA) negli anni 2000 ampliò ulteriormente il campo di applicazione del co-design. A differenza degli application-specific integrated circuit (ASIC), le FPGA possono essere riprogrammate dopo la produzione, consentendo di modificare l’hardware insieme al software. Gli strumenti di sintesi ad alto livello (HLS) ridussero ulteriormente la barriera d’ingresso, permettendo di tradurre in hardware digitale parti di programmi scritti in linguaggi ad alto livello come C e C++.

La crescente adozione delle field-programmable gate array (FPGA) negli anni 2000 ampliò ulteriormente il campo di applicazione del co-design. A differenza degli application-specific integrated circuit (ASIC), le FPGA possono essere riprogrammate dopo la produzione, quindi l'hardware può essere modificato insieme al software. Gli strumenti di sintesi ad alto livello (HLS) abbassarono ulteriormente la barriera consentendo di trasformare in hardware digitale parti di un programma scritte in linguaggi ad alto livello come il C e il C++.

Più recentemente, il co-design hardware/software è stato adottato nell’intelligenza artificiale (IA), nel cloud computing e nel calcolo eterogeneo. Gli acceleratori per IA, le architetture per data center e le architetture a dominio specifico possono essere progettati con approcci di co-design per aumentare le prestazioni per watt, mantenendo al contempo sotto controllo flessibilità e costi di sviluppo.

Confronto con altre metodologie Le metodologie di sviluppo hardware/software sono comunemente descritte come uno spettro che va dallo sviluppo indipendente al co-design integrato.

Progettazione indipendente hardware/software

Nel modello di progettazione tradizionale, hardware e software vengono sviluppati in larga misura in modo autonomo. Gli ingegneri hardware progettano una piattaforma in base a vincoli architetturali, mentre gli sviluppatori software scrivono le applicazioni assumendo che l’interfaccia hardware rimanga invariata. I due gruppi comunicano principalmente attraverso set di istruzioni, interfacce di programmazione o livelli di astrazione hardware predefiniti.

Dato che i due domini sono disaccoppiati, ciascuno può evolvere a proprio ritmo. Questo approccio funziona bene per piattaforme di calcolo general-purpose, software desktop, sistemi operativi e hardware commerciale standard, dove una singola piattaforma deve supportare un’ampia gamma di programmi eterogenei.

Un limite di questo modello è che la separazione tra hardware e software riduce le possibilità di ottimizzazione trasversale tra i livelli. Il software non può sfruttare capacità hardware non presenti nel dispositivo, mentre l’hardware non può essere adattato al comportamento di applicazioni specifiche.

Ottimizzazione del software per l'hardware

Un approccio comune consiste nello scegliere prima l'hardware, per poi ottimizzare il software allo scopo di estrarne le massime prestazioni. L'hardware è trattato come fisso e gli sviluppatori adattano i propri algoritmi e il proprio codice per fare il miglior uso delle risorse disponibili.

Le tecniche tipiche includono ottimizzazioni del compilatore, vettorizzazione, buon utilizzo della cache, programmazione parallela, e un'organizzazione ottimizzata delle strutture dati in memoria. Inoltre, gli algoritmi possono essere riscritti per utilizzare istruzioni single istruction, multiple data (SIMD), o per utilizzare unità di elaborazione grafica (GPU) o processori di segnale digitale (DSP).

Ottimizzazione dell'hardware per il software

L'approccio opposto al precedente consiste nel partire da un'applicazione o da un da uno specifico carico di lavoro e progettare l'hardware in modo da accelerarne l'esecuzione. Tra gli esempi più comuni rientrano i kernel di elaborazione di segnale, l'inferenza delle reti neurali, gli algoritmi crittografici, la codifica e decodifica video e le pipeline di elaborazione delle immagini.

Questo approccio è impiegato da tempo nei sistemi embedded e real-time, dove i vincoli di consumo energetico e le limitate risorse hardware rendono conveniente l'adozione di soluzioni personalizzate. Progettare l'hardware attorno a un carico di lavoro noto consente infatti di ottenere un rapporto prestazioni per watt superiore rispetto a quello offerto da un processore general-purpose. Negli ultimi anni, lo stesso principio è stato esteso al cloud computing su larga scala e ai data center, dove acceleratori per l'intelligenza artificiale, come le tensor processing unit (TPU), vengono impiegati per ridurre il consumo energetico e migliorare le prestazioni per watt.

Co-design hardware/software

Il co-design si distingue dai tre approcci descritti in precedenza perché nessuno dei due domini viene definito per primo. Hardware e software sono considerati parti di un unico processo di progettazione iterativo e collaborativo e vengono sviluppati congiuntamente in funzione di obiettivi comuni.

A partire da una specifica a livello di sistema, diverse possibili partizioni tra hardware e software vengono valutate sulla base di metriche quali prestazioni, consumo energetico, area e costo. Il processo è tipicamente iterativo: i risultati di ciascuna valutazione guidano le decisioni progettuali successive, consentendo di affinare progressivamente entrambe le componenti del sistema.

Applicazioni Il co-design hardware/software è ampiamente utilizzato nei sistemi che combinano processori general-purpose con hardware specifico per applicazione. I domini applicativi tipici includono:

Sistemi embedded, dove il consumo energetico, l'area del chip e il costo di produzione sono i vincoli principali. Settore automobilistico e aerospaziale, dove cicli di controllo critici per la sicurezza devono soddisfare requisiti real-time. Telecomunicazioni ed elaborazione digitale del segnale, dove funzioni come filtraggio, modulazione e la correzione degli errori sono comunemente implementate in hardware dedicato. Visione artificiale ed elaborazione delle immagini, dove kernel di elaborazione dei pixel vengono spesso accelerati in hardware. Acceleratori di intelligenza artificiale, comprese le TPU, le neural processing unit (NPU) e i tensor core delle GPU, che vengono sviluppati insieme ai framework software e ai formati numerici che supportano. Data center e cloud computing, dove acceleratori basati su FPGA e ASIC vengono impiegati per accelerare carichi di lavoro legati a rete, archiviazione, basi di dati e apprendimento automatico Calcolo scientifico, dove acceleratori specifici per applicazione vengono utilizzati per eseguire in modo efficiente kernel computazionali, come calcoli a stencil, simulazioni di dinamica molecolare e operazioni di algebra lineare sparsa.

Flusso di lavoro di progettazione Un flusso di co-design hardware/software inizia tipicamente con una specifica a livello di sistema, seguita dalla partizione hardware/software, dall'esplorazione dello spazio di progetto e dalla stima delle prestazioni. Queste attività vengono generalmente svolte in modo iterativo, poiché i risultati di ciascuna fase influenzano spesso le decisioni prese nelle fasi successive.[

Partizione Hardware/Software La partizione stabilisce, per ogni funzione o kernel computazionale, se debba essere implementato come software su un processore oppure come blocco hardware dedicato. I kernel costituiti da operazioni aritmetiche regolari e altamente parallelizzabili, come la convoluzione, la moltiplicazione di matrici o le fasi della trasformata veloce di Fourier (FFT), sono candidati ideali per un'implementazione hardware. Al contrario, il codice con una logica di controllo complessa, le operazioni eseguite raramente e le funzionalità che si prevede possano evolvere nel tempo vengono generalmente mantenuti nel software.

La partizione è generalmente formulata come un problema di ottimizzazione multi-obiettivo, nel quale si cerca un compromesso tra tempo di esecuzione, consumo energetico, area di silicio, larghezza di banda della memoria e sforzo di sviluppo. Tra gli approcci proposti figurano la programmazione lineare intera, il partizionamento di grafi, gli algoritmi evolutivi, il simulated annealing e, più recentemente, euristiche basate sull'apprendimento automatico.

Esplorazione dello spazio di progetto