Vet du säkert att din RISC-V RTL inte innehåller några överraskningar?

Källnod: 1600300

Med tanke på den relativa nyheten och komplexiteten hos RISC-V RTL-designer, oavsett om du köper en kommersiellt stödd kärna eller laddar ner ett populärt erbjudande med öppen källkod, finns det en liten men icke-noll risk för att oönskade överraskningar kommer ut oupptäckta i din slutprodukt. Tänk efter hög till låg sannolikhet:

  • Närvaron av en konstig-men-helt-möjlig hörn-fodral bugg
  • Buggar "inuti" de anpassade instruktionerna som du eller din leverantör skapar för din applikation
  • Buggar "vid kanterna" av en anpassad instruktion - t.ex. instruktionen körs korrekt, men den lämnar på något sätt maskinen i ett skadat tillstånd
  • Relaterat: odokumenterade och/eller dåligt specificerade nya funktioner som omedvetet öppnar upp hål i designen
  • Skadlig trojansk logik införd i smyg via en försörjningskedjasattack

Vanliga begränsningsmetoder

Naturligtvis är den första försvarslinjen expertinspektion av den inkommande eller utvecklande RTL-koden. Uppenbarligen bör detta göras; men det borde vara lika uppenbart att denna teknik – som man säger i den matematiska världen – "är nödvändig men inte tillräcklig" (även om du lät professor Patterson själv granska din kod).

Nästa försvarslinje är att tillämpa simuleringsbaserade tillvägagångssätt: Instruction Set Simulation (ISS), automatiserad jämförelse av din DUT med mogna gyllene modeller, begränsade slumpmässiga UVM-testbänkar för DUT RTL-simulering och till och med spridning av verkliga stimulanser till hårdvaruassisterad emulering av DUT. Återigen, dessa tillvägagångssätt är alla värdefulla och bör göras; men de lider alla av samma brist: de är till sin natur ofullständiga eftersom de är beroende av stimulansgenerering. Till exempel, i det extrema, men möjliga fallet av en supply chain-attack, har den trojanska logikutvecklaren medvetet skapat en utlösande sekvens av signalering och data som sannolikt kommer att undgå upptäckt av även den mest kreativa white hat-hacker. Och naturligtvis har funktionella buggar sitt eget sätt att använda naturligt förekommande entropi för att förbli dolda.

Summan av kardemumman är att det enda sättet att vara helt säker på att din RISC-V RTL är fri från naturliga eller skadliga överraskningar är att använda uttömmande, formella metoder för att verifiera designen.

Lättare sagt än gjort, eller hur?

Ja och nej: För 14 år sedan var den här typen av analys endast möjlig av forskare på doktorandnivå som använde sina egna handgjorda program. Men sedan 2008 har verktygen och teknikerna producerats så att alla som är bekanta med grunderna för formell verifiering och skrivandet av IEEE-standarden System Verilog Assertions (SVA) snabbt kan tillämpa och lyckas här.

En formelbaserad process i tre steg

Det rekommenderade formellt baserade flödet utvecklas enligt följande:

  1. Skapa en formell testbänk som "modellerar" DUT-specifikationen
  2. Definiera ingångsrestriktioner och kontroller som ska köras mot DUT
  3. Utför analys

Steg 1 – Skapa en formell testbänk som "modellerar" DUT-specifikationen

Grunden för denna metod är att skriva en uppsättning egenskaper som representerar beteendet för varje instruktion i din RISC-V-design. Uppgiften är att fånga effekten av en given instruktion på IP:ns utgångar och interna arkitektoniska tillstånd (i RISC-V-världen är detta programräknaren (PC) och registerfilen (RF)) för varje given godtyckligt lång ingångssekvens. Detta görs med hjälp av en specialbyggd tillägg till IEEE SVA som kallas Operational SVA. I ett nötskal, detta är ett bibliotek som levereras med det formellt baserade processorverifieringsverktyget; och från verifieringsingenjörens synvinkel ser det ut som en intuitiv delmängd av bekant SVA-kod. Figur 1 visar den allmänna strukturen:

