
Al depurar programas regulares, los puntos de interrupción se pueden establecer en casi todas partes y en cantidades bastante grandes. Por desgracia Cuando se ejecuta un programa en el controlador, esta regla no se aplica. Si hay una sección en la que se forma el diagrama de tiempo, entonces la parada lo arruinará todo. Y el pasaje a bajas y altas frecuencias no es lo mismo. Las condiciones de frontera son un flagelo para los desarrolladores. O, digamos, un bus USB. En NIOS II, no trabajé con él, pero en STM32 es terrible. Y quiero ver algo, y cuando te detienes, tomas un tiempo de espera. En general, muy a menudo, a pesar de la presencia de depuración avanzada de JTAG, el comportamiento del programa en áreas críticas es oscuro. ¡Sería genial ver, al menos después de la ejecución, por qué cadena pasó el programa, qué ramas funcionaron y cuáles no!
Es aún más importante conocer el historial de excepciones. En NIOS II, no hice esto, sino en el Cyclone V SoC en el núcleo ARM, completamente. Al depurar, todo funciona, y si inicia el programa desde ROM, obtendrá una excepción. Está claro cómo entraron, y qué tipo de desarrollo de la situación llevó a esto no es. El rastreo también rompe todas las cubiertas.
Artículos anteriores de la serie:
- Desarrollo del "firmware" más simple para FPGAs instalados en Redd, y depuración utilizando la prueba de memoria como ejemplo
- Desarrollo del "firmware" más simple para FPGAs instalados en Redd. Parte 2. Código del programa
- Desarrollo de su propio núcleo para incrustar en un sistema de procesador basado en FPGA
- Desarrollo de programas para el procesador central Redd sobre el ejemplo de acceso a la FPGA
- Los primeros experimentos que utilizan el protocolo de transmisión en el ejemplo de comunicación de CPU y procesador en el FPGA Redd
Introduccion
Es costumbre escribir artículos educativos con una cara seria, exponiendo el material con calma e imparcialidad. Pero, por desgracia, esto no siempre funciona. Ahora, de acuerdo con el plan, debería haber un artículo sobre la optimización del procesador sintetizado en el complejo Redd, en el que debemos hablar sobre las características de trabajar con el caché. El siguiente es un artículo sobre retrasos al acceder al autobús. En general, todo esto se puede mostrar en un osciloscopio. Ya hice esto en un artículo sobre DMA ("
DMA: Mitos y realidad "). Pero quería demostrar todo utilizando el procesador en sí, realicé tales comprobaciones para el núcleo ARM en el FPGA Cyclone V SoC. Muy conveniente (aunque los resultados no fueron publicados). Por esta razón, decidí tratar con el mecanismo de rastreo inherente en el bloque JTAG. Es una pena que hasta ahora no haya podido mostrar con medios descargables gratuitos cuántas barras se estaban reproduciendo este o aquel comando, pero había material por medio del cual siempre se puede preguntar al programa cómo llegó a tal vida. Bueno, y además, aunque los recuerdos de las noches de tormenta todavía están frescos en mi memoria, los arrojaré de una manera bastante emocional. Así que hoy habrá muchas memorias y una pequeña teoría útil.
Hardware
Entonces, muy a menudo al depurar un programa para un microcontrolador, es deseable conocer el camino que ha recorrido, y debe pasarlo a toda velocidad. Para el caso de NIOS II, este mecanismo está disponible y se incluye aquí en esta pestaña de las propiedades del núcleo del procesador:

Tipo de rastreo establece el tipo de información que se almacenará. No puede guardar nada (esto ahorrará la memoria del chip), puede guardar solo el historial de comandos (lo más frecuente es que sea suficiente), bueno, o guardar el historial de comandos y datos. Vale la pena señalar que la documentación dice que en el último modo, guardar información es de alguna manera difícil, mientras que las superposiciones con el historial de comandos son posibles y se consume más memoria. Utilice este modo solo cuando sea realmente necesario.
El parámetro Almacenamiento de rastreo establece el tipo de memoria en la que se guardará el rastreo. La documentación dice que la memoria externa no es compatible con el entorno de desarrollo estándar. Por lo tanto, es mejor elegir solo el interior.

Bueno, Onchip Trace Frame Size establece el tamaño del búfer. Cuanto más grande sea el búfer, más eventos se pueden colocar en él, mayor será el historial. Pero menos será el recuerdo del cristal para otras necesidades.

No es necesario habilitar la casilla de verificación para crear un puerto JTAG separado. Deje que todo taxis sea regular.
Soporte de software
Bueno Así que configuramos el núcleo del procesador, ¿qué sigue? Ohhhh! Entonces comienza la historia de detectives. Si las figuras anteriores se deben interpretar como una guía de acción, entonces seguirán ilustraciones que muestran un desorden y náuseas. Varios documentos dicen que para trabajar con el rastreo, debe usar programas caros de terceros e incluso equipos especiales de JTAG. Pero en algunos documentos se resbala que puede tomar algo a tiempo completo.
Experimentos Eclipse
Genial Echemos un vistazo a Eclipse. Les recuerdo que uso el entorno de desarrollo Quartus Prime 17.1. Bueno, sucedio. Iniciamos el programa para la depuración y vamos al elemento del menú que le permite abrir varias ventanas:

Allí seleccionamos la ventana Debug-> Trace Control:

Y obtenemos un muñeco así:

Pero se inicia la sesión de depuración. Además, los elementos del menú Comenzar rastreo y Detener rastreo incluso aparecieron en él (antes de abrir esta ventana no estaban). Pero están bloqueados. Y no pude activarlos.

En vano llené Google con diferentes solicitudes. En documentos antiguos, se describe que estos elementos funcionan bastante bien, pero en los modernos simplemente no se mencionan. Nadie los menciona en los foros. ¿Quizás alguien en los comentarios te diga algo?
Problemas con la última versión de Eclipse
Bueno ¿Qué pasa con la última versión del entorno de desarrollo? Tal vez todo funciona allí? Yyyyyy! Este es un tema para un capítulo separado. La última versión para el cuarto y quinto ciclones es 18.1.1. Es decir, primero debe descargar la versión 18.1 y luego instalar la actualización 18.1.1. Si alguien decidió que tengo demasiado tiempo libre, que reorganizo el software por el bien de cada pequeña cosa, entonces todo está bien. La verificación principal fue sobre problemas de caché. Son más serios, quería comprobarlos en la nueva versión, simplemente no estoy escribiendo sobre ellos aquí.
Entonces, lo descargué. Instalado. En primer lugar, se lanza la versión 18.1 bajo WIN7, pero 18.1.1 no encuentra la DLL. Bueno Descubrí que necesito descargar Redist de Visual Studio 2015. Lo instalé. Comenzó a correr. Creó un proyecto con un sistema procesador. Incluso se preparó. Voy a Eclipse, creando un programa con BSP basado en él, todo, como ya lo hemos hecho muchas veces ... Y obtengo tal cosa ...

El proyecto no va a. Si sale y entra, se abre solo parcialmente.

¿Ves la carpeta cerrada? Ahí tienes. Por qué Ohhhh! Tres archivos tienen:

Estos son los maravillosos atributos de protección:

Por lo tanto, no se pueden abrir ni cambiar ... Si otorga más derechos, el proyecto se abrirá, pero los archivos no se crean por completo, por lo que no funcionará recopilarlo. Intenté otorgar derechos hasta que Eclipse se cerró y luego guardé el proyecto. El resultado es el mismo.
¿Podría ser el culpable el rápido envejecimiento de Windows 7? ¡No es de extrañar que careciera de bibliotecas! Pongo Quartus nuevo en WIN10, ¡obtengo un resultado completamente idéntico al crear el proyecto! Tengo un amigo En virtud de su lugar de trabajo, a veces se encuentra con productos de fabricantes nacionales. Y expresa una serie de pensamientos sobre sí mismos y sobre sus parientes. Bueno, sobre el hecho de que "¿quién está construyendo esto?" Sabes, mirando las alegrías en el software Intel, empiezo a pensar que está lejos del país de origen ... En realidad, este no fue el caso bajo Alter ... Algo ha sucedido, pero no recuerdo eso.
Acabo de salir. Copié el proyecto en una unidad flash USB con el sistema de archivos FAT32. No hay atributos de seguridad. Abrí el proyecto desde allí, entré en Eclipse y creé el código. Sin atributos de seguridad, no hay problema. Luego lo volví a copiar en el disco duro y ... Bueno, por supuesto, tuve problemas para generar BSP. Porque el archivo * .bsp contiene muchas rutas relativas y una absoluta. Es bueno que saqué una unidad flash. De lo contrario, no me habría dado cuenta de que BSP se cae (ya que este es el lugar de nacimiento del proyecto), y el proyecto se recopila en el disco duro. Aquí hay un ejemplo de tal ruta (ya corregida):

Bueno, está bien ... Todo fue generado, ensamblado ... Y funciona exactamente igual que en la versión 17.1 ... Y para los controladores SoC en el nuevo entorno, también tienes que recrear la cadena JTAG cada vez en el programador. En la versión 17.1, fue suficiente para hacer esto una vez y guardar ... Eeeeeh. Bueno, bueno ...
Altera Monitor y su problema
De una forma u otra, las búsquedas en la red de las palabras Start Tracing y Stop Tracing me llevaron a documentos interesantes. Describen varias versiones de un programa divertido llamado
Altera Monitor hoy (el nombre era diferente en documentos antiguos). Encontrarla fue relativamente fácil. Debe descargar el paquete del
programa universitario para su versión del entorno de desarrollo. Presta atención a las restricciones de licencia. Pero como estamos estudiando ahora, no le tenemos miedo. Pero para el trabajo comercial, todo está mal allí. Detalles aquí:
www.intel.com/content/www/us/en/programmable/support/training/university/materials-software.htmlDescargar, poner ... Hay un documento adjunto a la versión actual (porque las versiones dispersas en Internet varían mucho). Incluso intenté ejecutar un ejemplo para mi placa de pruebas DE0-Nano-SoC. El esta trabajando. Pero cuando intenté hacer mi proyecto, no funcionó. El archivo * .sof se carga en el FPGA, después de lo cual, después de un tiempo, se muestra un mensaje:

Solo que no hay información en la ventana especificada. Si intenta descargar de nuevo: bueno, el texto aparecerá solo en esa ventana:
No se pudieron consultar los ID de instancia de JTAG.
Asegúrese de que el FPGA se haya configurado utilizando el archivo .sof correcto.¿Qué tipo de problema es este? Busqué en Google. Encontramos varios foros con el mismo problema. En un momento, un empleado de Intel preguntó qué frecuencia tiene el autor en JTAG y sugirió establecer uno estándar. Aunque, para ese momento, ya entendía que no era una cuestión de frecuencia: el ejemplo corporativo funcionó y cómo establecerlo. En un foro, el autor escribió que de alguna manera había pasado. No entendía cómo. Y dijo que si haces todo cuidadosamente de acuerdo con las instrucciones, todo funcionará. El resto de la imagen era igual. El hombre pregunta. No le responden. Después de seis meses o un año, alguien escribe que tiene la misma situación, ¿ha habido una solución? Y silencio aaaaaaaa ...
Intentos de solución experimentados
Bueno ¿Cuál podría ser el motivo? Al principio decidí mirar a mi alrededor con un ejemplo de trabajo. ¿Qué tipo de misteriosa identificación JTAG? ¿Podría esto ser debido a la presencia de un sistema de identificación del sistema en funcionamiento?

Sumado a sí mismo, no ayudó. ¿Quizás el culpable es el puente JTAG a Avalon, al que están conectados todos los dispositivos periféricos?

Agregado - no ayudó. Intenté algunas hipótesis más, pero me di cuenta de que puedes adivinar para siempre. Con pena, incluso le pregunté a Yandex, Bing e incluso BaiDu. Todos saben menos que Google. Quedó claro que teníamos que lidiar con la descompilación para probar desde el programa lo que necesitaba. Comprobado en qué idioma está escrito el programa. Resultó que en Java. El bytecode se almacena en el archivo Altera_Monitor_Program.jar. Bueno, es raro Excepto que no conozco este Java en absoluto. En Java Script, hubo un caso, incursionado en Internet de las cosas, pero no encontré un Java real. ¡Pero donde el nuestro no desapareció!
Análisis de bytecode de JAVA para encontrar el problema
¿Cómo abrir el código de bytes? Google condujo a un artículo sobre Habré, que dice que para esto necesitas usar la JD-GUI. Lo encontré en github, lo descargué. Identifiqué el área del problema con bastante rapidez, ya que la JD-GUI tiene una maravillosa navegación interactiva. Desde el mensaje al sitio, salí en 10 minutos. Esta sección llama a un programa de terceros, luego de lo cual analiza su respuesta. La llamada se ve así:
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()));
Bueno, y más allá: análisis de la respuesta que aún no consideramos.
Con este código, intenté abrir la consola NIOS II:

