Firmware-Simulation in der ModelSim-Umgebung unter Verwendung von Modellen in der SystemC-Sprache

Im letzten Artikel haben wir uns mit dem Modellierungsprozess von "Firmware" in der ModelSim-Umgebung vertraut gemacht, in der sowohl der Zielcode als auch der Generator von Testaktionen in der Sprache Verilog geschrieben sind. Schade, aber das reicht nicht für das im Zyklus gelöste Ziel. Ich habe wiederholt die Idee vertreten, dass die Entwicklung des Redd-Komplexes mit geringstem Aufwand erfolgen sollte. Wenn das Gerätemodell schnell geschrieben wird, kann es von Grund auf neu geschrieben werden. Das letzte Mal haben wir ein Busmodell erstellt, mit dem wir Bytes in den Addierer geschrieben haben. Aber ULPI ist eine sehr komplexe Sache. Ihr Modell von Grund auf neu zu schreiben - oh, wie schwierig es ist. Wenn Sie eine fertige finden können, ist es besser, dies zu tun. Und ich fand ... Leider und oh, es stellte sich heraus, dass es in der SystemC-Sprache war. Wir werden nun überlegen, wie Sie mit dieser Sprache arbeiten können.











Tatsächlich erschien dieser Artikel bereits im Juni als DOC-Datei. Dann wurde gleichzeitig ein Block mit fünf Artikeln geschrieben. Das Hochladen einer DOC-Datei nach Habr ist jedoch eine andere Aufgabe. Daher kam es vor, dass die Zeit dafür erst jetzt erschien (und zwei weitere schwinden vor Vorfreude). Beim Hochladen ist mir aufgefallen, dass dieser Artikel irgendwie langweilig aussieht, wenn Sie nicht in den Geist der vorherigen Artikel eintauchen. Wenn es einen solchen Wunsch gibt, aktualisieren Sie daher mindestens den letzten Artikel in Ihrem Speicher oder besser diese beiden ( "Den Kopf eines USB-Bus-Analysators machen ..." und "Das Verhalten eines Quartus-Projekts simulieren ..." ).



Einführung



Also, das fertige Modell, wo kann ich es bekommen? Es gibt ein Projekt, das genau das gleiche Problem wie der von uns entwickelte Analysator löst, jedoch einige Funktionen aufweist. Die erste Funktion ist für Xilinx-FPGAs. Zweitens ist es völlig undokumentiert. Es funktioniert irgendwie. Sie können sogar ein fertiges Steckbrett kaufen, es mit vorgefertigtem Binärcode füllen ... und einige Funktionen erhalten. Jeder, der um jeden Preis ein Gerät benötigt, kann einfach diesem Weg folgen. Aber niemand weiß, wie man es entwickelt. Das Projekt ist hier . Im Verzeichnis \ ulpi_wrapper \ testbenchEs gibt eine Reihe von Dateien zum Testen des Wrapper-Subsystems um ULPI. Sie empfehlen, in der Icarus Verilog-Umgebung zu modellieren, aber ich stöberte herum und fand auf der Oberfläche keine sinnvollen Beschreibungen, wie dies in der SystemC-Sprache zu tun ist. Aus diesem Grund habe ich mich entschlossen, weiterhin in der ModelSim-Umgebung zu arbeiten. Wenn ich wüsste, wie es enden würde ... Aber ich wusste es nicht. Deshalb begann ich zu recherchieren. Im Verlauf der Präsentation werden sowohl Erfolge als auch Misserfolge gezeigt. Beginnen wir mit Fehlern, damit jeder sehen kann, wie man es nicht macht.



Erfolgloser Versuch, alles "frontal" zu machen



Zuerst habe ich mich entschlossen, ein fertiges Beispiel zu nehmen und es durch Modellierung zu führen. Mit der üblichen Bewegung meiner Hand (und wir haben unsere Hand im letzten Artikel gestopft ) habe ich eine Testsuite erstellt, die Dateien auf Verilog und SystemC enthält. Es stellte sich







