In molte applicazioni, una CPU la cui esecuzione delle istruzioni ha una relazione di temporizzazione nota con stimoli di input previsti può gestire attività che richiederebbero una CPU molto più veloce se la relazione fosse sconosciuta. Ad esempio, in un progetto che ho usato un PSOC per generare video, ho usato il codice per emettere un byte di dati video ogni 16 clock della CPU. Dal momento che testare se il dispositivo SPI è pronto e ramificare in caso contrario IIRC richiederebbe 13 clock, e un caricamento e l'archiviazione sui dati di output richiederebbe 11, non c'era modo di testare la disponibilità del dispositivo tra i byte; invece, mi sono semplicemente arrangiato in modo che il processore eseguisse esattamente 16 cicli di codice per ogni byte dopo il primo (credo di aver usato un carico indicizzato reale, un carico indicizzato fittizio e un archivio). La prima scrittura SPI di ogni riga è avvenuta prima dell'inizio del video, e per ogni successiva scrittura c'era una finestra di 16 cicli in cui la scrittura poteva avvenire senza sovraccarico o sovraccarico del buffer. Il ciclo di ramificazione ha generato una finestra di 13 cicli di incertezza, ma la prevedibile esecuzione di 16 cicli ha significato che l'incertezza per tutti i byte successivi si adattava alla stessa finestra di 13 cicli (che a sua volta si adattava alla finestra di 16 cicli di quando la scrittura poteva accettabilmente si verificano).
Per le CPU meno recenti, le informazioni sui tempi delle istruzioni erano chiare, disponibili e inequivocabili. Per i nuovi ARM, le informazioni sui tempi sembrano molto più vaghe. Capisco che quando il codice viene eseguito da Flash, il comportamento della memorizzazione nella cache può rendere le cose molto più difficili da prevedere, quindi mi aspetto che qualsiasi codice conteggio dei cicli dovrebbe essere eseguito dalla RAM. Anche quando si esegue il codice dalla RAM, tuttavia, le specifiche sembrano un po 'vaghe. L'uso del codice conteggio dei cicli è ancora una buona idea? In tal caso, quali sono le migliori tecniche per farlo funzionare in modo affidabile? In che misura si può presumere in sicurezza che un fornitore di chip non scivoli silenziosamente in un chip "nuovo migliorato" che rade un ciclo dall'esecuzione di determinate istruzioni in determinati casi?
Supponendo che il ciclo seguente inizi su un confine di parola, come si determinerebbe in base alle specifiche esattamente quanto tempo impiegherebbe (supponiamo che Cortex-M3 con memoria zero-wait-state; nient'altro sul sistema dovrebbe importare per questo esempio).
myloop: mov r0, r0; Brevi semplici istruzioni per consentire il prefetch di più istruzioni mov r0, r0; Brevi semplici istruzioni per consentire il prefetch di più istruzioni mov r0, r0; Brevi semplici istruzioni per consentire il prefetch di più istruzioni mov r0, r0; Brevi semplici istruzioni per consentire il prefetch di più istruzioni mov r0, r0; Brevi semplici istruzioni per consentire il prefetch di più istruzioni mov r0, r0; Brevi semplici istruzioni per consentire il prefetch di più istruzioni aggiunge r2, r1, # 0x12000000; Istruzione di 2 parole ; Ripeti quanto segue, possibilmente con diversi operandi ; Continuerà ad aggiungere valori fino a quando si verifica un carry ITCC aggiungecc r2, r2, # 0x12000000; Istruzione di 2 parole, più "parola" extra per itcc ITCC aggiungecc r2, r2, # 0x12000000; Istruzione di 2 parole, più "parola" extra per itcc ITCC aggiungecc r2, r2, # 0x12000000; Istruzione di 2 parole, più "parola" extra per itcc ITCC aggiungecc r2, r2, # 0x12000000; Istruzione di 2 parole, più "parola" extra per itcc ; ... ecc., con più istruzioni condizionali di due parole sub r8, r8, # 1 bpl myloop
Durante l'esecuzione delle prime sei istruzioni, il core avrebbe avuto il tempo di recuperare sei parole, di cui tre sarebbero state eseguite, quindi potrebbero esserci fino a tre pre-recuperate. Le istruzioni successive sono tutte e tre le parole ciascuna, quindi non sarebbe possibile per il core recuperare le istruzioni più velocemente di quanto vengano eseguite. Mi aspetto che alcune delle istruzioni "it" richiedano un ciclo, ma non so come prevedere quali.
Sarebbe bello se ARM potesse specificare determinate condizioni in cui la tempistica dell'istruzione "it" sarebbe deterministica (ad es. Se non ci sono stati di attesa o contesa del bus di codice, e le due precedenti istruzioni sono istruzioni di registro a 16 bit, ecc.) ma non ho visto nessuna di queste specifiche.
Applicazione di esempio
Supponiamo che uno stia cercando di progettare una scheda figlia per un Atari 2600 per generare output video componente a 480P. Il 2600 ha un clock pixel da 3,579 MHz e un clock CPU da 1,19 MHz (dot clock / 3). Per i video componente 480P, ogni linea deve essere emessa due volte, il che implica un'uscita dot clock a 7.158 MHz. Poiché il chip video (TIA) di Atari emette uno dei 128 colori usando come segnale luma a 3 bit più un segnale di fase con una risoluzione di circa 18 ns, sarebbe difficile determinare con precisione il colore semplicemente guardando le uscite. Un approccio migliore sarebbe quello di intercettare le scritture nei registri dei colori, osservare i valori scritti e alimentare ciascun registro nei valori di luminanza TIA corrispondenti al numero di registro.
Tutto ciò potrebbe essere fatto con un FPGA, ma alcuni dispositivi ARM piuttosto veloci possono essere molto più economici di un FPGA con RAM sufficiente per gestire il buffering necessario (sì, lo so che per i volumi di una cosa del genere potrebbe essere prodotto il costo non è ' t un fattore reale). Richiedere a ARM di guardare il segnale di clock in entrata, tuttavia, aumenterebbe in modo significativo la velocità della CPU richiesta. Il conteggio dei cicli prevedibile potrebbe rendere le cose più pulite.
Un approccio di progettazione relativamente semplice sarebbe quello di fare in modo che un CPLD guardi la CPU e il TIA e generi un segnale di sincronizzazione RGB + a 13 bit, quindi fare in modo che DMA ARM acquisisca valori a 16 bit da una porta e li scriva su un altro con tempismo adeguato. Sarebbe una sfida progettuale interessante vedere se un ARM economico potesse fare tutto. Il DMA potrebbe essere un aspetto utile di un approccio all-in-one se si potessero prevedere i suoi effetti sul conteggio dei cicli della CPU (soprattutto se i cicli DMA potrebbero verificarsi in cicli in cui il bus di memoria era altrimenti inattivo), ma a un certo punto del processo l'ARM dovrebbe svolgere le sue funzioni di ricerca da tavolo e di sorveglianza del bus. Si noti che a differenza di molte architetture video in cui i registri dei colori vengono scritti durante gli intervalli di blanking, l'Atari 2600 scrive spesso nei registri dei colori durante una porzione visualizzata di un fotogramma,
Forse l'approccio migliore sarebbe quello di utilizzare un paio di chip a logica discreta per identificare le scritture dei colori e forzare i bit inferiori dei registri dei colori sui valori corretti, quindi utilizzare due canali DMA per campionare il bus della CPU in entrata e i dati di uscita TIA, e un terzo canale DMA per generare i dati di output. La CPU sarebbe quindi libera di elaborare tutti i dati da entrambe le fonti per ciascuna linea di scansione, eseguire la traduzione necessaria e bufferizzarli per l'output. L'unico aspetto delle funzioni dell'adattatore che dovrebbe avvenire in "tempo reale" sarebbe l'override dei dati scritti su COLUxx, e questo potrebbe essere curato utilizzando due chip logici comuni.