=== [I] Setup del HPS y SDRAM === Luego de agregar el HPS a Platform Designer hay que ejecutar un script Tcl para que Quartus agarre la config correcta de impedancias y más magia. Si se sintetiza sin más acción entonces pasa esto: Error (174068): Output buffer atom "platform:plat|platform_hps_0:hps_0|platform_hps_0_hps_io:hps_io|platform_hps_0_hps_io_border:border|hps_sdram:hps_sdram_inst|hps_sdram_p0:p0|hps_sdram_p0_acv_hard_memphy:umemphy|hps_sdram_p0_acv_hard_io_pads:uio_pads|hps_sdram_p0_altdqdqs:dq_ddio[0].ubidir_dq_dqs|altdq_dqs2_acv_connect_to_hard_phy_cyclonev:altdq_dqs2_inst|obuf_os_bar_0" has port "PARALLELTERMINATIONCONTROL[8]" connected, but does not use calibrated on-chip termination Foro: Tools > Tcl Scripts. There navigate through your QSys project, synthesis > submodules folders, and there you should find a script whose name ends with pin_assignments.tcl . Select that script, run it and try and compile the project again Nota: es *_pin_assignments.tcl y no ningún otro === [II] Emulación de Avalon === Para las señales fuera del top que C++ escribe, por ejemplo en tb/platform.sv, se necesita /*verilator public_flat_rw @(negedge clk_clk)*/ en vez de /*verilator public*/ (la última igual se usa para señales que C++ lee). Poner lo segundo en una señal `s` hace que `assign a = s;` no tenga ningún efecto, lo cual es difícil de depurar. https://github.com/verilator/verilator/issues/2262 === [III] MSEL, uboot y fpga2sdram === Solamente cambiar MSEL a 01010, convertir a rbf en Quartus y tratar de programar desde uboot resulta en esto: SOCFPGA_CYCLONE5 # fpga load 0 ${fpgadata} ${fpgadatasize} altera_load: Failed with error code -4 Hay que setear un modo en opciones de Quartus para que esto sirva. También puse el MSEL en 00000 por si acaso. El manual dice que 00000 corresponde a FPPx16 https://community.intel.com/t5/FPGA-SoC-And-CPLD-Boards-And/Altera-Cyclone-V-development-board-FPGA-problem-error-code-4/m-p/103855 Ahora pasa una de cuatro cosas con `mw 0xFFC2505C 0xA` (apply en registro staticcfg): 1. Hard-lock 2. Data abort 3. Prefetch abort 4. Como 1/10 veces parece servir Sin apply la flag de done se queda levantada por siempre al tocar memoria. Hice de cero varias partes del Platform en Platform Designer, también desactivé MPU events en hps_0 y cambié el data width de fpga2sdram de 64 a 256 bits. Todo sigue igual. Si omito la instrucción que toca applycfg algo sirve. Escribir ya sirve (confirmado con dd if=/dev/mem en HPS). Leer crashea el HPS tal como predice zangman. Shintel al rescate: https://www.intel.com/content/www/us/en/programmable/support/support-resources/knowledge-base/embedded/2016/how-and-when-can-i-enable-the-fpga2sdram-bridge-on-cyclone-v-soc.html?utm_source=Altera&utm_medium=newsletter&utm_campaign=FACTS&utm_content=NA_how_can_i_enable_KI_15_08_2016 Bug exacto: https://forum.rocketboards.org/t/fpga-to-sdram-cyclone-v-can-write-but-cannot-read/2796 Errata: https://support.criticallink.com/redmine/projects/mityarm-5cs/wiki/Important_Note_about_FPGAHPS_SDRAM_Bridge El problema parece ser uno de dos: - Me faltan las señales de burst - uboot está en RAM cuando se toca applycfg Para lo segundo, errata dice que: Altera has provided the capability to set the configuration bit in step three with a macro command in their (and Critical Link's) u-Boot port. This is accomplished by copying a small routine to on-chip RAM that disables caches and asserts the APPLYCFG bit and then returns operation to the typical DDR space. No sé donde putas está esa macro, así que voy a escribir mi propia: Info sobre OCRAM (on-chip RAM): https://www.intel.com/content/www/us/en/programmable/hps/cyclone-v/hps.html#sfo1410068453374.html#sfo1410068453374 sdram_staticcfg_applycfg: dmb dsb isb mov r0, #0x505c movt r0, #0xffc2 mov r1, #0xa str r1, [r0] dmb dsb mov r0, #0 bx lr Trivial. Esto solucionó todo. === [IV] Minimizando ciclos y evitando una Fmax asquerosa === Para este punto ya tengo semi-pipeline ((pre)fetch, decode, exec con máquina de estados multiciclo en exec), register file (duplicado para tener dos read ports), ALU, shifter, branches, condiciones y todas las instrucciones de procesamiento de datos. También simuladores de Avalon y VGA. En este momento necesitamos block memory real (no construida con lógica) para el archivo de registros. El problema es que al ser memoria síncrona existe un ciclo intermedio entre leer y recibir la lectura. Esto es absolutamente inaceptable. Hay dos grandes dilemas: - La altsyncram no está calzando con el diseño - La Fmax se está yendo directo al caño (antes iba por como 120MHz, hoy tocó piso con ~30MHz), principalmente por culpa de esa memoria y también que el shifter está en serie con la ALU. Traté de hacer un workaround con @(negedge clk) para operaciones de register file. Esto arregla las cosas en Verilator pero reduce la Fmax a la mitad (!!!!) en la cuarta esencia. Algunas Fmax: - ~30MHz con @(negedge clk) - ~60MHz con @(posedge clk) (claramente no sirve pero da una idea) - 75.57MHz si quito el shifter del todo También sospecho que es buena idea ponerle su propioo reloj a platform para que no estorbe, pero para eso necesito un clock crossing bridge y una PLL. El operand forwarding también está destruyendo todo, luego del cambio del shifter todos los top failling paths se nota que vienen de eso. Lo voy a cambiar por stalls artificiales. Subió a 105MHz con esto. La limitante ahora parecen ser los bloques M10K de register file. Luego de reacomodar la relación shifter-ALU (rediseño grande) hay Fmax = 102.99MHz con el Slow 1100mV 0C Model. Reemplazando el register file con un registro dummy obtengo 108.52MHz. Hay una ruta crítica entre cycles.pc y psr.flags. Principales causas identificadas: - Los M10K limitan a no más de 110MHz por alguna razón - Lógica combinacional para seleccionar entre PC y file_rd_value - Entradas combinacionales de ALU en cycles, esto llega hasta psr.flags Voy a seguir con esto después. === [V] Port (more like stub inicial) de U-Boot === Lo útil empieza en l[ineas 2108 y 3086 del README. === [VI] Ejecución de Qsys (Platform Designer) de manera OS-agnóstica === EL problema de NullPointerExceptions de AWT al abrir QSys en sistemas non-NixOS, es por configuración de fonts. Ver este caso: La soloución es usar home-manager o utilizar: export LOCALE_ARCHIVE="${pkgs.glibcLocales}/lib/locale/locale-archive" export FONTCONFIG_FILE="${pkgs.fontconfig.out}/etc/fonts/fonts.conf" === [VII] Reset === Hasta el momento todo había sido simulado y eso ha evitado mil problemas imposibles de depurar que, inevitablemente, ocurrieron cuando traté de ejecutar el sistema en la FPGA. Desde U-Boot (HPS) hubo indicios de que algo estaba ocurriendo en las direcciones de memoria que sim/sdram presuntamente escribe. 0x20001000 estaba forzado a cero y cualquier intento de escribir con md.l no tenía efecto (probablemente por writes sin fin a esa dirección). Además, a veces esto no pasaba al azar, sino que del todo no ocurría nada. Claramente hay problemas de reset. En el primer intento no existían conexiones de reset del todo, y además Verilator inicializaba todos los x-values a cero. Introduje aleatorización de 'x en simulación para arreglar todos los glitches de reset, y además reemplacé los bloques initial con resets reales en listas de sensibilidad. En el proceso descubrí varios bugs en fetch, decode y control. Agregué un JTAG-to-Avalon Bridge para depurar. Luego de realizar estos arreglos, el sistema no parecía hacer nada del todo, ni en 0x20000000 ni tampoco en 0x20001000. Noté que una diferencia importante entre lab4 y el proyecto es que en lab4 la PLL tiene un reset (lógica positiva) forzado a 0, pero en Platform Designer es obligatorio conectarlo a algo. Como conecté reset a un slide switch, probablemente existieron problemas de bouncing y cosas analógicas raras, en especial cuando ese reset también le caía a PLL. Habilité "debug instrumentation", que presuntamente me permite usar el bus analyzer, pero ymmv según esto: También puse el debouncer del lab4 antes del reset que va a platform.