Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Industrial programming >> VHDL

Een Tcl-gedreven testbench maken voor een VHDL code-lock module

De meeste VHDL-simulators blootstellen de Tool Command Language (Tcl) als hun primaire scriptinterface. Wanneer je een commando typt in de simulator-console, gebruik je Tcl, en je kunt ook scripts schrijven die je VHDL-ontwerp aansturen en observeren.

Dit artikel begeleidt je door het bouwen van een zelf-controlerende testbench die Tcl gebruikt — in plaats van VHDL — om het gedrag van een simpele code-lock module te verifiëren. Het resultaat is een duidelijke, onderhoudbare testharness die uitgevoerd, gewijzigd en herbruikt kan worden zonder de VHDL te hercompileren.

Zie ook:

Download de code en ModelSim-projectbestanden hieronder.

De DUT: Een Code-Lock Module in VHDL

Voordat we in de testbench duiken, laten we het Device Under Test (DUT) bekijken. De module emuleert een simpele slot dat een kluis openen wanneer de correcte numerieke reeks wordt ingevoerd op een pincode-toetsenblok.

Hoewel veel mensen zo'n apparaat een "combination lock" noemen, is de correcte term een "permutation lock" — de volgorde van de cijfers telt. Voor duidelijkheid noemen we het een code lock doorheen.

Een Tcl-gedreven testbench maken voor een VHDL code-lock module

De illustratie hierboven toont een typische hotelseif. Voor simplicitet gebruikt ons ontwerp alleen numerieke toetsen en laat de CLEAR- en LOCK-knoppen weg.

Hoe de Code-Lock Module Werkt

Het slot begint in een vergrendelde toestand. Wanneer een gebruiker vier opeenvolgende cijfers invoert die overeenkomen met de geheime pincode, gaat het slot open. Het invoeren van een onjuiste reeks vergrendelt het apparaat opnieuw. Dit gedrag wordt geïmplementeerd als een simpele sequentie-detector in VHDL.

Een Tcl-gedreven testbench maken voor een VHDL code-lock module

De waveform illustreert de timing van de module. Naast klok en reset accepteert de module twee invoeren: input_digit (een integer 0–9) en input_enable (een std_logic). De DUT samplet het cijfer op een stijgende klokflank wanneer enable hoog is.

De enige uitgang is unlock, een std_logic die alleen hoog gaat wanneer de vier opeenvolgende cijfers overeenkomen met de correcte pincode. In dit voorbeeld is de wachtcode 1234.

De Entiteit

De volgende entiteitsdefinitie hardcodeert de geheime pincode via generics. Elke generiek is een integer in het bereik 0–9, wat een Binary Coded Decimal (BCD) cijfer voorstelt.

entity code_lock is generic (pin0, pin1, pin2, pin3 : integer range 0 to 9); port ( clk : in std_logic; rst : in std_logic; input_digit : in integer range 0 to 9; input_enable : in std_logic; unlock : out std_logic ); end code_lock;

Het Declaratieve Gebied

De module gebruikt een enkele interne signaal — een 4-bit schuifregister dat de meest recent ingevoerde cijfers opslaat. We laten het register waarden van –1 tot 9 bevatten. De speciale waarde –1 wordt gebruikt voor de reset-toestand, zodat een pincode van 0000 het slot niet standaard ontgrendelt.

type pins_type is array (0 to 3) of integer range -1 to 9; signal pins : pins_type;

De Implementatie

De architectuur bevat een combinatoire toewijzing die unlock hoog zet wanneer het schuifregister overeenkomt met de generieke pincode-waarden. Omdat pins geklokt is, verandert unlock alleen op een stijgende klokflank.

unlock <= '1' when pins = (pin3, pin2, pin1, pin0) else '0';

Het volgende proces implementeert het schuifregister. Bij reset worden alle entries op –1 gezet. Wanneer input_enable hoog is op een stijgende flank, wordt het huidige cijfer opgeslagen op positie 0, en de vorige cijvers schuiven naar rechts.