ungefähr so heraus: Ich starte ModelSim und sehe in der Arbeitsgruppe nichts, was mit SystemC zu tun hätte. Ich sehe den Verilogo-Code, den Sishny-Code jedoch nicht.







Wenn Sie sich die Protokolle ansehen, können Sie feststellen, dass sie nicht versucht haben, sie zu sammeln. Was ist los?







Nützliche Informationen zum Konfigurieren der * .do-Datei



Es ist bekannt, dass die * .do-Datei ModelSim ausführt. Aber als Liebhaber, alles mit einer "Maus" zu machen, habe ich nie in ihn hineingeschaut. Lassen Sie uns danach suchen und es öffnen! Es gibt nur eine solche Datei im Projektverzeichnis. Das ist wahrscheinlich was wir brauchen.







Wir öffnen es. Am Anfang - die Zusammenstellung aller Arten von Serviceelementen und Dateien, die im Projekt enthalten sind.

Beobachten Sie den Text
transcript on
if ![file isdirectory verilog_libs] {
	file mkdir verilog_libs
}

if ![file isdirectory vhdl_libs] {
	file mkdir vhdl_libs
}

vlib verilog_libs/altera_ver
vmap altera_ver ./verilog_libs/altera_ver
vlog -vlog01compat -work altera_ver {c:/intelfpga_lite/17.1/quartus/eda/sim_lib/altera_primitives.v}

vlib verilog_libs/lpm_ver
vmap lpm_ver ./verilog_libs/lpm_ver
vlog -vlog01compat -work lpm_ver {c:/intelfpga_lite/17.1/quartus/eda/sim_lib/220model.v}

vlib verilog_libs/sgate_ver
vmap sgate_ver ./verilog_libs/sgate_ver
vlog -vlog01compat -work sgate_ver {c:/intelfpga_lite/17.1/quartus/eda/sim_lib/sgate.v}




Aber am Ende - klar die Zusammenstellung der Dinge, die wir brauchen, beurteile ich dies anhand des Namens der Datei ulpi_wrapper.v :

vlog -vlog01compat -work work +incdir+C:/Work/UsbHead1/SystemCPlay {C:/Work/UsbHead1/SystemCPlay/ulpi_wrapper.v}

vsim -t 1ps -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L cycloneive_ver -L rtl_work -L work -L UsbHead1 -voptargs="+acc"  lalala

add wave *
view structure
view signals
run 10 us


Ja wirklich. Es gibt eine Zusammenstellung eines Verilog-Moduls, und es gibt keinen Hinweis auf die Zusammenstellung von Modulen in SystemC. Das einzige Schade ist, dass diese DO-Datei bei jedem Start der Simulation automatisch erstellt wird, sodass Sie sie nicht einfach nehmen und bearbeiten können. Es wird von einem sehr komplexen TCL-Skript erstellt. Es besteht kein Wunsch, darüber zu herrschen. Aber nach dem Artikel über das fröhliche Viertel ist es wahrscheinlich klar, dass eine solche Kleinigkeit kein Grund ist, aufzugeben. Sicher ist alles schon da. Das einzige Schade ist, dass in der Dokumentation steht, dass "Sie das Skript auf diese Weise erstellen können oder dass Sie dies tun können", und dass es keine Hinweise auf Beispiele gibt. Nun, lassen Sie uns alles experimentell ableiten. Erstellen Sie eine Datei C: \ Work \ UsbHead1 \ SystemCPlay \ myrun.do und versuchen Sie, die Kontrolle darauf zu übertragen. Zuerst versuchen wir es so:







Die Haupt-DO-Datei wird weiterhin generiert, aber ihr Ende sieht folgendermaßen aus:

vlog -sv -work UsbHead1 +incdir+C:/Work/UsbHead1/UsbHead1/synthesis/submodules {C:/Work/UsbHead1/UsbHead1/synthesis/submodules/UsbHead1_master_0_b2p_adapter.sv}
vlog -sv -work UsbHead1 +incdir+C:/Work/UsbHead1/UsbHead1/synthesis/submodules {C:/Work/UsbHead1/UsbHead1/synthesis/submodules/UsbHead1_master_0_timing_adt.sv}

vlog -vlog01compat -work work +incdir+C:/Work/UsbHead1/SystemCPlay {C:/Work/UsbHead1/SystemCPlay/ulpi_wrapper.v}

vsim -t 1ps -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L cycloneive_ver -L rtl_work -L work -L UsbHead1 -voptargs="+acc"  lalala

do C:/Work/UsbHead1/SystemCPlay/myrun.do


Wir sehen, dass die Verilog-Datei noch kompiliert ist, dann wird der Modellierungsprozess noch gestartet (obwohl ich dies während der Testläufe gesehen habe, aber jetzt kann ich sicher sagen, dass der Befehl vsim diesen Prozess startet), wonach die Steuerung an unsere übertragen wird Skript. Dieses Skript sollte den Anzeigeprozess steuern. Aber wir können die Montage immer noch nicht verwalten. Wenn die gesammelten Dateien nicht ausreichen, fällt das System versehentlich ab, bevor wir etwas tun dürfen. Nun, großartig, versuchen wir die letzte Einstellung.







Und hier beginnt der Spaß. Es ist so wichtig, dass ich es einrahmen werde.



Ich wähle ein Skript aus, aber es ist nicht ausgewählt. Ich gehe in die Einstellungen (ich habe die zuvor ausgewählte Option). Ich wähle, nicht gewählt. Und so - sogar zu blau im Gesicht. Bis ich es bemerkte, bis ich herausfand, wie man gewinnt - ich habe den Abend getötet! Es stellte sich heraus, dass die Schaltfläche Übernehmen grau bleibt, wenn Sie nur eine Datei auswählen. Und die Änderungen werden nicht in Erinnerung bleiben. Es ist unbedingt erforderlich, dass die Schaltfläche Übernehmen durch Bearbeiten anderer Dialogparameter schwarz wird! Im obigen Bild ist es genau schwarz. Wenn es abgeblendet bleibt, werden die Änderungen nicht gespeichert und nicht alles für die Verwendung des Skripts neu konfiguriert.




Das Skript wird noch erstellt, aber sein Ende ist für uns bequemer geworden.

vlog -sv -work UsbHead1 +incdir+C:/Work/UsbHead1/UsbHead1/synthesis/submodules {C:/Work/UsbHead1/UsbHead1/synthesis/submodules/UsbHead1_master_0_timing_adt.sv}

do "C:/Work/UsbHead1/SystemCPlay/myrun.do"


Schließlich ist der Prozess der Erstellung von Quellcodes für das Projekt völlig unserer Gnade ausgeliefert! Wunderbar! Zu diesem Zeitpunkt konnte ich nur das für Xilinx geschriebene SystemC Verification with ModelSim- Dokument finden . Aber ModelSim ist in Afrika ModelSim. Anhand der Beispiele aus diesem Dokument und der Beispiele der DO-Datei, die in früheren Experimenten erstellt wurden, habe ich den folgenden Skripttext erstellt (seien Sie nicht beunruhigt über die Fülle an Schlüsseln, unten werden wir fast alles wegwerfen, dann werden wir auch absolute Pfade durch relative ersetzen. In diesem Stadium habe ich einfach alles aus den Beispielen gezogen und automatisch generierte Samples).

vlog -vlog01compat -work work +incdir+C:/Work/UsbHead1/SystemCPlay {C:/Work/UsbHead1/SystemCPlay/ulpi_wrapper.v}

vlib sc_work
sccom –g –I C:/intelFPGA_lite/17.1/quartus/cusp/systemc/include –work sc_work C:/Work/UsbHead1/SystemCPlay/ulpi_driver.cpp