egenskapsinstruktion_A; // konceptuellt tillstånd t ##0 ready_to_issue() och // trigger t ##0 opcode==instr_A_opc antyder // konceptuellt tillstånd t ##0 ready_to_issue() och // minnesgränssnitt utdata // läs nästa instruktion t ##0 imem_access(instr_A_opc) och // dataladdning/lagra t ##1 dmem_access(instr_A_opc) och // arkitekturregister t ##1 RF_update(instr_A_opc) och t ##1 PC_update(instr_A_opc) endproperty 

Fig. 1: Struktur för operationell SVA-kod som fångar specifikationen av en processorinstruktion. [1]

Med hänvisning till figur 1, den vänstra sidan av inblandning (delen av koden ovan nyckelordet innebär) identifierar när maskinen är redo att utfärda en ny instruktion och instruktionen som utfärdas. Påståendet fångar de nuvarande värdena för de arkitektoniska tillstånden och, till höger om implikationen (delen av koden nedan nyckelordet innebär), bevisar deras nästa värden.

Dessutom ska processorutgångarna bevisas vara korrekta - i det här fallet för att säkerställa att instruktionen kommer åt de förväntade data- och instruktionsminnesplatserna. Påståendet bevisar också att maskinen är redo att utfärda en ny instruktion vid nästa cykel. Detta är avgörande för att frikoppla verifieringen av en instruktion från den sekvens av instruktioner som den kan vara en del av. Till exempel kan instruktion A köras korrekt, men lämnar maskinen i ett skadat tillstånd. Detta felaktiga tillstånd kan orsaka att nästa instruktion B producerar felaktiga resultat utan att det är något eget fel. Följaktligen, med Operational SVA-tillvägagångssättet, skulle påståendeverifieringsinstruktionen B passera, medan påståendeverifieringsinstruktionen A skulle misslyckas (där läs- och skrivminnesoperationer kan pågå i flera cykler).

Bottom-line: funktionerna som representerar arkitektoniska tillstånd i Operational SVA-koden måste mappas till implementeringssignalerna och måste återspegla processorns mikroarkitektur. Statusen för RF kan till exempel bero på aktiveringen av vidarebefordringsvägar. [1]

[Notera: För de av er som är bekanta med antingen simulering eller formell funktionell täckning, förlitar sig denna uppfattning om fullständighet inte på strukturella täckningsmått, eller på att skapa och samla in mätvärden för en funktionell täckningsmodell. Istället (och att komma lite före de återstående stegen och resultaten) handlar analysresultatet här om att få fullständiga bevis för alla egenskaper. Fullständiga bevis visar också implicit att det inte finns någon annan funktionalitet - som var ospecificerad eller oväntad (specifikation eller kodningsbugg), eller med uppsåt infogat - som inte fångas upp av denna uppsättning egenskaper. Omformulering handlar denna metodik om att uppnå 100 % "testplanstäckning" som verifierats av de uttömmande formella analysresultaten - där ingenting är mer "komplett" än ett matematiskt bevis!]

Steg 2 – Definiera indatarestriktioner och kontroller som ska köras mot DUT

För att komplettera specifikationsegenskaperna för varje instruktion är nästa steg att definiera inmatningsbegränsningarna och eventuella ytterligare utdatakontroller. Återigen används Operational SVA, där användaren nu specificerar en "fullständighetsplan" för att definiera både legala input och illegala signaler som DUT bör ignorera. Enligt exemplet som visas i figur 2 finns det tre avsnitt: bestämningsantaganden, bestämningskrav och egenskapsdiagram.