PINS_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then pins <= (others => -1); else if input_enable = '1' then pins(0) <= input_digit; pins(1 to 3) <= pins(0 to 2); end if; end if; end if; end process;

De VHDL Testbench

Hoewel we Tcl gebruiken voor de verificatie-logica, hebben we nog steeds een basis VHDL-testbench nodig om de klok- en reset-signalen te genereren. Hieronder is het complete VHDL-testbench-bestand.

library ieee; use ieee.std_logic_1164.all; entity code_lock_tb is end code_lock_tb; architecture sim of code_lock_tb is constant clk_hz : integer := 100e6; constant clock_period : time := 1 sec / clk_hz; signal clk : std_logic := '1'; signal rst : std_logic := '1'; signal input_digit : integer range 0 to 9; signal input_enable : std_logic := '0'; signal unlock : std_logic; begin clk <= not clk after clock_period; DUT : entity work.code_lock(rtl) generic map (1,2,3,4) port map ( clk => clk, rst => rst, input_digit => input_digit, input_enable => input_enable, unlock => unlock ); end architecture;

De Tcl Testbench

Hieronder is een Tcl-script dat binnen ModelSim draait. Als je Vivado of een andere simulator gebruikt, zijn kleine aanpassingen vereist, aangezien sommige commando's simulator-specifiek zijn. Raadpleeg de ModelSim Command Reference Manual voor details.

Download het voorbeeldproject via het formulier hieronder.

Een Namespace Gebruiken

Het inkapselen van het script in een namespace voorkomt onbedoelde botsingen met globale variabelen. Alle Tcl-code zit binnen de codelocktb namespace.