Trommelwirbel ... Und ModelSim erklärt uns:







Wenn wir alle obszönen Wörter weglassen, dann habe ich nichts zu sagen ... Aber ein solcher Weg ist gegangen ! Und wo bekommt man ein anderes ULPI-Modell? Natürlich habe ich eine Vereinbarung mit ausländischen Freunden getroffen, die professionell an ernsthaften Projekten für FPGAs beteiligt sind. Speziell für mich haben sie für das Wochenende den Fernzugriff auf eine Maschine mit einem lizenzierten ModelSim eröffnet. Der zweite Pfannkuchen erwies sich ebenfalls als klumpig: Die 64-Bit-Version funktioniert selbst in der lizenzierten Form nicht mit SystemC. Aber am Ende konnte ich mit der 32-Bit-Version des lizenzierten ModelSim herumspielen. Deshalb setzen wir die Geschichte fort ...



Ein paar Worte zur Dokumentation



Damit. Jetzt, da ich Zugriff auf die lizenzierte Software habe, ist es Zeit, darüber zu sprechen, wo ich nach Informationen suchen und wo ich mich inspirieren lassen kann. Im Web sind Informationen über die Sprache eher lückenhaft. Bei der Auslieferung des Systems gibt es jedoch die folgenden nützlichen Verzeichnisse:



C: \ modeltech_10.2c \ docs \ pdfdocs - Dokumentation, einschließlich Dateien im PDF-Format. Ich mochte die Dateien modelsim_se_ref.pdf (ModelSim SE-Befehlsreferenzhandbuch), modelsim_se_user.pdf (ModelSim SE-Benutzerhandbuch) und modelsim_se_tut.pdf (ModelSim SE-Lernprogramm). Es gibt nicht viel über die Sprache selbst, aber darüber, wie man Dateien verbindet und wie man Dialektprobleme löst - ganz.



Als nächstes nützliches Verzeichnis C: \ modeltech_10.2c \ examples... Es gibt Beispiele für vorgefertigte * .do-Dateien und vorgefertigte cpp- und h-Dateien. Das nützlichste Beispiel für uns ist C: \ modeltech_10.2c \ examples \ systemc \ vlog_sc . Es zeigt Ihnen, wie Sie über Verilog-Code auf SystemC-Code zugreifen. Wir werden am Ende genau diesen Weg gehen.



Das Verzeichnis C: \ modeltech_10.2c \ include \ systemc enthält den Quellcode für die Sprachtypbibliothek. Kein schlechtes Nachschlagewerk. Wie sie sagen, gibt es Fische für Fischlosigkeit und Krebs.



Alles aus Katalogen. Nun der Titel eines wunderbaren Buches, aus dem Sie viel über die Sprache und die darin enthaltenen Programmiermethoden lernen können. SystemC - Von Grund auf, zweite Ausgabe. Von David C. Black, Jack Donovan, Bill Bunton und Anna Keist.



SystemC-Dialekte



Damit. Nachdem ich Zugang zum Arbeitssystem erhalten hatte, stellte ich das Projekt freudig gemäß dem zuvor erstellten Skript zusammen. Er versammelte sich ohne Fehler! Das erste Modell von GitHub hat sich bereit erklärt, mit uns zusammenzuarbeiten! Um den Benchmark auszuführen, habe ich die Datei ulpi_wrapper_tb.cpp aus demselben Verzeichnis zum Projekt hinzugefügt und unzählige Fehler erhalten.

Angenommen, die Zeile enthält einen Fehler: m_vpi_handle = vpi_handle_by_name ((const char *) name, NULL);

schwer zu reparieren, aber immer noch möglich. Aber die Linie

        // Update systemC TB
        if(sc_pending_activity())
            sc_start((int)(time_value-m_last_time),SC_NS);


