Joyeux Quartusel, ou comment le processeur est arrivé à une telle vie



Lors du débogage de programmes réguliers, les points d'arrêt peuvent être définis presque partout et en quantités assez importantes. Hélas. Lorsqu'un programme est exécuté sur le contrôleur, cette règle ne s'applique pas. S'il y a une section dans laquelle le diagramme temporel est formé, alors l'arrêt gâchera tout. Et le passage aux basses et hautes fréquences n'est pas la même chose. Les conditions aux limites sont un fléau pour les développeurs. Ou, disons, un bus USB. Dans NIOS II, je ne travaillais pas avec, mais sur STM32 c'est terrible. Et je veux voir quelque chose, et quand tu t'arrêtes, tu attrapes un temps mort. En général, très souvent, malgré la présence d'un débogage JTAG avancé, le comportement du programme dans les zones critiques est obscurci. Ce serait formidable de voir, au moins après l'exécution, quelle chaîne le programme a traversé, quelles branches ont fonctionné et lesquelles n'ont pas fonctionné!

Il est encore plus important de connaître l'historique des exceptions. Sur NIOS II, je ne l'ai pas fait, mais sur le Cyclone V SoC dans le noyau ARM - complètement. Lors du débogage, tout fonctionne et si vous démarrez le programme à partir de la ROM, vous obtenez une exception. Il est clair comment ils y sont entrés et quel type d'évolution de la situation n'a pas conduit à cela. Le traçage casse également toutes les couvertures.

Articles précédents de la série:
  1. Développement du «firmware» le plus simple pour les FPGA installés dans Redd, et débogage en utilisant le test de mémoire comme exemple
  2. Développement du «firmware» le plus simple pour les FPGA installés dans Redd. Partie 2. Code de programme
  3. Développement de son propre noyau pour l'intégration dans un système de processeur basé sur FPGA
  4. Développement de programmes pour le processeur central Redd sur l'exemple d'accès au FPGA
  5. Les premières expériences utilisant le protocole de streaming sur l'exemple de communication CPU et processeur dans le FPGA Redd

Présentation


Il est de coutume d'écrire des articles éducatifs avec un visage sérieux, présentant le matériel avec calme et impartialité. Mais hélas, cela ne fonctionne pas toujours. Maintenant, selon le plan, il devrait y avoir un article sur l'optimisation du processeur synthétisé dans le complexe Redd, dans lequel nous devons parler des caractéristiques de travailler avec le cache. Ensuite, un article sur les retards lors de l'accès au bus. En général, tout cela peut être montré sur un oscilloscope. Je l'ai déjà fait dans un article sur le DMA (" DMA: Mythes et réalité "). Mais je voulais tout montrer en utilisant le processeur lui-même, j'ai effectué de telles vérifications pour le cœur ARM dans le FPGA Cyclone V SoC. Très pratique (bien que les résultats n'aient pas été publiés). Pour cette raison, j'ai décidé de traiter le mécanisme de traçage inhérent au bloc JTAG. C'est dommage que jusqu'à présent je n'ai pas pu afficher avec des ressources téléchargeables gratuitement combien de temps jouait telle ou telle commande, mais il y avait du matériel par lequel le programme peut toujours être demandé comment il est arrivé à une telle vie. Eh bien, et d'ailleurs, alors que les souvenirs des soirées orageuses sont encore frais dans ma mémoire, je vais les jeter d'une manière plutôt émotionnelle. Il y aura donc aujourd'hui de nombreux mémoires et une petite théorie utile.

Matériel informatique


Ainsi, très souvent lors du débogage d'un programme pour un microcontrôleur, il est souhaitable de connaître le chemin qu'il a parcouru, et il doit le passer à toute vitesse. Pour le cas de NIOS II, ce mécanisme est disponible et est inclus ici sur cet onglet des propriétés du cœur du processeur:



Type de trace définit le type d'informations à stocker. Vous ne pouvez rien enregistrer (cela économisera la mémoire de la puce), vous pouvez enregistrer uniquement l'historique des commandes (le plus souvent cela suffit), ou bien, enregistrer l'historique des commandes et des données. Il convient de noter que la documentation indique que dans le dernier mode, l'enregistrement des informations est en quelque sorte difficile, alors que des superpositions avec l'historique des commandes sont possibles, et plus de mémoire est consommée. N'utilisez donc ce mode que lorsque c'est vraiment nécessaire.

Le paramètre Trace Storage définit le type de mémoire dans lequel la trace sera enregistrée. La documentation indique que la mémoire externe n'est pas prise en charge par l'environnement de développement standard. Par conséquent, il vaut mieux choisir uniquement l'intérieur.



Eh bien, Onchip Trace Frame Size définit la taille du tampon. Plus le tampon est grand, plus il peut y être placé d'événements, plus l'historique peut être considéré. Mais le moins sera la mémoire du cristal pour d'autres besoins.



Il n'est pas nécessaire d'activer la case à cocher pour créer un port JTAG distinct. Laissez tout taxis régulièrement.