namespace eval ::codelocktb { # Alle Tcl-code hier }

De Simulatie Initialiseren

We starten de simulatie met vsim en laden het waveform-bestand als het bestaat.

# Laad de simulatie vsim work.code_lock_tb # Laad de waveform if {[file exists wave.do]} { do wave.do }

VHDL-waarden importeren in Tcl

Met ModelSim's examine commando lezen we de clock_period constante en de PIN-generics. Het volgende snippet extraheert de numerieke waarde en tijdseenheid.

variable clockPeriod [examine clock_period] variable clockPeriod [string trim $clockPeriod "{}"] variable timeUnits [lindex $clockPeriod 1] variable clockPeriod [lindex $clockPeriod 0] variable pinCode [examine dut.pin0 dut.pin1 dut.pin2 dut.pin3]

We initialiseren ook een errorCount variabele om fouten bij te houden.

variable errorCount 0

Printen met Tijdstempel

Het echo commando toont berichten in de ModelSim-console op alle platforms. De volgende procedure prefix elk bericht met de huidige simulatiestijd.

proc printMsg { msg } { global now variable timeUnits echo $now $timeUnits: $msg }

Draaien voor een Gespecificeerd Aantal Klokcycli

Omdat de DUT klok-gevoelig is, schuiven we de tijd in veelvouden van de klokperiode.

proc runClockCycles { count } { variable clockPeriod variable timeUnits set t [expr {$clockPeriod * $count}] run $t $timeUnits }

Signaalwaarden Controleren

De checkSignal procedure vergelijkt een VHDL-signaal met een verwachte waarde, en rapporteert een fout als ze verschillen.

proc checkSignal { signalName expectedVal } { variable errorCount set val [examine $signalName] if {$val != $expectedVal} { printMsg "ERROR: $signalName=$val (expected=$expectedVal)" incr errorCount } }

Pincode-invoer Simuleren

Deze procedure stuurt de DUT-invoeren aan om een gebruiker te simuleren die een 4-cijferige pincode invoert. Het controleert de unlock uitgang zodra alle vier cijfers zijn toegepast.

proc tryPin { digits } { variable pinCode set pinStatus "incorrect" if { $digits == $pinCode } { set pinStatus "correct" } printMsg "Entering $pinStatus PIN code: $digits" foreach i $digits { force input_digit $i -deposit force input_enable 1 -deposit runClockCycles 1 force input_enable 0 -deposit runClockCycles 1 } if { $pinStatus == "correct" } { checkSignal unlock 1 } else { checkSignal unlock 0 } }

Testsequentie en Resultaatrapportage

Na een korte initialisatieperiode, laat het script de reset los en draait verschillende testcases: twee corner cases (0000 en 9999), de correcte pincode, en de omgekeerde pincodesequentie. Daarna rapporteert het het algehele resultaat.

runClockCycles 10 force rst '0' -deposit runClockCycles 1 printMsg "Checking reset value" checkSignal unlock 0 tryPin {0 0 0 0} tryPin {9 9 9 9} tryPin $pinCode tryPin [lreverse $pinCode] if { $errorCount == 0 } { printMsg "Test: OK" } else { printMsg "Test: Failure ($errorCount errors)" }

De Testbench Draaien

Voer het script uit met het volgende commando binnen ModelSim:

source code_lock/code_lock_tb.tcl

Een succesvolle run produceert output vergelijkbaar met het volgende, met tijdstempels voor elk bericht.

VSIM> source code_lock/code_lock_tb.tcl # vsim # 110 ns: Checking reset value # 110 ns: Entering incorrect PIN code: 0 0 0 0 # 190 ns: Entering incorrect PIN code: 9 9 9 9 # 270 ns: Entering correct PIN code: 1 2 3 4 # 350 ns: Entering incorrect PIN code: 4 3 2 1 # 430 ns: Test: OK

Als de DUT een defect bevat (bijv. een typfout in de unlock toewijzing), rapporteert het script de fout en het foutenaantal.

VSIM> source code_lock/code_lock_tb.tcl # vsim # 110 ns: Checking reset value # 110 ns: Entering incorrect PIN code: 0 0 0 0 # 190 ns: Entering incorrect PIN code: 9 9 9 9 # 270 ns: Entering correct PIN code: 1 2 3 4 # 350 ns: ERROR: unlock=0 (expected=1) # 350 ns: Entering incorrect PIN code: 4 3 2 1 # 430 ns: Test: Failure (1 errors)

Eindgedachten

Doorheen mijn carrière heb ik talloze Tcl-gebaseerde testbenches geschreven. Ze bieden unieke voordelen: interactief testen, de mogelijkheid om de testharness te wijzigen zonder hercompilatie, en een extra verificatielaag die beschermt tegen bugs in zowel het ontwerp als de testbench.

Er zijn echter afwegingen. Tcl-scripts draaien merkbaar langzamer dan zuivere VHDL-testbenches, en de taal kan kwetsbaar zijn — fouten zijn vroegtijdig moeilijk te vangen, en debuggen is minder intuïtief dan in hogere talen zoals Python.

Ondanks deze nadelen blijft Tcl de de-facto lijmtaal voor FPGA-tooling en simulatie. Als je werkt met Xilinx Vivado, Intel Quartus of Mentor Graphics Questa, zal het beheersen van Tcl zich uitbetalen. Deel gerust je ervaringen in de reacties hieronder.

VHDL

  1. Dynamische string-lijsten in VHDL: Best Practices & Voorbeeld
  2. Een VHDL-testbench netjes beëindigen: methoden en best practices
  3. Een PWM-controller implementeren in VHDL: Ontwerp, Simulatie en FPGA-demo
  4. Ontwerpen van een robuuste VHDL-ringbuffer FIFO in blok-RAM
  5. Hardwareverificatie verbeteren met een Tcl-gebaseerde interactieve testbench
  6. Een self-checking testbench in VHDL bouwen – Een praktische gids
  7. Een dynamische gelinkte lijst in VHDL implementeren met protected types en access pointers
  8. Impure functies in VHDL gebruiken: FSM-leesbaarheid en onderhoudbaarheid verbeteren
  9. VHDL-functies onder de knie krijgen: een praktische gids voor efficiënt ontwerp
  10. Een eindige-toestandsmachine in VHDL ontwerpen: een praktisch verkeerslichtvoorbeeld
  11. Gratis VHDL-simulator & editor setup: Een studentengids