beschwor schlechte Gedanken. In den Bibliotheken gibt es keine Funktion sc_pending_activity () . Es gibt eine sc_pending_activity_at_current_time () -Funktion , aber ich habe mich nicht einmal darum gekümmert . Anstelle von tausend erklärenden Worten werde ich einen Dump geben:







Und es gab 44 Dateien mit diesem Text (* .exe, * .dll usw.).



Sie könnten versuchen, alles neu zu schreiben ... Aber ist es notwendig? Ich möchte Sie daran erinnern, dass ich das alles tatsächlich begonnen habe, weil ich alles verwenden wollte, was fertig war. Ich kann alles in einer freien Umgebung auf einem reinen SystemVerilog entwickeln, wenn ich wirklich viel Zeit verschwende ... Ich bin hierher gegangen, um keine Zeit zu verschwenden, sondern um zu sparen! Aber eigentlich ... Die Hauptsache ist nicht zu vergessen, was wir tun. Wir wollen das ULPI-Busmodell verwenden. Sie sammelte sich. Beim Versuch, aus dem Beispiel ein vollständiges Testsystem zu erstellen, traten Probleme auf ... Warum ist das so? Nun, das komplette System funktioniert nicht und okay. Wir werden ein Modell durch Versuch und Irrtum beherrschen, ohne die Funktionsweise des Systems zu betrachten.



Beseitigung dialektbasierter Missverständnisse



Damit. Wir werden ein gemischtes System machen. Das Modul mit dem Modell wird in der SystemC-Sprache geschrieben, und ich werde ihm Testaktionen und das Modul, das in der Verilog-Sprache entwickelt wird, übermitteln. Das heißt, Sie müssen das Modul ulpi_driver in der Arbeitsgruppe anzeigen .



Als ich Beispiele für * .do-Dateien aus der Lieferung von ModelSim untersuchte, vereinfachte ich das Skript erheblich und machte am Ende Folgendes:

vlog +../../SystemCPlay {../../MyCores/ULPIhead.sv}

sccom -g ../../SystemCPlay/ulpi_driver.cpp
sccom -link


Es gibt keine Fehler, aber das Modul wurde auch nicht in der Gruppe angezeigt. Bei der Untersuchung der Beispieldateien (denken Sie daran, dass das beste Beispiel für die Implementierung einer solchen Sprachmischung das Verzeichnis C: \ modeltech_10.2c \ examples \ systemc \ vlog_sc ist ) wurde mir klar, dass die folgende Zeile am Ende der Datei ulpi_driver.cpp hinzugefügt werden sollte :

SC_MODULE_EXPORT(ulpi_driver);


In der Dokumentation zu ModelSim heißt es, dass dies Dialektfunktionen sind. Und voila! Hier ist unser Modul:







Richtig, das Menü "Welle erstellen" (wir haben dieses Menü im letzten Artikel besprochen ) ist dafür nicht verfügbar. Und er hat keine Häfen. Historisch gesehen habe ich mich zuerst mit Ports befasst, aber methodisch - ich werde die Geschichte über sie auf später verschieben. Andernfalls müssen Sie den Code zweimal bearbeiten. Um dies nicht zu tun, werden wir uns zunächst ein wenig vorbereiten.



Einen Uhrgenerator bauen



Es stellte sich heraus, dass das Modell einige Unterschiede zum echten ULPI aufweist. Der erste Unterschied besteht darin, dass der 66-MHz-Takt vom Chip erzeugt werden muss. Was sehen wir im Modell?

    sc_in<bool>             clk_i;


Störung! Beginnen wir mit der Überarbeitung! Alle Arbeiten werden, sofern nicht anders angegeben, in der Datei ulpi_driver.h ausgeführt.

Ändern Sie den Porttyp. Es war:

    sc_in<bool>             clk_i;


wurde (ich habe auch den Portnamen geändert):

    sc_inout<bool>             clk;