Support logiciel


Bon. Nous avons donc mis en place le cœur du processeur, et ensuite? Ohhhh! Commence alors l'histoire du détective. Si les figures ci-dessus doivent être interprétées comme un guide d'action, des illustrations montrant un gâchis et un bâillonnement suivront. Un certain nombre de documents indiquent que pour travailler avec le traçage, vous devez utiliser des programmes tiers coûteux et même un équipement JTAG spécial. Mais dans certains documents, il glisse que vous pouvez prendre quelque chose à plein temps.

Expériences Eclipse


Super. Regardons autour d'Eclipse. Je vous rappelle que j'utilise l'environnement de développement Quartus Prime 17.1. Eh bien, c'est arrivé. Nous démarrons le programme de débogage et passons à l'élément de menu qui vous permet d'ouvrir différentes fenêtres:



Là, nous sélectionnons la fenêtre Debug-> Trace Control:



Et nous obtenons un tel mannequin:



Mais la session de débogage est lancée. De plus, les éléments de menu Démarrer le suivi et Arrêter le suivi y figuraient même (avant d'ouvrir cette fenêtre, ils ne l'étaient pas). Mais ils sont bloqués. Et je n'ai pas pu les activer.



En vain, j'ai rempli Google avec différentes demandes. Dans les anciens documents, ces éléments sont décrits comme fonctionnant assez bien, mais dans les documents modernes, ils ne sont tout simplement pas mentionnés. Personne ne les mentionne sur les forums. Peut-être que quelqu'un dans les commentaires vous dira quelque chose?

Problèmes avec la dernière version d'Eclipse


Bon. Qu'en est-il de la dernière version de l'environnement de développement? Peut-être que tout fonctionne là-bas? Yyyyyy! Ceci est un sujet pour un chapitre séparé. La dernière version pour les quatrième et cinquième cyclones est la 18.1.1. Autrement dit, vous devez d'abord télécharger la version 18.1, puis installer la mise à jour 18.1.1. Si quelqu'un décide que j'ai trop de temps libre, que je réorganise le logiciel pour le bien de tout, alors tout va bien. La vérification principale concernait les problèmes de cache. Ils sont plus sérieux, je voulais les vérifier dans la nouvelle version, je n'écris pas sur eux ici.

Je l'ai donc téléchargé. Installé. Tout d'abord, la version 18.1 sous WIN7 est lancée, mais 18.1.1 ne trouve pas la DLL. Bon. J'ai découvert que je devais télécharger Redist à partir de Visual Studio 2015. Je l'ai installé. Il a commencé à fonctionner. Création d'un projet avec un système de processeur. Il s'est même préparé. Je vais sur Eclipse, je crée un programme avec BSP basé sur tout, comme nous l'avons déjà fait plusieurs fois ... Et je reçois ce genre de chose ...



Le projet ne va pas. Si vous quittez et entrez, il ne s'ouvre que partiellement.



Voir le dossier fermé? Voilà. Pourquoi? Ohhhh! Trois fichiers ont:



Ce sont les merveilleux attributs de la protection:



Ils ne peuvent donc pas être ouverts ou modifiés ... Si vous donnez plus de droits, le projet s'ouvrira, mais les fichiers ne sont pas complètement créés, donc cela ne fonctionnera pas pour les collecter. J'ai essayé de donner des droits jusqu'à la fermeture d'Eclipse, puis d'enregistrer le projet. Le résultat est le même.

Le vieillissement rapide de Windows 7 pourrait-il être à blâmer? Pas étonnant que je manquais de bibliothèques! J'ai mis Quartus frais sur WIN10, j'obtiens un résultat complètement identique en créant le projet! J'ai un ami. En raison de son lieu de travail, il rencontre parfois des produits de fabricants nationaux. Et il exprime une série de réflexions sur eux-mêmes et sur leurs proches. Eh bien, sur le fait que "qui construit cela?" Vous savez, en regardant les joies du logiciel Intel, je commence à penser qu'il est loin du pays d'origine ... En fait, ce n'était pas le cas sous Alter ... Tout est arrivé, mais je ne m'en souviens pas.

Je viens de sortir. J'ai copié le projet sur une clé USB avec le système de fichiers FAT32. Il n'y a aucun attribut de sécurité. J'en ai ouvert le projet, je suis entré dans Eclipse et j'ai créé le code. Aucun attribut de sécurité - pas de problème. Ensuite, je l'ai copié sur le disque dur et ... Eh bien, bien sûr, j'ai eu des problèmes pour générer BSP. Parce que le fichier * .bsp contient de nombreux chemins relatifs et un absolu. C'est bien d'avoir sorti une clé USB. Sinon, je n'aurais pas remarqué que BSP tombe dessus (car c'est le lieu de naissance du projet), et le projet est collecté sur le disque dur. Voici un exemple d'un tel chemin (déjà corrigé):