fullständighetsprocessor; determination_sumptions: // INPUTS bestämt(imem_data_i); bestämd(dmem_valid_i); if (dmem_valid_i) determined(dmem_data_i) endif; determination_requirements: // OUTPUTS bestämd(imem_read_o), if (imem_read_o) determined(imem_addr_o) endif; bestämd(dmem_enable_o); if (dmem_enable_o) determined(dmem_rd_wr_o), determined(dmem_addr_o) endif; // ARKITEKTURSTÄNDER bestämt(PC); bestämt(RF); property_graph: all_instructions := instruction_not_a, instruction_add_a, instruction_sub_a, [...] all_instructions -> all_instructions; slutgiltighet; 

Fig. 2: Exempel på en fullständighetsplan med antaganden och krav för villkorad bestämning.

Att utveckla:

  • "determination_assumptions" är helt enkelt ett fint namn för indatavärdebegränsningar
  • "determination_requirements" är en definition av de signaler som måste verifieras (både processorns utsignaler och arkitektoniska tillstånd)
  • Sektionen "property_graph" är helt enkelt en bindning av denna fil till alla egenskaper som skapades i steg 1

Sammanfattning av var vi är vid denna tidpunkt: i steg 1 skapade du vad som faktiskt är en cykelexakt modell av DUT som måste bevisas sann för alla tider och alla ingångar; i steg 2 ställer du in begränsningarna och eventuella speciella beteenden att hålla utkik efter. Lägg ihop dessa, och i själva verket har du en formell testbänk som är redo att köras!

Steg 3 – Utför analys

Målet med alla formella verktyg är att uttömmande bevisa att alla egenskaper är sanna för alla tider och alla indata. I fallet med RISC-V-processorverifiering arbetar verktyget för att bevisa att vilken godtyckligt lång ingångssekvens som helst kan matchas till en unik sekvens av den specificerade Operational SVA som förutsäger värdena för utgångar och arkitektoniska tillstånd.

Och det är precis vad som händer. Om det upptäcks någon skillnad i beteende mellan specifikationen och DUT, levererar det formella verktyget en "motexempel"-vågform som visar exakt den serie av insignaler och data som kan skapa ett brott mot specifikationen. Som nämnts ovan kan sådana fel hittas i det inre av instruktionens RTL-logik eller i "överlämningslogiken" som startar nästa lagliga gren/instruktion.

Hur som helst, när dessa problem är åtgärdade och verktyget bevisar alla egenskaper, är resultaten verkligen "fullständiga" - dvs du kan vara matematiskt säker på att det inte finns några RTL-kodningsfel - den formella analysen har bokstavligen bevisat frånvaron av några buggar !

Resultat

För det första, som nämnts ovan, har många processorutvecklare under åren dragit nytta av detta flöde [2], [3], [4].

Genom att testa denna metodik med RISC-V gjorde mina kollegor en fallstudie med den populära Rocket Chip open source-kärnan. Specifikt undersöktes RV64IMAFDC – sv39 vm-konfigurationen. Detta är en 64-bitars processorkärna med ett 39-bitars virtuellt minnessystem [5] och tillägg, såsom komprimerade och atomära instruktioner [6]. Denna RISC-V ISA-implementering med öppen källkod använder en pipeline i fem steg, enutgåva, i ordning med iordningställande komplettering för instruktioner med lång fördröjning, som delning eller cachemissar. Kärnan stöder också förutsägelse av gren och körtidsmodifiering av "misa"-registret, vilket gör att det kan stänga av vissa instruktionsuppsättningar.

Även om denna ögonblicksbild av Rocket Chip hade verifierats och bandats ut flera gånger, identifierades fyra tidigare okända, hörnfall, misstänkta beteenden och rapporterades till Rocket Core RTL-utvecklarna. Dessa problem ([7], [8], [9] och [10]) upptäcktes enbart genom den systematiska tillämpningen av den fullständiga formella verifieringsmetoden som beskrivs i denna artikel.