Allí fui al directorio donde está el archivo sof y conduje la línea de comando:
system-console --script = jtag_instance_check.tcl USB-0 test.sofSin embargo, para esto tuve que copiar el archivo C: \ intelFPGALite \ 17.1 \ University_Program \ Monitor_Program \ bin \ jtag_instance_check.tcl en el mismo lugar donde está sof, para no sufrir con la ruta. Al final, obtuve una respuesta bastante decente:
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)
Todo parece ser hermoso ...
JAVA Bytecode Tracing
Si el caso tuviera lugar hoy, esta sección no existiría. Pero sucedió ayer. Todavía entendía Java muy mal. Lo que estaba escrito allí mientras analizaba el texto era un bosque oscuro para mí. Es cierto que durante dos años mi hijo asistió a cursos de programación de olimpiadas en 1 franquiciado soviético (los certificados y folletos fueron 1 soviético). Se dio dinero loco para estos cursos. Y les enseñaron allí solo en Java. Entonces, tampoco entendió lo que estaba escrito más en el código (manteniendo la intriga, publicaré el código un poco más abajo, no ahora). En general, había una sensación persistente de que era hora de rastrear. Conozco la sección incorrecta, veo que las líneas se recibieron allí y al programa no le gustan con algo. ¿Y qué?
El niño me encontró un artículo muy maravilloso
www.crowdstrike.com/blog/native-java-bytecode-debugging-without-source-codeHabla de un complemento muy útil para Eclipse, que le permite trabajar con JAR, estableciendo puntos de interrupción en ellos. Dónde descargar, encontré aquí:
marketplace.eclipse.org/content/bytecode-visualizer/helpDescargué Eclipse, descargué el complemento para la instalación fuera de línea con pena a la mitad ... Comencé a instalar, no hay suficientes bibliotecas. Comencé a leer. Resulta que hay tres versiones del complemento. Bajo Eslipse 4.5 (Marte), 4.4 (Luna) y 4.3 (no recuerdo el nombre). Bueno, todo es simple. Vamos al sitio web de Eclipse, vemos un enlace para descargar la versión de Marte para Java ... Y ... está muerto. ¡No importa! ¡Hay alrededor de una docena de espejos! ... Y todos los enlaces a ellos están muertos. Intentamos Luna para Java, hay enlaces a x64 muertos, a x86 hay uno vivo ... Como dice un amigo mío: "Las hemorroides, son completas". En general, Google tuvo dificultades, pero me encontró un ensamblado Java de 64 bits de la versión Mars en algún servidor no oficial. Lo descargué durante media hora, pero lo descargué.
Implementé un complemento, creé un proyecto ... ¡Horror! Allí, la traza no está en el nivel del código fuente, sino en el nivel de un ensamblador la. En resumen, se rastrea el código de byte decodificado. Pero, de hecho, ¡no importa! Después de todo, siempre puede verificar con las fuentes descompiladas abiertas en otra ventana, además de que el complemento muestra muy buenos comentarios ... También resultó que los puntos de interrupción no se pueden establecer en ningún lugar, sino solo en la entrada de la función. ¡Pero no puedo parar! No hay mucho allí y debe caminar desde la entrada hasta el área problemática.
Permíteme recordarte que las líneas procesadas se ven así:
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)Y aquí está el código 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); }
Aísla perfectamente la ID de instancia. Y aquí está el código:
Pattern getHPath = Pattern.compile("FULL_HPATH (.+?)\\|(.+?) \\("); Matcher hpathMatcher = getHPath.matcher(str); if (hpathMatcher.find()) { hpath = hpathMatcher.group(2).replace("|", "."); }
La variable hpath no se completa. Hoy ya sé que la expresión regular:
"FULL_HPATH (.+?)\\|(.+?) \\("
requiere dos palabras separadas por una barra vertical. Bueno, entonces solo se toma lo que está después de la línea. No lo supe ayer. Más interesante es otro. ¡El niño estudió trabajo en Java durante dos años y no aprendió expresiones regulares! No, está claro que no se les enseñó el idioma, sino la programación de la Olimpiada utilizando el idioma, pero, según tengo entendido, las expresiones regulares en Java están en el orden de las cosas. Toman ese dinero, sacuden certificados de compañías de buena reputación, pero no enseñan cosas importantes ... Pero estoy divagando.
Luz al final del túnel.
¿Qué es la línea vertical? Tomamos el proyecto que funcionó, le damos el mismo equipo y obtenemos esta respuesta:
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é es Computer_System: The_System? Todo es simple aquí. En esta serie de artículos, estoy promoviendo una idea avanzada donde el sistema informático está en el nivel superior de la jerarquía.
Y este ejemplo tiene esta capa 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
Lo traje específicamente para enfatizar cuánto código completamente innecesario tienes que escribir en este caso. Y si se agregan o eliminan las patas, este código también tendrá que editarse. En realidad, las líneas