Eh bien, très bien ... Tout a été généré, assemblé ... Et cela fonctionne exactement de la même manière que dans la version 17.1 ... Et pour les contrôleurs SoC dans le nouvel environnement, vous devez également recréer la chaîne JTAG à chaque fois dans le programmeur. Dans la version 17.1, il suffisait de le faire une fois et d'économiser ... Eeeeeh. Eh bien oh bien ...

Altera Monitor et son problème


D'une manière ou d'une autre, la recherche en réseau des mots Démarrer le traçage et Arrêter le traçage m'a conduit à des documents intéressants. Ils décrivent différentes versions d'un programme amusant appelé Altera Monitor aujourd'hui (le nom était différent dans les anciens documents). La trouver était relativement facile. Vous devez télécharger le package du programme universitaire pour votre version de l'environnement de développement. Faites attention aux restrictions de licence. Mais puisque nous étudions maintenant, nous n'en avons pas peur. Mais pour le travail commercial - tout est mauvais là-bas. Détails ici: www.intel.com/content/www/us/en/programmable/support/training/university/materials-software.html

Télécharger, mettre ... Il y a un document attaché à la version actuelle (car les versions dispersées sur Internet varient énormément). J'ai même essayé d'exécuter un exemple pour ma planche à pain DE0-Nano-SoC. Il travaille. Mais quand j'ai essayé de faire mon projet, ça n'a pas marché. Le fichier * .sof est chargé dans le FPGA, après quoi, après un certain temps, un message s'affiche:



Seulement, il n'y a aucune information dans la fenêtre spécifiée. Si vous essayez de télécharger à nouveau: eh bien, le texte apparaîtra juste dans cette fenêtre:
Impossible d'interroger les ID d'instance JTAG.

Veuillez vous assurer que le FPGA a été configuré en utilisant le fichier .sof correct.

Quel genre de problème est-ce? J'ai cherché sur Google. Trouvé plusieurs forums avec le même problème. À une heure, un employé d'Intel a demandé quelle fréquence l'auteur avait chez JTAG et a suggéré d'en fixer une standard. Bien que, à ce moment-là, j'ai déjà compris que ce n'était pas une question de fréquence: l'exemple de l'entreprise fonctionnait et comment le définir? Sur un forum, l'auteur a écrit que cela avait réussi. Il n'a pas compris comment. Et il a dit que si vous faites tout avec soin selon les instructions, tout fonctionnera. Le reste de l'image était le même. Demande l'homme. Ils ne lui répondent pas. Après six mois ou un an, quelqu'un écrit qu'il a la même situation, y a-t-il eu une solution? Et le silence aaaaaaaa ...

Tentatives de solution expérimentées


Bon. Quelle pourrait être la raison? Au début, j'ai décidé de regarder autour de moi dans un exemple de travail. Quel genre de mystérieux identifiant JTAG? Cela pourrait-il être dû à la présence d'un système d'identification système fonctionnel?



Ajouté à lui-même, n'a pas aidé. Peut-être que le JTAG vers le pont d'Avalon, auquel tous les périphériques sont également connectés, est à blâmer?



Ajouté - n'a pas aidé. J'ai essayé quelques hypothèses de plus, mais j'ai réalisé que vous pouvez deviner pour toujours. Avec chagrin, j'ai même demandé à Yandex, Bing et même BaiDu. Ils en savent tous moins que Google. Il est devenu clair que nous devions faire face à la décompilation afin d'extraire du programme lui-même ce dont il avait besoin. Vérifié dans quelle langue le programme est écrit. Il s'est avéré qu'à Java. Le bytecode est stocké dans le fichier Altera_Monitor_Program.jar. Eh bien, c'est bizarre. Sauf que je ne connais pas du tout ce Java. Sur Java Script, il y avait un cas, tâté dans l'Internet des objets, mais je ne suis pas tombé sur un vrai Java. Mais là où le nôtre n'a pas disparu!

Analyse de bytecode JAVA pour trouver le problème