Närmare bestämt [10] – upptäckten av en icke-standardinstruktion CEASE (Opcode 0x30500073) i RTL: uppenbarligen föll Rocket Chip-teamet efter med sin dokumentation (och de fixade detta nästan omedelbart efter inlämnandet av GitHub pull-begäran). Den större poängen är att detta visar att logiken som krävs för att implementera en hel instruktion – dussintals rader kod och många grindar av syntetiserad, placerad och dirigerad logik – kan undgå upptäckt genom visuell inspektion, RTL-simulering, grindnivåsimulering, hela back-end implementeringsprocess och hårdvaruprototyper i labbet!

Men hur är det med prestandan för detta flöde?

Låt oss först ta upp den större betydelsen av "prestanda". På grund av den nya karaktären hos Rocket Chip-designen tog det för denna fallstudie ungefär 20 ingenjörsveckor för våra formella verifieringsutövare att utveckla hela testbänken och begränsningarna. Tidigare tillämpningar av detta flöde på mer strukturerad, kommersiell IP har dock vanligtvis tagit en bråkdel av denna tid. Naturligtvis kommer hela uppläggningsprocessen att gå mycket snabbare ju mer stabila och mogna specifikationerna är, hur väldokumenterad och läsbar DUT RTL-koden är och hur mycket tillgång du har till designingenjörerna för frågor och svar.

När miljön väl hade ställts in var körtiden för väggklockan hela 2 timmar – dvs. mycket mindre än vad du rimligen kunde förvänta dig från slumpmässig RTL-simulering och till och med hårdvaruassisterad verifiering. Plus, kom ihåg att resultaten av denna analys är giltiga för alla indata och hela tiden - med ett ord, de är uttömmande [11].

Sammanfattning

Den kompletta, formellt baserade processorverifieringsmetoden som presenteras i den här artikeln använder en tillägg till IEEE SVA, Operational SVA, för att formellt verifiera att en RISC-V ISA är fri från luckor och inkonsekvenser. Till skillnad från testbänkar med begränsad slumpmässig simulering, emulering eller fysisk prototypning, upptäcker den kompletta uppsättningen egenskaper och begränsningar uttömmande många typer av RTL-fel, såväl som förekomsten av odokumenterad eller dåligt specificerad kod och skadliga trojaner.

Referensprojekt

1 – 2019 GOMACTech Conference, Albuquerque, NM, 28 mars 2019: Komplett formell verifiering av RISC-V-processor-IP:er för trojanfria betrodda IC:er, David Landoll, et.al.

2 – DVCon 2007: Komplett formell verifiering av TriCore2 och andra processorer, Infineon Gmbh.

3 - 51st Design Automation Conference (DAC): Formell verifiering tillämpas på Renesas MCU Design Platform med hjälp av OneSpin-verktygen

4 – DVCon Europe 2019: Komplett formell verifiering av en familj av DSP:er för fordon, Bosch Gmbh.

5 – Handboken för RISC-V-instruktionsuppsättningen, volym II: Privileged Architecture, dokumentversion 1.10.

6 - https://github.com/freechipsproject/rocket-chip [tillgänglig 20 december 2018]

7 – DIV-instruktionsresultat skrivs inte till registerfil
https://github.com/freechipsproject/rocket-chip/issues/1752

8 – JAL- och JALR-instruktioner Lagra annan returdator
https://github.com/freechipsproject/rocket-chip/issues/1757

9 – Olagliga opkoder spelas upp och orsakar oväntade biverkningar
https://github.com/freechipsproject/rocket-chip/issues/1861

10 – Icke-standardinstruktion CEASE (Opcode 0x30500073) Upptäckt i RTL, https://github.com/freechipsproject/rocket-chip/issues/1868

11 – Verification Horizons blogg, Hur kan du säga att formell verifiering är uttömmande?, Joe Hupcey III
https://blogs.sw.siemens.com/verificationhorizons/2021/09/16/how-can-you-say-that-formal-verification-is-exhaustive/

Källa: https://semiengineering.com/do-you-know-for-sure-your-risc-v-rtl-doesnt-contain-any-surprises/

Tidsstämpel:

Mer från Semiconductor Engineering