Mismo texto: ... Computer_System The_System ( //////////////////////////////////// // FPGA Side //////////////////////////////////// // Global signals .system_pll_ref_clk_clk (CLOCK_50), ...
y dale este prefijo. Los autores creen que la jerarquía debería ser tal, solo esto y no otro. El sistema del procesador no se puede quitar más profundo y no se puede cargar.
No debemos esperar la misericordia de la naturaleza, tómala, ¡nuestra tarea!
¿Realmente hemos hecho un trabajo tan solo para aguantar este asunto? Como a un amigo mío le gusta decir: "el trabajo innecesario es peor que la embriaguez", y la creación de esa capa es un caso típico de trabajo innecesario. Por lo tanto, trataremos de eludir esta limitación. Recuerde, al llamar a un programa JAVA de terceros, el código sustituyó a un script tcl, ¿también lo copié en el directorio al lado del archivo sof? ¡Es nuestra salvación! Es él quien le dice a la consola del sistema qué acciones tomar y es él quien formatea la respuesta. el formato es así:

Mismo texto: # 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 } }
El primer bloque formatea información sobre los bloques JTAG_UART, el segundo, sobre los núcleos del procesador. ¡Ahora, si aquí agregamos líneas verticales a la secuencia de salida! Mi colega corrigió esta sección de la siguiente manera:
# 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 } }
Ahora, si no hay guiones, se agregarán. Y, por último, el programa funcionará no solo con un sistema de procesador terrible, sino también con un procesador óptimamente escrito.
Configurar un proyecto en Altera Monitor
Uffff Eso es todo. El final de la excavación, todo terreno y descuido (aunque, sobre todo terreno, esto no es exacto). ¡Ahora, nuevamente, los dibujos en el artículo reflejan las instrucciones para el trabajo! Tenemos un proyecto para FPGA, así como un programa que se construye y ejecuta en Eclipse. Ahora inicie Altera Monitor y cree un proyecto.

Cree un directorio con el proyecto (lo puse por separado del proyecto para FPGA) y asigne el nombre del proyecto. También elija una arquitectura de procesador

El sistema que elijo es Sistema personalizado. Debe especificar mis archivos * .sof y * .sopcinfo. Los selecciono en los directorios de trabajo. Nuestro sistema no necesita un precargador.

Seleccione el tipo de programa Programa con soporte de controlador de dispositivo, luego se construirá la biblioteca BSP:

Hasta ahora solo hay un archivo de trabajo (se creó en Eclipse). Aquí lo agrego:

En la última ventana, no cambio nada:

Aceptamos la descarga del archivo sof:

Si acabamos de instalar el software, cambiamos al modo fuente. Entonces ya estará activado (le mostraré cómo se ve el menú cuando todo esté activado, también habrá un elemento para incluir).

Tengo el programa C más 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; }
Estoy tratando de coleccionarlo:

Me sale un error:
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: la región 'Código' se desbordó en 15888 bytesEsto se debe a que no agregué SDRAM al sistema, lo limité a la memoria interna FPGA. Pero, ¿por qué todo encajaba en Eclipse, pero no aquí? Porque elegí BSP allí con el sufijo Small, pero aquí se me hizo automáticamente un paquete normal. Por lo tanto, abra el archivo: C: \ Work \ Play2 \ BSP \ settings.bsp
Y comenzamos la sintonización manual.


Reconstruir BSP:

Y de nuevo recogemos el proyecto. Esta vez con exito. Ahora cárgalo:

Finalmente, el rastro real
¿No has olvidado por qué hago todo esto? Hago esto para rastrear. Debe estar activado. Para hacer esto, vaya a la pestaña Rastreo y seleccione Habilitar rastreo en el menú contextual:

Pondré un punto de interrupción al final de la función main () en la pestaña Desmontaje (¡qué agradable es el ensamblador RISC para el terrible ensamblador de pila en el que se convierte el código Java!)
Aquí está el comienzo de la función principal:

Desplácese hacia abajo un poco y ponga un punto de interrupción aquí:

Comenzamos, esperamos una parada y vamos a la pestaña Trazar.
En general, todo no es muy bueno. Al principio, obviamente había algún tipo de expectativa (tuvimos una conclusión en JTAG allí, por lo que es algo legítimo):