Comment ouvrir le code d'octet? Google a conduit à un article sur Habré, qui dit que pour cela, vous devez utiliser le JD-GUI. Je l'ai trouvé sur github, je l'ai téléchargé. J'ai identifié la zone problématique assez rapidement, car la JD-GUI a une merveilleuse navigation interactive. Du message au site, je suis sorti en 10 minutes. Cette section appelle un programme tiers, après quoi il analyse sa réponse. L'appel ressemble à ceci:
systemConsoleCommand[index] = "system-console"; systemConsoleCommand[var24++] = "--script=" + Globals.gHost.getMonitorProgramRootDir("bin/jtag_instance_check.tcl", true); systemConsoleCommand[var24++] = cable; systemConsoleCommand[var24++] = Globals.gProject.system.sofFilename; try { Process sysConsoleProc = NiosIIShell.executeCommand(systemConsoleCommand).start(); BufferedReader gdbIn = new BufferedReader(new InputStreamReader(sysConsoleProc.getInputStream())); 

Eh bien, et plus loin - analyse de la réponse que nous ne considérons pas encore.

Avec ce code, j'ai essayé d'ouvrir la console NIOS II:



Là, je suis allé dans le répertoire où se trouve le fichier sof et j'ai conduit la ligne de commande:
console système --script = jtag_instance_check.tcl USB-0 test.sof

Certes, pour cela, j'ai dû copier le fichier C: \ intelFPGALite \ 17.1 \ University_Program \ Monitor_Program \ bin \ jtag_instance_check.tcl au même endroit où se trouve sof, afin de ne pas souffrir avec le chemin. Au final, j'ai eu une réponse assez décente:

TYPE_NAME altera_avalon_jtag_uart.jtag FULL_HPATH jtag_uart_0 (INSTANCE_ID: 0)

TYPE_NAME altera_nios2_gen2.data_master FULL_HPATH nios2_gen2_0 (INSTANCE_ID: 0)


Tout semble être beau ...

Suivi de bytecode JAVA


Si l'affaire avait eu lieu aujourd'hui, cette section n'existerait pas. Mais c'est arrivé hier. Je comprenais encore très mal Java. Ce qui y était écrit lors de l'analyse du texte était une forêt sombre pour moi. Certes, pendant deux ans, mon enfant a suivi des cours de programmation olympiade chez 1 franchisés soviétiques (les certificats et les documents étaient 1 soviétique). De l'argent fou a été donné pour ces cours. Et ils leur ont enseigné là-bas juste à Java. Donc, il n'a pas non plus compris ce qui était écrit plus loin dans le code (en gardant l'intrigue, je publierai le code un peu plus bas, pas maintenant). En général, il y avait un sentiment persistant qu'il était temps de retracer. Je connais la mauvaise section, je vois que les lignes ont été reçues là-bas et le programme ne les aime pas avec quelque chose. Et alors?

L'enfant m'a trouvé un très bel article www.crowdstrike.com/blog/native-java-bytecode-debugging-without-source-code

Il parle d'un plugin très utile pour Eclipse, qui vous permet de travailler avec des fichiers JAR, en y définissant des points d'arrêt. Où télécharger, j'ai trouvé ici: marketplace.eclipse.org/content/bytecode-visualizer/help

J'ai téléchargé Eclipse, téléchargé le plug-in pour une installation hors ligne avec une peine de moitié ... J'ai commencé à installer - il n'y a pas assez de bibliothèques. J'ai commencé à lire. Il s'avère qu'il existe trois versions du plugin. Sous Eslipse 4.5 (Mars), 4.4 (Luna) et 4.3 (je ne me souviens pas du nom). Eh bien, tout est simple. On va sur le site d'Eclipse, on voit un lien pour télécharger la version de Mars pour Java ... Et ... Elle est morte. Peu importe! Il y a une dizaine de miroirs! .. Et tous les liens vers eux sont morts. Nous essayons Luna pour Java, les liens vers x64 sont morts, vers x86 il y en a un vivant ... Comme dit un de mes amis: "Hémorroïdes, c'est complet." En général, Google a eu du mal, mais m'a trouvé un assemblage Java 64 bits de la version Mars sur un serveur non officiel. Je l'ai téléchargé pendant une demi-heure, mais je l'ai téléchargé.

Implémentation d'un plugin, création d'un projet ... Horreur! Là, la trace n'est pas au niveau du code source, mais au niveau d'un assembleur. En bref, le code d'octet décodé est tracé. Mais en fait, ce n'est pas grave! Après tout, vous pouvez toujours vérifier avec les sources décompilées ouvertes dans une autre fenêtre, et ce plugin affiche de très bons commentaires ... Il s'est également avéré que les points d'arrêt peuvent être définis non pas à n'importe quel endroit, mais seulement à l'entrée de la fonction. Mais je ne peux pas m'arrêter! Il n'y a pas grand-chose là-bas et vous devez marcher de l'entrée de la zone à problème.

Permettez-moi de vous rappeler que les lignes traitées ressemblent à ceci:
TYPE_NAME altera_avalon_jtag_uart.jtag FULL_HPATH jtag_uart_0 (INSTANCE_ID: 0)

TYPE_NAME altera_nios2_gen2.data_master FULL_HPATH nios2_gen2_0 (INSTANCE_ID: 0)