Ich habe aus dem Buch gelernt, dass ein echter Generator durch Hinzufügen einer Variablen eingefügt wird:

    sc_clock oscillator;


Wir setzen die Parameter im Konstruktor. Infolgedessen hat der Konstruktor die Form:

    //-------------------------------------------------------------
    // Constructor
    //-------------------------------------------------------------
    SC_HAS_PROCESS(ulpi_driver);
    ulpi_driver(sc_module_name name): sc_module(name),
                                      m_tx_fifo(1024), 
                                      m_rx_fifo(1024),
                                      oscillator ("clk66",sc_time(15,SC_NS))
    {


Die letzte Zeile ist nur dafür. Wenn Sie möchten, können Sie sogar die Simulation starten, auf das Modul usb_driver doppelklicken , dann clk66 zur temporären Hütte ziehen und den Simulationsprozess ein wenig ausführen . Wir sehen bereits, wie der Generator funktioniert:







Vergessen wir nicht, den Namen des Taktsignals an der Stelle zu ändern, an der der Haupt-Thread beginnt. Es war:

        SC_CTHREAD(drive, clk_i.pos());


Wurden:

        SC_CTHREAD(drive, clk.pos());




Interne Links wurden ersetzt. Aber wie schön es ist , das Signal nach draußen zu bringen, habe ich nicht gefunden. Vielleicht fehlt mir einfach die Qualifikation. Aber die eine oder andere Art und alle Versuche, den Hafen herauszuziehen, waren nicht von Erfolg gekrönt. Es war immer etwas im Weg. Ich fand sogar eine Diskussion in einem Forum, in dem der Autor dasselbe tun musste. Das Team entschied, dass es nur an die Eingangsports weitergeleitet werden kann. Aber wir müssen raus! Deshalb machen wir das.



Fügen Sie unterhalb des Konstruktors eine Stream-Funktion hinzu:

    void clkThread(void) 
    {
       while (true)
       {
           wait(oscillator.posedge_event());
           clk.write (true);
           wait(oscillator.negedge_event());
           clk.write (false);
       }
    }


Und fügen Sie im Klassenkonstruktor einen Link hinzu:

        SC_THREAD(clkThread);


Lassen Sie mich Ihnen den aktuellen Konstruktorbereich zeigen, damit Sie eine ganzheitliche Sicht auf das aktuelle Ergebnis haben:

    SC_HAS_PROCESS(ulpi_driver);
    ulpi_driver(sc_module_name name): sc_module(name),
                                      m_tx_fifo(1024), 
                                      m_rx_fifo(1024),
                                      oscillator ("clk66",sc_time(15,SC_NS))
    {
        SC_CTHREAD(drive,clk.pos());
        SC_THREAD(clkThread);

        m_reg[ULPI_REG_VIDL]    = 0x24;
        m_reg[ULPI_REG_VIDH]    = 0x04;
        m_reg[ULPI_REG_PIDL]    = 0x04;
        m_reg[ULPI_REG_PIDH]    = 0x00;
        m_reg[ULPI_REG_FUNC]    = 0x41;
        m_reg[ULPI_REG_OTG]     = 0x06;
        m_reg[ULPI_REG_SCRATCH] = 0x00;
    }

    void clkThread(void) 
    {
       while (true)
       {
           wait(oscillator.posedge_event());
           clk.write (true);
           wait(oscillator.negedge_event());
           clk.write (false);
       }
    }


Alle. Die erste Bearbeitung ist abgeschlossen.



Erstellen eines bidirektionalen Datenbusses



ULPI verfügt über einen bidirektionalen Datenbus. Und im Modell sehen wir die folgende Beschreibung:

    sc_out <sc_uint<8> >    ulpi_data_o;
    sc_in  <sc_uint<8> >    ulpi_data_i;


Störung! Zuerst machen wir basierend auf dem Ausgangsbus ein Leerzeichen, und dann schalten wir alles darauf um. Wo soll ich anfangen? Aus der Tatsache, dass der Bus in den dritten Zustand wechseln sollte und der Typ sc_uint <8> nur mit Binärdaten funktioniert. Der Typ sc_lv <8> hilft uns dabei . Daher ändern wir die Reifendeklaration in:

    sc_inout <sc_lv<8> >    ulpi_data_o;


Gehen Sie nun zur Datei ulpi_driver.cpp und suchen Sie dort nach allen Aufrufen des Busses ulpi_data_o . Intuitiv wurde mir klar, dass es nur einen Ort gab, den ich reparieren konnte:





Der gleiche Text.
void ulpi_driver::drive_input(void)
{
    // Turnaround
    ulpi_dir_o.write(false);
    ulpi_nxt_o.write(false);
    ulpi_data_o.write(0x00);

    wait(oscillator.posedge_event());
}






Ändern Sie die ausgewählte Zeile in

    ulpi_data_o.write("ZZZZZZZZ");


Alle. Jetzt können Sie anstelle von zwei Zeilen:

    sc_inout <sc_lv<8> >    ulpi_data_o;
    sc_in  <sc_uint<8> >    ulpi_data_i;


schreibe eins:

    sc_inout <sc_lv<8> >    ulpi_data;


und ersetzen Sie alle Verweise auf alte Variablen sowohl im h-nick als auch im cpp-shnik durch Verweise auf die Variable ulpi_data .



Fügen Sie Port-Aliase hinzu



Damit. Nach einer langen Suche kam ich zu dem Schluss (möglicherweise fehlerhaft), dass es in der ModelSim-Umgebung einfach ist, die Ports für ein separates Modul auf SystemC über die GUI zu ermitteln, kein Glück. Wenn dieses Modul jedoch in das Testsystem eingefügt wird, werden sie angezeigt. Aber während ich mich mit der Theorie befasste, fand ich heraus, wie man Aliase für Portnamen wunderschön einstellt. Der endgültige Klassenkonstruktor sieht nun folgendermaßen aus:

    SC_HAS_PROCESS(ulpi_driver);
    ulpi_driver(sc_module_name name): sc_module(name),
                                      m_tx_fifo(1024), 
                                      m_rx_fifo(1024),
                                      oscillator ("clk66",sc_time(15,SC_NS)),
                                      rst_i ("rst"),     
                                      ulpi_data ("data"),
                                      ulpi_dir_o ("dir"),
                                      ulpi_nxt_o ("nxt"),
                                      ulpi_stp_i ("stp")
    {
        SC_CTHREAD(drive,clk.pos());
        SC_THREAD(clkThread);

        m_reg[ULPI_REG_VIDL]    = 0x24;
        m_reg[ULPI_REG_VIDH]    = 0x04;
        m_reg[ULPI_REG_PIDL]    = 0x04;
        m_reg[ULPI_REG_PIDH]    = 0x00;
        m_reg[ULPI_REG_FUNC]    = 0x41;
        m_reg[ULPI_REG_OTG]     = 0x06;
        m_reg[ULPI_REG_SCRATCH] = 0x00;
    }


Ein Testsystem erstellen



Na dann. Es ist mir nicht gelungen, alles automatisch zu erledigen, sodass zwei debuggte Module (der Analysatorkopf und das ULPI-Busmodell) selbst in die Testdatei sprangen. Aber machen wir wenigstens einen Kopftest und fügen dann ULPI hinzu. Mit der Technik aus dem letzten Artikel habe ich ein Testsystem für die Datei ULPIhead.sv erstellt . Ich habe eine Datei namens sim1.v und habe sie sofort in sim1.sv umbenannt .



Dann habe ich das ulpi_driver- Modul mit den Handles hinzugefügt . Das resultierende Skript myrun.do sieht folgendermaßen aus:

vlog +../../SystemCPlay {../../MyCores/ULPIhead.sv}

sccom -g ../../SystemCPlay/ulpi_driver.cpp
sccom -link

vlog +../../SystemCPlay {../../SystemCPlay/sim1.sv}
vsim -voptargs="+acc" sim1


Die letzte Zeile wird gefoltert. Ohne sie hatte der Verilog-Code keine Ports. Durch Ändern der Optimierungsparameter beseitigen wir dieses Problem. Ich habe es in dieser * .do-Datei gesehen, die erstellt wurde, um unser System zu Beginn zu simulieren, als noch alles auf dem Computer erledigt war. Es stimmt, es gibt eine lange Schlange. Ich habe gerade den Schlüssel gefunden, der das Problem löst, und ihn kopiert. Und so - ich mag keine langen Schlangen, ich habe alles Unnötige rausgeworfen.



Jetzt fügen wir den ULPI-Block zum Testsystem hinzu und führen einen Dummy-Test durch. Nur um sicherzustellen, dass alle Taktsignale ticken und die Busse auf die richtigen Werte eingestellt sind.



Ich habe diesen Test bekommen.

Beobachten Sie den Text.
`timescale 1ns / 1ns
module sim1  ; 
 
  reg    ulpi_dir   ; 
  wire   source_valid   ; 
  wire    ulpi_stp   ; 
  reg    ulpi_clk   ; 
  reg    ulpi_nxt   ; 
  reg    reset_n   ; 
  reg    read   ; 
  reg  [31:0]  writedata   ; 
  wire    ulpi_rst   ; 
  reg    clk   ; 
  wire  [7:0]  source_data   ; 
  reg    write   ; 
  wire  [7:0]  ulpi_data   ; 
  reg    source_ready   ; 
  reg  [1:0]  address   ; 
  wire  [31:0]  readdata   ; 

  always 
  begin
     clk = 1;
     #5;
     clk = 0;
     #5;
  end

  ULPIhead  DUT  
  ( 
      .ulpi_dir (ulpi_dir ) ,
      .source_valid (source_valid ) ,
      .ulpi_stp (ulpi_stp ) ,
      .ulpi_clk (ulpi_clk ) ,
      .ulpi_nxt (ulpi_nxt ) ,
      .reset_n (reset_n ) ,
      .read (read ) ,
      .writedata (writedata ) ,
      .ulpi_rst (ulpi_rst ) ,
      .clk (clk ) ,
      .source_data (source_data ) ,
      .write (write ) ,
      .ulpi_data (ulpi_data ) ,
      .source_ready (source_ready ) ,
      .address (address ) ,
      .readdata (readdata ) ); 


  ulpi_driver ULPI
  (
      .clk (ulpi_clk),
      .rst (ulpi_rst),
      .data (ulpi_data),
      .dir (ulpi_dir),
      .nxt (ulpi_nxt),
      .stp (ulpi_stp)

  );

  initial
  begin
     reset_n  = 1'b0;
     source_ready = 1;
     writedata = 0;
     address = 0;
     read = 0;
     write = 0;
     #20
     reset_n  = 1'b1;
  end

endmodule










Fazit



Zumindest haben wir die Modellierung in der SystemC-Sprache mit dem ModelSim-System beherrscht. Es stellte sich jedoch heraus, dass hierfür der Zugriff auf die lizenzierte 32-Bit-Version erforderlich ist. Die kostenlose Version und die lizenzierte 64-Bit-Version bieten keine solche Möglichkeit. Soweit ich weiß, kann im Icarus Verilog-System alles völlig kostenlos ausgeführt werden, aber ich habe nicht genau herausgefunden, wie dies erreicht werden kann. Es stellte sich heraus, dass ich leichter auf das erforderliche ModelSim zugreifen konnte. Im nächsten Artikel werden wir dieses Wissen nutzen, um unseren Kopf zu modellieren.



Im Laufe der Arbeiten wurden recht komplexe Modifikationen der Modelle vorgenommen. Die resultierenden Dateien können hier heruntergeladen werden .



All Articles