Al final, algún otro código ... ¡Pero no veo el código de la función principal! Aquí está el final:

Ni siquiera sé qué decir. Pero de todos modos, si coloca no uno sino dos puntos de interrupción (al principio y al final de la función principal), luego de ejecutar del primero al segundo, la imagen será decente:

Breves conclusiones
Entonces, descubrimos que es muy posible descubrir cómo funciona un sitio en particular. Entonces, se revela el tema del artículo ("... cómo el procesador ha llegado a tal vida"). Es más interesante cómo todos aquellos cuyos problemas tuvieron que resolverse para obtener un resultado han llegado a tal vida. Y es muy lamentable que hasta ahora no haya podido determinar cuántos barriles completó un equipo en particular. A partir de fragmentos de documentación, está claro que esto parece ser técnicamente posible, pero qué software permitirá que esto se haga no está claro. Existe la opinión de que el documento
Análisis y depuración de diseños con la consola del sistema , que tuve que leer al analizar el script tcl, nos ayudará. Tiene una tableta interesante
Tabla 10-15: Comandos del sistema de rastreo , pero personalmente, no tengo tiempo para un estudio detallado de este asunto. Pero quizás sea tan importante para alguien que implemente todo. Estos comandos están incluidos en los scripts tcl.
Bueno, en los siguientes artículos, las mediciones tendrán que hacerse a la antigua, con un osciloscopio.