Et voici le code Java:
 if (str.contains("(INSTANCE_ID:")) { Pattern getInstance = Pattern.compile("\\(INSTANCE_ID:(\\d+)\\)"); Matcher idMatcher = getInstance.matcher(str); if (idMatcher.find()) { String foundstr = idMatcher.group(1); instance = Integer.parseInt(foundstr); } 

isole parfaitement l'ID d'instance. Et voici le code:
  Pattern getHPath = Pattern.compile("FULL_HPATH (.+?)\\|(.+?) \\("); Matcher hpathMatcher = getHPath.matcher(str); if (hpathMatcher.find()) { hpath = hpathMatcher.group(2).replace("|", "."); } 

La variable hpath ne se remplit pas. Aujourd'hui, je sais déjà que l'expression régulière:
 "FULL_HPATH (.+?)\\|(.+?) \\(" 

nécessite deux mots séparés par une barre verticale. Eh bien, alors seulement ce qui est après la ligne est pris. Je ne le savais pas hier. Plus intéressant est un autre. L'enfant a étudié le travail à Java pendant deux ans et n'a pas appris les expressions régulières! Non, il est clair qu'on leur a enseigné non pas le langage, mais la programmation de l'Olympiade au moyen du langage, mais si je comprends bien, les expressions régulières en Java sont dans l'ordre des choses. Ils prennent un tel argent, ils secouent des certificats d'entreprises réputées, mais ils n'enseignent pas des choses importantes ... Mais je m'égare.

La lumière au bout du tunnel


Quelle est la ligne verticale? Nous prenons le projet qui a fonctionné, lui donnons la même équipe et obtenons cette réponse:

TYPE_NAME altera_avalon_jtag_uart.jtag FULL_HPATH Computer_System: The_System | JTAG_UART (INSTANCE_ID: 0)

TYPE_NAME altera_avalon_jtag_uart.jtag FULL_HPATH Computer_System: The_System | JTAG_UART_2nd_Core (INSTANCE_ID: 1)

TYPE_NAME altera_avalon_jtag_uart.jtag FULL_HPATH Computer_System: The_System | JTAG_UART_for_ARM_0 (INSTANCE_ID: 2)

TYPE_NAME altera_avalon_jtag_uart.jtag FULL_HPATH Computer_System: The_System | JTAG_UART_for_ARM_1 (INSTANCE_ID: 3)

TYPE_NAME altera_nios2_gen2.data_master FULL_HPATH Computer_System: The_System | Nios2 (INSTANCE_ID: 0)

TYPE_NAME altera_nios2_gen2.data_master FULL_HPATH Computer_System: The_System | Nios2_2nd_Core (INSTANCE_ID: 1)

Qu'est-ce que Computer_System: The_System? Ici, tout est simple. Dans cette série d'articles, je fais la promotion d'une idée avancée où le système informatique est au niveau supérieur de la hiérarchie.
Et cet exemple a cette couche Verilog:
 module DE0_Nano_SoC_Computer ( //////////////////////////////////// // FPGA Pins //////////////////////////////////// // Clock pins input CLOCK_50, input CLOCK2_50, input CLOCK3_50, // ADC output ADC_CONVST, output ADC_SCLK, output ADC_SDI, input ADC_SDO, // ARDUINO inout [15:0] ARDUINO_IO, inout ARDUINO_RESET_N, // GPIO inout [35:0] GPIO_0, inout [35:0] GPIO_1, // KEY input [1:0] KEY, // LED output [7:0] LED, // SW input [3:0] SW, //////////////////////////////////// // HPS Pins //////////////////////////////////// // DDR3 SDRAM output [14:0] HPS_DDR3_ADDR, output [2:0] HPS_DDR3_BA, output HPS_DDR3_CAS_N, output HPS_DDR3_CKE, output HPS_DDR3_CK_N, output HPS_DDR3_CK_P, output HPS_DDR3_CS_N, output [3:0] HPS_DDR3_DM, inout [31:0] HPS_DDR3_DQ, inout [3:0] HPS_DDR3_DQS_N, inout [3:0] HPS_DDR3_DQS_P, output HPS_DDR3_ODT, output HPS_DDR3_RAS_N, output HPS_DDR3_RESET_N, input HPS_DDR3_RZQ, output HPS_DDR3_WE_N, // Ethernet output HPS_ENET_GTX_CLK, inout HPS_ENET_INT_N, output HPS_ENET_MDC, inout HPS_ENET_MDIO, input HPS_ENET_RX_CLK, input [3:0] HPS_ENET_RX_DATA, input HPS_ENET_RX_DV, output [3:0] HPS_ENET_TX_DATA, output HPS_ENET_TX_EN, // Accelerometer inout HPS_GSENSOR_INT, // I2C inout HPS_I2C0_SCLK, inout HPS_I2C0_SDAT, inout HPS_I2C1_SCLK, inout HPS_I2C1_SDAT, // Pushbutton inout HPS_KEY, // LED inout HPS_LED, // LTC inout HPS_LTC_GPIO, // SD Card output HPS_SD_CLK, inout HPS_SD_CMD, inout [3:0] HPS_SD_DATA, // SPI output HPS_SPIM_CLK, input HPS_SPIM_MISO, output HPS_SPIM_MOSI, inout HPS_SPIM_SS, // UART input HPS_UART_RX, output HPS_UART_TX, // USB inout HPS_CONV_USB_N, input HPS_USB_CLKOUT, inout [7:0] HPS_USB_DATA, input HPS_USB_DIR, input HPS_USB_NXT, output HPS_USB_STP ); //======================================================= // REG/WIRE declarations //======================================================= wire hps_fpga_reset_n; //======================================================= // Structural coding //======================================================= Computer_System The_System ( //////////////////////////////////// // FPGA Side //////////////////////////////////// // Global signals .system_pll_ref_clk_clk (CLOCK_50), .system_pll_ref_reset_reset (1'b0), // ADC .adc_sclk (ADC_SCLK), .adc_cs_n (ADC_CONVST), .adc_dout (ADC_SDO), .adc_din (ADC_SDI), // Arduino GPIO .arduino_gpio_export (ARDUINO_IO), // Arduino Reset_n .arduino_reset_n_export (ARDUINO_RESET_N), // Slider Switches .slider_switches_export (SW), // Pushbuttons .pushbuttons_export (~KEY), // Expansion JP1 .expansion_jp1_export ({GPIO_0[35:19], GPIO_0[17], GPIO_0[15:3], GPIO_0[1]}), // Expansion JP7 .expansion_jp7_export ({GPIO_1[35:19], GPIO_1[17], GPIO_1[15:3], GPIO_1[1]}), // LEDs .leds_export (LED), //////////////////////////////////// // HPS Side //////////////////////////////////// // DDR3 SDRAM .memory_mem_a (HPS_DDR3_ADDR), .memory_mem_ba (HPS_DDR3_BA), .memory_mem_ck (HPS_DDR3_CK_P), .memory_mem_ck_n (HPS_DDR3_CK_N), .memory_mem_cke (HPS_DDR3_CKE), .memory_mem_cs_n (HPS_DDR3_CS_N), .memory_mem_ras_n (HPS_DDR3_RAS_N), .memory_mem_cas_n (HPS_DDR3_CAS_N), .memory_mem_we_n (HPS_DDR3_WE_N), .memory_mem_reset_n (HPS_DDR3_RESET_N), .memory_mem_dq (HPS_DDR3_DQ), .memory_mem_dqs (HPS_DDR3_DQS_P), .memory_mem_dqs_n (HPS_DDR3_DQS_N), .memory_mem_odt (HPS_DDR3_ODT), .memory_mem_dm (HPS_DDR3_DM), .memory_oct_rzqin (HPS_DDR3_RZQ), // Accelerometer .hps_io_hps_io_gpio_inst_GPIO61 (HPS_GSENSOR_INT), // Ethernet .hps_io_hps_io_gpio_inst_GPIO35 (HPS_ENET_INT_N), .hps_io_hps_io_emac1_inst_TX_CLK (HPS_ENET_GTX_CLK), .hps_io_hps_io_emac1_inst_TXD0 (HPS_ENET_TX_DATA[0]), .hps_io_hps_io_emac1_inst_TXD1 (HPS_ENET_TX_DATA[1]), .hps_io_hps_io_emac1_inst_TXD2 (HPS_ENET_TX_DATA[2]), .hps_io_hps_io_emac1_inst_TXD3 (HPS_ENET_TX_DATA[3]), .hps_io_hps_io_emac1_inst_RXD0 (HPS_ENET_RX_DATA[0]), .hps_io_hps_io_emac1_inst_MDIO (HPS_ENET_MDIO), .hps_io_hps_io_emac1_inst_MDC (HPS_ENET_MDC), .hps_io_hps_io_emac1_inst_RX_CTL (HPS_ENET_RX_DV), .hps_io_hps_io_emac1_inst_TX_CTL (HPS_ENET_TX_EN), .hps_io_hps_io_emac1_inst_RX_CLK (HPS_ENET_RX_CLK), .hps_io_hps_io_emac1_inst_RXD1 (HPS_ENET_RX_DATA[1]), .hps_io_hps_io_emac1_inst_RXD2 (HPS_ENET_RX_DATA[2]), .hps_io_hps_io_emac1_inst_RXD3 (HPS_ENET_RX_DATA[3]), // I2C .hps_io_hps_io_i2c0_inst_SDA (HPS_I2C0_SDAT), .hps_io_hps_io_i2c0_inst_SCL (HPS_I2C0_SCLK), .hps_io_hps_io_i2c1_inst_SDA (HPS_I2C1_SDAT), .hps_io_hps_io_i2c1_inst_SCL (HPS_I2C1_SCLK), // Pushbutton .hps_io_hps_io_gpio_inst_GPIO54 (HPS_KEY), // LED .hps_io_hps_io_gpio_inst_GPIO53 (HPS_LED), // LTC .hps_io_hps_io_gpio_inst_GPIO40 (HPS_LTC_GPIO), // SD Card .hps_io_hps_io_sdio_inst_CMD (HPS_SD_CMD), .hps_io_hps_io_sdio_inst_D0 (HPS_SD_DATA[0]), .hps_io_hps_io_sdio_inst_D1 (HPS_SD_DATA[1]), .hps_io_hps_io_sdio_inst_CLK (HPS_SD_CLK), .hps_io_hps_io_sdio_inst_D2 (HPS_SD_DATA[2]), .hps_io_hps_io_sdio_inst_D3 (HPS_SD_DATA[3]), // SPI .hps_io_hps_io_spim1_inst_CLK (HPS_SPIM_CLK), .hps_io_hps_io_spim1_inst_MOSI (HPS_SPIM_MOSI), .hps_io_hps_io_spim1_inst_MISO (HPS_SPIM_MISO), .hps_io_hps_io_spim1_inst_SS0 (HPS_SPIM_SS), // UART .hps_io_hps_io_uart0_inst_RX (HPS_UART_RX), .hps_io_hps_io_uart0_inst_TX (HPS_UART_TX), // USB .hps_io_hps_io_gpio_inst_GPIO09 (HPS_CONV_USB_N), .hps_io_hps_io_usb1_inst_D0 (HPS_USB_DATA[0]), .hps_io_hps_io_usb1_inst_D1 (HPS_USB_DATA[1]), .hps_io_hps_io_usb1_inst_D2 (HPS_USB_DATA[2]), .hps_io_hps_io_usb1_inst_D3 (HPS_USB_DATA[3]), .hps_io_hps_io_usb1_inst_D4 (HPS_USB_DATA[4]), .hps_io_hps_io_usb1_inst_D5 (HPS_USB_DATA[5]), .hps_io_hps_io_usb1_inst_D6 (HPS_USB_DATA[6]), .hps_io_hps_io_usb1_inst_D7 (HPS_USB_DATA[7]), .hps_io_hps_io_usb1_inst_CLK (HPS_USB_CLKOUT), .hps_io_hps_io_usb1_inst_STP (HPS_USB_STP), .hps_io_hps_io_usb1_inst_DIR (HPS_USB_DIR), .hps_io_hps_io_usb1_inst_NXT (HPS_USB_NXT) ); endmodule 


Je l'ai spécifiquement apporté dans son intégralité pour souligner la quantité de code complètement inutile que vous devez écrire dans ce cas. Et si les jambes sont ajoutées ou supprimées, ce code devra également être modifié. En fait, les lignes


Même texte:
 ... Computer_System The_System ( //////////////////////////////////// // FPGA Side //////////////////////////////////// // Global signals .system_pll_ref_clk_clk (CLOCK_50), ... 


et donnez ce préfixe. Les auteurs estiment que la hiérarchie doit être telle, seulement ceci et pas d'autre. Le système de processeur ne peut pas être retiré plus profondément et ne peut pas être transporté.

Nous ne devons pas attendre la pitié de la nature, prenez-la - notre tâche!


Avons-nous vraiment fait un tel travail uniquement pour supporter cette affaire? Comme un de mes amis aime à le dire: «le travail inutile est pire que l'ivresse», et la création d'une telle couche est un cas typique de travail inutile. Par conséquent, nous essaierons de contourner cette limitation. Rappelez-vous, lorsque vous appelez un programme JAVA tiers, le code a substitué un script tcl, je l'ai également copié dans le répertoire à côté du fichier sof? C'est notre salut! C'est lui qui indique à la console système les actions à entreprendre et c'est lui qui formate la réponse. le formatage se présente comme suit:

Même texte:
 # PRINT OUT INSTANCE ID INFO FOR EVERYTHING: set i 0 foreach path [lsort -command compare_node_number [get_service_paths bytestream]] { # If this path corresponds to a JTAG UART, incr i if {[string match *$cable_name* $path ] && [string match *jtag_uart* [marker_get_type $path] ]} { puts "[marker_get_info $path] (INSTANCE_ID:$i)" incr i } } set i 0 foreach path [lsort -command compare_node_number [get_service_paths processor]] { # If this path corresponds to a NiosII, incr i if {[string match *$cable_name* $path ] && [string match *nios2* [marker_get_type $path] ]} { puts "[marker_get_info $path] (INSTANCE_ID:$i)" incr i } } 


Le premier bloc formate les informations sur les blocs JTAG_UART, le second - sur les cœurs de processeur. Maintenant, si ici nous ajoutons des lignes verticales au flux de sortie! Mon collègue a corrigé cet article comme suit:
 # PRINT OUT INSTANCE ID INFO FOR EVERYTHING: set i 0 foreach path [lsort -command compare_node_number [get_service_paths bytestream]] { # If this path corresponds to a JTAG UART, incr i if {[string match *$cable_name* $path ] && [string match *jtag_uart* [marker_get_type $path] ]} { set info [marker_get_info $path] if {[string first "|" $info] == -1} { set info [string map {"FULL_HPATH " "FULL_HPATH a:b|"} $info] } puts "$info (INSTANCE_ID:$i)" incr i } } set i 0 foreach path [lsort -command compare_node_number [get_service_paths processor]] { # If this path corresponds to a NiosII, incr i if {[string match *$cable_name* $path ] && [string match *nios2* [marker_get_type $path] ]} { set info [marker_get_info $path] if {[string first "|" $info] == -1} { set info [string map {"FULL_HPATH " "FULL_HPATH a:b|"} $info] } puts "$info (INSTANCE_ID:$i)" incr i } } 

Maintenant, s'il n'y a pas de tirets, ils seront ajoutés. Et enfin, le programme fonctionnera non seulement avec un terrible, mais aussi avec un système de processeur écrit de manière optimale!

Configuration d'un projet dans Altera Monitor


Uffff. C’est tout. La fin du gougeage, du tout-terrain et de la négligence (bien que, tout-terrain - ce n'est pas exact). Encore une fois, les dessins de l'article reflètent les instructions de travail! Nous avons un projet pour les FPGA, ainsi qu'un programme qui se construit et s'exécute dans Eclipse. Lancez maintenant Altera Monitor et créez un projet.



Nous créons un catalogue avec le projet (je le mets séparément du projet pour FPGA) et donnons le nom du projet. Choisissez également une architecture de processeur



Le système que je choisis est un système personnalisé. Vous devez spécifier mes fichiers * .sof et * .sopcinfo. Je les sélectionne dans les répertoires de travail. Notre système n'a pas besoin de préchargeur.



Sélectionnez le type de programme Programme avec prise en charge du pilote de périphérique, puis la bibliothèque BSP sera créée:



Il n'y a pour l'instant qu'un seul fichier de travail (il a été créé dans Eclipse). Ici, je l'ajoute:



Dans la dernière fenêtre, je ne change rien:



Nous acceptons le téléchargement du fichier sof:



Si nous venons d'installer le logiciel, nous sommes passés en mode source. Ensuite, il sera déjà activé (je vous montrerai à quoi ressemble le menu lorsque tout est déjà activé, il y aura également un élément à inclure).



J'ai le programme C le plus simple:
 #include "sys/alt_stdio.h" int main() { alt_putstr("Hello from Nios II!\n"); volatile int i=0; i += 1; i += 2; i += 3; i += 4; i += 5; i += 6; i += 7; i += 8; i += 9; i += 10; i += 11; i += 12; /* Event loop never exits. */ while (1); return 0; } 

J'essaye de le récupérer:



Je reçois une erreur:
c: /intelfpga/17.1/nios2eds/bin/gnu/h-x86_64-mingw32/bin /../ lib / gcc / nios2-elf / 5.3.0 /../../../../ .. /H-x86_64-mingw32/nios2-elf/bin/ld.exe: région `Code 'débordée de 15888 octets

C'est parce que je n'ai pas ajouté de SDRAM au système, je l'ai limité à la mémoire FPGA interne. Mais pourquoi tout s'intégrait-il dans Eclipse, mais pas ici? Parce que j'y ai choisi BSP avec le suffixe Small, mais ici on m'a automatiquement fait un package régulier. Par conséquent, ouvrez le fichier: C: \ Work \ Play2 \ BSP \ settings.bsp

Et nous commençons le réglage manuel.





Reconstruire BSP:



Et encore une fois, nous collectons le projet. Cette fois avec succès. Maintenant, chargez-le:



Enfin, la vraie trace


Tu n'as pas oublié pourquoi je fais tout ça? Je fais cela pour le traçage. Il doit être activé. Pour ce faire, accédez à l'onglet Trace et sélectionnez Activer la trace dans le menu contextuel:



Je mettrai un point d'arrêt à la fin de la fonction main () sur l'onglet Désassemblage (à quel point l'assembleur RISC s'occupe bien du terrible assembleur de pile dans lequel le code Java se transforme!)

Voici le début de la fonction principale:



Faites défiler un peu et mettez un point d'arrêt ici:



Nous commençons, attendons un arrêt et allons dans l'onglet Trace.

En général, tout n'est pas très bon. Au début, il y avait évidemment une sorte d’attente (nous avions là une conclusion dans JTAG, donc c’est une chose légitime):



En fin de compte - un autre code ... Mais je ne vois pas le code de fonction principale! Voici la fin:



Je ne sais même pas quoi dire. Mais de toute façon, si vous mettez non pas un, mais deux points d'arrêt (au début et à la fin de la fonction principale), puis après avoir exécuté du premier au deuxième, l'image sera décente:



Brèves conclusions


Nous avons donc découvert qu'il était tout à fait possible de découvrir comment fonctionnait un site particulier. Ainsi, le sujet de l'article ("... comment le processeur est arrivé à une telle vie") est divulgué. Il est plus intéressant de voir comment tous ceux dont les problèmes ont dû être résolus pour obtenir un résultat sont arrivés à une telle vie? Et il est très regrettable que jusqu'à présent je n'ai pas pu déterminer combien de barres une équipe particulière a complétées. D'après des extraits de documentation, il est clair que cela semble techniquement possible, mais le logiciel qui permettra de le faire n'est pas clair. Il y a une opinion que le document Analyser et déboguer des conceptions avec la console système , que j'ai dû lire lors de l'analyse du script tcl, nous aidera. Il a une tablette intéressante Tableau 10-15: Commandes du système de trace , mais personnellement, je n'ai tout simplement pas le temps pour une étude détaillée de cette question. Mais peut-être que ce sera si important pour quelqu'un qu'il mettra tout en œuvre. Ces commandes sont incluses dans les scripts tcl.

Eh bien, dans les articles suivants, les mesures devront être faites à l'ancienne, avec un oscilloscope.

Source: https://habr.com/ru/post/fr464795/


All Articles